aboutsummaryrefslogtreecommitdiffstats
path: root/container-core/src/main/java/com/yahoo/jdisc/http/server/jetty/JDiscHttpServlet.java
diff options
context:
space:
mode:
Diffstat (limited to 'container-core/src/main/java/com/yahoo/jdisc/http/server/jetty/JDiscHttpServlet.java')
-rw-r--r--container-core/src/main/java/com/yahoo/jdisc/http/server/jetty/JDiscHttpServlet.java148
1 files changed, 148 insertions, 0 deletions
diff --git a/container-core/src/main/java/com/yahoo/jdisc/http/server/jetty/JDiscHttpServlet.java b/container-core/src/main/java/com/yahoo/jdisc/http/server/jetty/JDiscHttpServlet.java
new file mode 100644
index 00000000000..41a1ffc2709
--- /dev/null
+++ b/container-core/src/main/java/com/yahoo/jdisc/http/server/jetty/JDiscHttpServlet.java
@@ -0,0 +1,148 @@
+// Copyright 2017 Yahoo Holdings. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
+package com.yahoo.jdisc.http.server.jetty;
+
+import com.yahoo.container.logging.AccessLogEntry;
+import com.yahoo.jdisc.Metric;
+import com.yahoo.jdisc.handler.OverloadException;
+import com.yahoo.jdisc.http.HttpRequest.Method;
+
+import javax.servlet.ServletException;
+import javax.servlet.annotation.WebServlet;
+import javax.servlet.http.HttpServlet;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+import java.io.IOException;
+import java.util.Enumeration;
+import java.util.Map;
+import java.util.Set;
+import java.util.logging.Level;
+import java.util.logging.Logger;
+import java.util.stream.Collectors;
+import java.util.stream.Stream;
+
+import static com.yahoo.jdisc.http.server.jetty.HttpServletRequestUtils.getConnection;
+
+/**
+ * @author Simon Thoresen Hult
+ * @author bjorncs
+ */
+@WebServlet(asyncSupported = true, description = "Bridge between Servlet and JDisc APIs")
+class JDiscHttpServlet extends HttpServlet {
+
+ public static final String ATTRIBUTE_NAME_ACCESS_LOG_ENTRY = JDiscHttpServlet.class.getName() + "_access-log-entry";
+
+ private final static Logger log = Logger.getLogger(JDiscHttpServlet.class.getName());
+ private final JDiscContext context;
+
+ private static final Set<String> servletSupportedMethods =
+ Stream.of(Method.OPTIONS, Method.GET, Method.HEAD, Method.POST, Method.PUT, Method.DELETE, Method.TRACE)
+ .map(Method::name)
+ .collect(Collectors.toSet());
+
+ public JDiscHttpServlet(JDiscContext context) {
+ this.context = context;
+ }
+
+ @Override
+ protected void doGet(HttpServletRequest request, HttpServletResponse response) throws IOException {
+ dispatchHttpRequest(request, response);
+ }
+
+ @Override
+ protected void doPost(HttpServletRequest request, HttpServletResponse response) throws IOException {
+ dispatchHttpRequest(request, response);
+ }
+
+ @Override
+ protected void doHead(HttpServletRequest request, HttpServletResponse response) throws IOException {
+ dispatchHttpRequest(request, response);
+ }
+
+ @Override
+ protected void doPut(HttpServletRequest request, HttpServletResponse response) throws IOException {
+ dispatchHttpRequest(request, response);
+ }
+
+ @Override
+ protected void doDelete(HttpServletRequest request, HttpServletResponse response) throws IOException {
+ dispatchHttpRequest(request, response);
+ }
+
+ @Override
+ protected void doOptions(HttpServletRequest request, HttpServletResponse response) throws IOException {
+ dispatchHttpRequest(request, response);
+ }
+
+ @Override
+ protected void doTrace(HttpServletRequest request, HttpServletResponse response) throws IOException {
+ dispatchHttpRequest(request, response);
+ }
+
+ /**
+ * Override to set connector attribute before the request becomes an upgrade request in the web socket case.
+ * (After the upgrade, the HttpConnection is no longer available.)
+ */
+ @Override
+ protected void service(HttpServletRequest request, HttpServletResponse response)
+ throws ServletException, IOException {
+ request.setAttribute(JDiscServerConnector.REQUEST_ATTRIBUTE, getConnector(request));
+
+ Metric.Context metricContext = getMetricContext(request);
+ context.metric.add(MetricDefinitions.NUM_REQUESTS, 1, metricContext);
+ context.metric.add(MetricDefinitions.JDISC_HTTP_REQUESTS, 1, metricContext);
+
+ String method = request.getMethod().toUpperCase();
+ if (servletSupportedMethods.contains(method)) {
+ super.service(request, response);
+ } else if (method.equals(Method.PATCH.name())) {
+ // PATCH method is not handled by the Servlet spec
+ dispatchHttpRequest(request, response);
+ } else {
+ // Divergence from HTTP / Servlet spec: JDisc returns 405 for both unknown and known (but unsupported) methods.
+ response.sendError(HttpServletResponse.SC_METHOD_NOT_ALLOWED);
+ }
+ }
+
+ static JDiscServerConnector getConnector(HttpServletRequest request) {
+ return (JDiscServerConnector)getConnection(request).getConnector();
+ }
+
+ private void dispatchHttpRequest(HttpServletRequest request, HttpServletResponse response) throws IOException {
+ AccessLogEntry accessLogEntry = new AccessLogEntry();
+ request.setAttribute(ATTRIBUTE_NAME_ACCESS_LOG_ENTRY, accessLogEntry);
+ try {
+ switch (request.getDispatcherType()) {
+ case REQUEST:
+ new HttpRequestDispatch(context, accessLogEntry, getMetricContext(request), request, response).dispatch();
+ break;
+ default:
+ if (log.isLoggable(Level.INFO)) {
+ log.info("Unexpected " + request.getDispatcherType() + "; " + formatAttributes(request));
+ }
+ break;
+ }
+ } catch (OverloadException e) {
+ // nop
+ } catch (RuntimeException e) {
+ throw new ExceptionWrapper(e);
+ }
+ }
+
+ private static Metric.Context getMetricContext(HttpServletRequest request) {
+ return JDiscServerConnector.fromRequest(request).createRequestMetricContext(request, Map.of());
+ }
+
+ private static String formatAttributes(final HttpServletRequest request) {
+ StringBuilder out = new StringBuilder();
+ out.append("attributes = {");
+ for (Enumeration<String> names = request.getAttributeNames(); names.hasMoreElements(); ) {
+ String name = names.nextElement();
+ out.append(" '").append(name).append("' = '").append(request.getAttribute(name)).append("'");
+ if (names.hasMoreElements()) {
+ out.append(",");
+ }
+ }
+ out.append(" }");
+ return out.toString();
+ }
+}