diff options
Diffstat (limited to 'container-core/src/main/java/com/yahoo/jdisc/http/server')
15 files changed, 17 insertions, 883 deletions
diff --git a/container-core/src/main/java/com/yahoo/jdisc/http/server/jetty/AccessLogRequestLog.java b/container-core/src/main/java/com/yahoo/jdisc/http/server/jetty/AccessLogRequestLog.java index 2eea7f155ee..b41c80a471c 100644 --- a/container-core/src/main/java/com/yahoo/jdisc/http/server/jetty/AccessLogRequestLog.java +++ b/container-core/src/main/java/com/yahoo/jdisc/http/server/jetty/AccessLogRequestLog.java @@ -8,7 +8,6 @@ import com.yahoo.container.logging.RequestLog; import com.yahoo.container.logging.RequestLogEntry; import com.yahoo.jdisc.http.HttpRequest; import com.yahoo.jdisc.http.ServerConfig; -import com.yahoo.jdisc.http.servlet.ServletRequest; import org.eclipse.jetty.http2.HTTP2Stream; import org.eclipse.jetty.http2.server.HttpTransportOverHTTP2; import org.eclipse.jetty.server.HttpChannel; @@ -86,10 +85,10 @@ class AccessLogRequestLog extends AbstractLifeCycle implements org.eclipse.jetty addNonNullValue(builder, jdiscRequest.getUserPrincipal(), RequestLogEntry.Builder::userPrincipal); } - String requestFilterId = (String) request.getAttribute(ServletRequest.JDISC_REQUEST_CHAIN); + String requestFilterId = (String) request.getAttribute(RequestUtils.JDISC_REQUEST_CHAIN); addNonNullValue(builder, requestFilterId, (b, chain) -> b.addExtraAttribute("request-chain", chain)); - String responseFilterId = (String) request.getAttribute(ServletRequest.JDISC_RESPONSE_CHAIN); + String responseFilterId = (String) request.getAttribute(RequestUtils.JDISC_RESPONSE_CHAIN); addNonNullValue(builder, responseFilterId, (b, chain) -> b.addExtraAttribute("response-chain", chain)); UUID connectionId = (UUID) request.getAttribute(JettyConnectionLogger.CONNECTION_ID_REQUEST_ATTRIBUTE); @@ -109,7 +108,7 @@ class AccessLogRequestLog extends AbstractLifeCycle implements org.eclipse.jetty builder.addExtraAttribute(header, value); } }); - X509Certificate[] clientCert = (X509Certificate[]) request.getAttribute(ServletRequest.SERVLET_REQUEST_X509CERT); + X509Certificate[] clientCert = (X509Certificate[]) request.getAttribute(RequestUtils.SERVLET_REQUEST_X509CERT); if (clientCert != null && clientCert.length > 0) { builder.sslPrincipal(clientCert[0].getSubjectX500Principal()); } diff --git a/container-core/src/main/java/com/yahoo/jdisc/http/server/jetty/FilterInvoker.java b/container-core/src/main/java/com/yahoo/jdisc/http/server/jetty/FilterInvoker.java deleted file mode 100644 index 3c329bbf13b..00000000000 --- a/container-core/src/main/java/com/yahoo/jdisc/http/server/jetty/FilterInvoker.java +++ /dev/null @@ -1,28 +0,0 @@ -// Copyright Yahoo. 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.google.inject.ImplementedBy; -import com.yahoo.jdisc.handler.ResponseHandler; -import com.yahoo.jdisc.http.filter.RequestFilter; -import com.yahoo.jdisc.http.filter.ResponseFilter; - -import javax.servlet.http.HttpServletRequest; -import javax.servlet.http.HttpServletResponse; -import java.net.URI; - -/** - * Separate interface since DiscFilterRequest/Response and Security filter chains are not accessible in this bundle - */ -@ImplementedBy(UnsupportedFilterInvoker.class) -public interface FilterInvoker { - HttpServletRequest invokeRequestFilterChain(RequestFilter requestFilterChain, - URI uri, - HttpServletRequest httpRequest, - ResponseHandler responseHandler); - - void invokeResponseFilterChain( - ResponseFilter responseFilterChain, - URI uri, - HttpServletRequest request, - HttpServletResponse response); -} diff --git a/container-core/src/main/java/com/yahoo/jdisc/http/server/jetty/FilterInvokingPrintWriter.java b/container-core/src/main/java/com/yahoo/jdisc/http/server/jetty/FilterInvokingPrintWriter.java deleted file mode 100644 index 90b12e64a55..00000000000 --- a/container-core/src/main/java/com/yahoo/jdisc/http/server/jetty/FilterInvokingPrintWriter.java +++ /dev/null @@ -1,266 +0,0 @@ -// Copyright Yahoo. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root. -package com.yahoo.jdisc.http.server.jetty; - -import java.io.IOException; -import java.io.PrintWriter; -import java.io.Writer; -import java.util.Locale; - -/** - * Invokes the response filter the first time anything is output to the underlying PrintWriter. - * The filter must be invoked before the first output call since this might cause the response - * to be committed, i.e. locked and potentially put on the wire. - * Any changes to the response after it has been committed might be ignored or cause exceptions. - * @author Tony Vaagenes - */ -final class FilterInvokingPrintWriter extends PrintWriter { - private final PrintWriter delegate; - private final OneTimeRunnable filterInvoker; - - public FilterInvokingPrintWriter(PrintWriter delegate, OneTimeRunnable filterInvoker) { - /* The PrintWriter class both - * 1) exposes new methods, the PrintWriter "interface" - * 2) implements PrintWriter and Writer methods that does some extra things before calling down to the writer methods. - * If super was invoked with the delegate PrintWriter, the superclass would behave as a PrintWriter(PrintWriter), - * i.e. the extra things in 2. would be done twice. - * To avoid this, all the methods of PrintWriter are overridden with versions that forward directly to the underlying delegate - * instead of going through super. - * The super class is initialized with a non-functioning writer to catch mistakenly non-overridden methods. - */ - super(new Writer() { - @Override - public void write(char[] cbuf, int off, int len) throws IOException { - throwAssertionError(); - } - - private void throwAssertionError() { - throw new AssertionError(FilterInvokingPrintWriter.class.getName() + " failed to delegate to the underlying writer"); - } - - @Override - public void flush() throws IOException { - throwAssertionError(); - } - - @Override - public void close() throws IOException { - throwAssertionError(); - } - }); - - this.delegate = delegate; - this.filterInvoker = filterInvoker; - } - - @Override - public String toString() { - return getClass().getName() + " (" + super.toString() + ")"; - } - - private void runFilterIfFirstInvocation() { - filterInvoker.runIfFirstInvocation(); - } - - @Override - public void flush() { - runFilterIfFirstInvocation(); - delegate.flush(); - } - - @Override - public void close() { - runFilterIfFirstInvocation(); - delegate.close(); - } - - @Override - public boolean checkError() { - return delegate.checkError(); - } - - @Override - public void write(int c) { - runFilterIfFirstInvocation(); - delegate.write(c); - } - - @Override - public void write(char[] buf, int off, int len) { - runFilterIfFirstInvocation(); - delegate.write(buf, off, len); - } - - @Override - public void write(char[] buf) { - runFilterIfFirstInvocation(); - delegate.write(buf); - } - - @Override - public void write(String s, int off, int len) { - runFilterIfFirstInvocation(); - delegate.write(s, off, len); - } - - @Override - public void write(String s) { - runFilterIfFirstInvocation(); - delegate.write(s); - } - - @Override - public void print(boolean b) { - runFilterIfFirstInvocation(); - delegate.print(b); - } - - @Override - public void print(char c) { - runFilterIfFirstInvocation(); - delegate.print(c); - } - - @Override - public void print(int i) { - runFilterIfFirstInvocation(); - delegate.print(i); - } - - @Override - public void print(long l) { - runFilterIfFirstInvocation(); - delegate.print(l); - } - - @Override - public void print(float f) { - runFilterIfFirstInvocation(); - delegate.print(f); - } - - @Override - public void print(double d) { - runFilterIfFirstInvocation(); - delegate.print(d); - } - - @Override - public void print(char[] s) { - runFilterIfFirstInvocation(); - delegate.print(s); - } - - @Override - public void print(String s) { - runFilterIfFirstInvocation(); - delegate.print(s); - } - - @Override - public void print(Object obj) { - runFilterIfFirstInvocation(); - delegate.print(obj); - } - - @Override - public void println() { - runFilterIfFirstInvocation(); - delegate.println(); - } - - @Override - public void println(boolean x) { - runFilterIfFirstInvocation(); - delegate.println(x); - } - - @Override - public void println(char x) { - runFilterIfFirstInvocation(); - delegate.println(x); - } - - @Override - public void println(int x) { - runFilterIfFirstInvocation(); - delegate.println(x); - } - - @Override - public void println(long x) { - runFilterIfFirstInvocation(); - delegate.println(x); - } - - @Override - public void println(float x) { - runFilterIfFirstInvocation(); - delegate.println(x); - } - - @Override - public void println(double x) { - runFilterIfFirstInvocation(); - delegate.println(x); - } - - @Override - public void println(char[] x) { - runFilterIfFirstInvocation(); - delegate.println(x); - } - - @Override - public void println(String x) { - runFilterIfFirstInvocation(); - delegate.println(x); - } - - @Override - public void println(Object x) { - runFilterIfFirstInvocation(); - delegate.println(x); - } - - @Override - public PrintWriter printf(String format, Object... args) { - runFilterIfFirstInvocation(); - return delegate.printf(format, args); - } - - @Override - public PrintWriter printf(Locale l, String format, Object... args) { - runFilterIfFirstInvocation(); - return delegate.printf(l, format, args); - } - - @Override - public PrintWriter format(String format, Object... args) { - runFilterIfFirstInvocation(); - return delegate.format(format, args); - } - - @Override - public PrintWriter format(Locale l, String format, Object... args) { - runFilterIfFirstInvocation(); - return delegate.format(l, format, args); - } - - @Override - public PrintWriter append(CharSequence csq) { - runFilterIfFirstInvocation(); - return delegate.append(csq); - } - - @Override - public PrintWriter append(CharSequence csq, int start, int end) { - runFilterIfFirstInvocation(); - return delegate.append(csq, start, end); - } - - @Override - public PrintWriter append(char c) { - runFilterIfFirstInvocation(); - return delegate.append(c); - } -} diff --git a/container-core/src/main/java/com/yahoo/jdisc/http/server/jetty/FilterInvokingServletOutputStream.java b/container-core/src/main/java/com/yahoo/jdisc/http/server/jetty/FilterInvokingServletOutputStream.java deleted file mode 100644 index d2be107ef86..00000000000 --- a/container-core/src/main/java/com/yahoo/jdisc/http/server/jetty/FilterInvokingServletOutputStream.java +++ /dev/null @@ -1,165 +0,0 @@ -// Copyright Yahoo. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root. -package com.yahoo.jdisc.http.server.jetty; - -import javax.servlet.ServletOutputStream; -import javax.servlet.WriteListener; -import java.io.IOException; - -/** - * Invokes the response filter the first time anything is output to the underlying ServletOutputStream. - * The filter must be invoked before the first output call since this might cause the response - * to be committed, i.e. locked and potentially put on the wire. - * Any changes to the response after it has been committed might be ignored or cause exceptions. - * - * @author Tony Vaagenes - */ -class FilterInvokingServletOutputStream extends ServletOutputStream { - private final ServletOutputStream delegate; - private final OneTimeRunnable filterInvoker; - - public FilterInvokingServletOutputStream(ServletOutputStream delegate, OneTimeRunnable filterInvoker) { - this.delegate = delegate; - this.filterInvoker = filterInvoker; - } - - @Override - public boolean isReady() { - return delegate.isReady(); - } - - @Override - public void setWriteListener(WriteListener writeListener) { - delegate.setWriteListener(writeListener); - } - - - private void runFilterIfFirstInvocation() { - filterInvoker.runIfFirstInvocation(); - } - - @Override - public void write(int b) throws IOException { - runFilterIfFirstInvocation(); - delegate.write(b); - } - - - @Override - public void write(byte[] b) throws IOException { - runFilterIfFirstInvocation(); - delegate.write(b); - } - - @Override - public void print(String s) throws IOException { - runFilterIfFirstInvocation(); - delegate.print(s); - } - - @Override - public void write(byte[] b, int off, int len) throws IOException { - runFilterIfFirstInvocation(); - delegate.write(b, off, len); - } - - @Override - public void print(boolean b) throws IOException { - runFilterIfFirstInvocation(); - delegate.print(b); - } - - @Override - public void flush() throws IOException { - runFilterIfFirstInvocation(); - delegate.flush(); - } - - @Override - public void print(char c) throws IOException { - runFilterIfFirstInvocation(); - delegate.print(c); - } - - @Override - public void close() throws IOException { - runFilterIfFirstInvocation(); - delegate.close(); - } - - @Override - public void print(int i) throws IOException { - runFilterIfFirstInvocation(); - delegate.print(i); - } - - @Override - public void print(long l) throws IOException { - runFilterIfFirstInvocation(); - delegate.print(l); - } - - @Override - public void print(float f) throws IOException { - runFilterIfFirstInvocation(); - delegate.print(f); - } - - @Override - public void print(double d) throws IOException { - runFilterIfFirstInvocation(); - delegate.print(d); - } - - @Override - public void println() throws IOException { - runFilterIfFirstInvocation(); - delegate.println(); - } - - @Override - public void println(String s) throws IOException { - runFilterIfFirstInvocation(); - delegate.println(s); - } - - @Override - public void println(boolean b) throws IOException { - runFilterIfFirstInvocation(); - delegate.println(b); - } - - @Override - public void println(char c) throws IOException { - runFilterIfFirstInvocation(); - delegate.println(c); - } - - @Override - public void println(int i) throws IOException { - runFilterIfFirstInvocation(); - delegate.println(i); - } - - @Override - public void println(long l) throws IOException { - runFilterIfFirstInvocation(); - delegate.println(l); - } - - @Override - public void println(float f) throws IOException { - runFilterIfFirstInvocation(); - delegate.println(f); - } - - @Override - public void println(double d) throws IOException { - runFilterIfFirstInvocation(); - delegate.println(d); - } - - @Override - public String toString() { - return getClass().getCanonicalName() + " (" + delegate.toString() + ")"; - } -} diff --git a/container-core/src/main/java/com/yahoo/jdisc/http/server/jetty/FilterResolver.java b/container-core/src/main/java/com/yahoo/jdisc/http/server/jetty/FilterResolver.java index 873f336f0c9..32def124131 100644 --- a/container-core/src/main/java/com/yahoo/jdisc/http/server/jetty/FilterResolver.java +++ b/container-core/src/main/java/com/yahoo/jdisc/http/server/jetty/FilterResolver.java @@ -10,7 +10,6 @@ import com.yahoo.jdisc.handler.ResponseHandler; import com.yahoo.jdisc.http.HttpRequest; import com.yahoo.jdisc.http.filter.RequestFilter; import com.yahoo.jdisc.http.filter.ResponseFilter; -import com.yahoo.jdisc.http.servlet.ServletRequest; import org.eclipse.jetty.server.Request; import java.net.URI; @@ -40,13 +39,13 @@ class FilterResolver { Optional<String> maybeFilterId = bindings.resolveRequestFilter(jdiscUri, getConnector(request).listenPort()); if (maybeFilterId.isPresent()) { metric.add(MetricDefinitions.FILTERING_REQUEST_HANDLED, 1L, createMetricContext(request, maybeFilterId.get())); - request.setAttribute(ServletRequest.JDISC_REQUEST_CHAIN, maybeFilterId.get()); + request.setAttribute(RequestUtils.JDISC_REQUEST_CHAIN, maybeFilterId.get()); } else if (!strictFiltering) { metric.add(MetricDefinitions.FILTERING_REQUEST_UNHANDLED, 1L, createMetricContext(request, null)); } else { String syntheticFilterId = RejectingRequestFilter.SYNTHETIC_FILTER_CHAIN_ID; metric.add(MetricDefinitions.FILTERING_REQUEST_HANDLED, 1L, createMetricContext(request, syntheticFilterId)); - request.setAttribute(ServletRequest.JDISC_REQUEST_CHAIN, syntheticFilterId); + request.setAttribute(RequestUtils.JDISC_REQUEST_CHAIN, syntheticFilterId); return Optional.of(RejectingRequestFilter.INSTANCE); } return maybeFilterId.map(bindings::getRequestFilter); @@ -56,7 +55,7 @@ class FilterResolver { Optional<String> maybeFilterId = bindings.resolveResponseFilter(jdiscUri, getConnector(request).listenPort()); if (maybeFilterId.isPresent()) { metric.add(MetricDefinitions.FILTERING_RESPONSE_HANDLED, 1L, createMetricContext(request, maybeFilterId.get())); - request.setAttribute(ServletRequest.JDISC_RESPONSE_CHAIN, maybeFilterId.get()); + request.setAttribute(RequestUtils.JDISC_RESPONSE_CHAIN, maybeFilterId.get()); } else { metric.add(MetricDefinitions.FILTERING_RESPONSE_UNHANDLED, 1L, createMetricContext(request, null)); } diff --git a/container-core/src/main/java/com/yahoo/jdisc/http/server/jetty/HttpRequestFactory.java b/container-core/src/main/java/com/yahoo/jdisc/http/server/jetty/HttpRequestFactory.java index 52c2a83563e..c54fa1cf1b9 100644 --- a/container-core/src/main/java/com/yahoo/jdisc/http/server/jetty/HttpRequestFactory.java +++ b/container-core/src/main/java/com/yahoo/jdisc/http/server/jetty/HttpRequestFactory.java @@ -2,7 +2,6 @@ package com.yahoo.jdisc.http.server.jetty; import com.yahoo.jdisc.http.HttpRequest; -import com.yahoo.jdisc.http.servlet.ServletRequest; import com.yahoo.jdisc.service.CurrentContainer; import org.eclipse.jetty.server.Request; import org.eclipse.jetty.util.Utf8Appendable; @@ -32,7 +31,7 @@ class HttpRequestFactory { HttpRequest.Version.fromString(servletRequest.getProtocol()), new InetSocketAddress(servletRequest.getRemoteAddr(), servletRequest.getRemotePort()), getConnection((Request) servletRequest).getCreatedTimeStamp()); - httpRequest.context().put(ServletRequest.JDISC_REQUEST_X509CERT, getCertChain(servletRequest)); + httpRequest.context().put(RequestUtils.JDISC_REQUEST_X509CERT, getCertChain(servletRequest)); servletRequest.setAttribute(HttpRequest.class.getName(), httpRequest); return httpRequest; } catch (Utf8Appendable.NotUtf8Exception e) { diff --git a/container-core/src/main/java/com/yahoo/jdisc/http/server/jetty/JDiscFilterInvokerFilter.java b/container-core/src/main/java/com/yahoo/jdisc/http/server/jetty/JDiscFilterInvokerFilter.java deleted file mode 100644 index 0fd4e8c42fb..00000000000 --- a/container-core/src/main/java/com/yahoo/jdisc/http/server/jetty/JDiscFilterInvokerFilter.java +++ /dev/null @@ -1,302 +0,0 @@ -// Copyright Yahoo. 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.handler.ResponseHandler; -import com.yahoo.jdisc.http.filter.RequestFilter; -import org.eclipse.jetty.server.Request; - -import javax.servlet.AsyncContext; -import javax.servlet.AsyncListener; -import javax.servlet.Filter; -import javax.servlet.FilterChain; -import javax.servlet.FilterConfig; -import javax.servlet.ServletContext; -import javax.servlet.ServletException; -import javax.servlet.ServletOutputStream; -import javax.servlet.ServletRequest; -import javax.servlet.ServletResponse; -import javax.servlet.http.HttpServletRequest; -import javax.servlet.http.HttpServletRequestWrapper; -import javax.servlet.http.HttpServletResponse; -import javax.servlet.http.HttpServletResponseWrapper; -import java.io.IOException; -import java.io.PrintWriter; -import java.net.URI; -import java.util.Map; -import java.util.Optional; -import java.util.concurrent.atomic.AtomicReference; - -import static com.yahoo.jdisc.http.server.jetty.RequestUtils.getConnector; -import static com.yahoo.yolean.Exceptions.throwUnchecked; - -/** - * Runs JDisc security filters for Servlets - * This component is split in two: - * 1) JDiscFilterInvokerFilter, which uses package private methods to support JDisc APIs - * 2) SecurityFilterInvoker, which is intended for use in a servlet context. - * - * @author Tony Vaagenes - */ -class JDiscFilterInvokerFilter implements Filter { - private final JDiscContext jDiscContext; - private final FilterInvoker filterInvoker; - - public JDiscFilterInvokerFilter(JDiscContext jDiscContext, - FilterInvoker filterInvoker) { - this.jDiscContext = jDiscContext; - this.filterInvoker = filterInvoker; - } - - - @Override - public void init(FilterConfig filterConfig) throws ServletException {} - - @Override - public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException { - HttpServletRequest httpRequest = (HttpServletRequest)request; - HttpServletResponse httpResponse = (HttpServletResponse)response; - - URI uri; - try { - uri = HttpRequestFactory.getUri(httpRequest); - } catch (RequestException e) { - httpResponse.sendError(e.getResponseStatus(), e.getMessage()); - return; - } - - AtomicReference<Boolean> responseReturned = new AtomicReference<>(null); - - HttpServletRequest newRequest = runRequestFilterWithMatchingBinding(responseReturned, uri, httpRequest, httpResponse); - assert newRequest != null; - responseReturned.compareAndSet(null, false); - - if (!responseReturned.get()) { - runChainAndResponseFilters(uri, newRequest, httpResponse, chain); - } - } - - private void runChainAndResponseFilters(URI uri, HttpServletRequest request, HttpServletResponse response, FilterChain chain) throws IOException, ServletException { - Optional<OneTimeRunnable> responseFilterInvoker = - jDiscContext.filterResolver.resolveResponseFilter(toJettyRequest(request), uri) - .map(responseFilter -> - new OneTimeRunnable(() -> - filterInvoker.invokeResponseFilterChain(responseFilter, uri, request, response))); - - - HttpServletResponse responseForServlet = responseFilterInvoker - .<HttpServletResponse>map(invoker -> - new FilterInvokingResponseWrapper(response, invoker)) - .orElse(response); - - HttpServletRequest requestForServlet = responseFilterInvoker - .<HttpServletRequest>map(invoker -> - new FilterInvokingRequestWrapper(request, invoker, responseForServlet)) - .orElse(request); - - chain.doFilter(requestForServlet, responseForServlet); - - responseFilterInvoker.ifPresent(invoker -> { - boolean requestHandledSynchronously = !request.isAsyncStarted(); - - if (requestHandledSynchronously) { - invoker.runIfFirstInvocation(); - } - // For async requests, response filters will be invoked on AsyncContext.complete(). - }); - } - - private HttpServletRequest runRequestFilterWithMatchingBinding(AtomicReference<Boolean> responseReturned, URI uri, HttpServletRequest request, HttpServletResponse response) throws IOException { - try { - RequestFilter requestFilter = jDiscContext.filterResolver.resolveRequestFilter(toJettyRequest(request), uri).orElse(null); - if (requestFilter == null) - return request; - - ResponseHandler responseHandler = createResponseHandler(responseReturned, request, response); - return filterInvoker.invokeRequestFilterChain(requestFilter, uri, request, responseHandler); - } catch (Exception e) { - throw new RuntimeException("Failed running request filter chain for uri " + uri, e); - } - } - - private ResponseHandler createResponseHandler(AtomicReference<Boolean> responseReturned, HttpServletRequest httpRequest, HttpServletResponse httpResponse) { - return jdiscResponse -> { - boolean oldValueWasNull = responseReturned.compareAndSet(null, true); - if (!oldValueWasNull) - throw new RuntimeException("Can't return response from filter asynchronously"); - - HttpRequestDispatch requestDispatch = createRequestDispatch(httpRequest, httpResponse); - return requestDispatch.dispatchFilterRequest(jdiscResponse); - }; - } - - private HttpRequestDispatch createRequestDispatch(HttpServletRequest request, HttpServletResponse response) { - try { - final AccessLogEntry accessLogEntry = null; // Not used in this context. - return new HttpRequestDispatch(jDiscContext, - accessLogEntry, - getConnector(toJettyRequest(request)).createRequestMetricContext(request, Map.of()), - request, response); - } catch (IOException e) { - throw throwUnchecked(e); - } - } - - private static Request toJettyRequest(HttpServletRequest request) { - if (request instanceof com.yahoo.jdisc.http.servlet.ServletRequest) { - return (Request) ((com.yahoo.jdisc.http.servlet.ServletRequest)request).getRequest(); - } - return (Request) request; - } - - @Override - public void destroy() {} - - // ServletRequest wrapper that is necessary because we need to wrap AsyncContext. - private static class FilterInvokingRequestWrapper extends HttpServletRequestWrapper { - private final OneTimeRunnable filterInvoker; - private final HttpServletResponse servletResponse; - - public FilterInvokingRequestWrapper( - HttpServletRequest request, - OneTimeRunnable filterInvoker, - HttpServletResponse servletResponse) { - super(request); - this.filterInvoker = filterInvoker; - this.servletResponse = servletResponse; - } - - @Override - public AsyncContext startAsync() { - final AsyncContext asyncContext = super.startAsync(); - return new FilterInvokingAsyncContext(asyncContext, filterInvoker, this, servletResponse); - } - - @Override - public AsyncContext startAsync( - final ServletRequest wrappedRequest, - final ServletResponse wrappedResponse) { - // According to the documentation, the passed request/response parameters here must either - // _be_ or _wrap_ the original request/response objects passed to the servlet - which are - // our wrappers, so no need to wrap again - we can use the user-supplied objects. - final AsyncContext asyncContext = super.startAsync(wrappedRequest, wrappedResponse); - return new FilterInvokingAsyncContext(asyncContext, filterInvoker, this, wrappedResponse); - } - - @Override - public AsyncContext getAsyncContext() { - final AsyncContext asyncContext = super.getAsyncContext(); - return new FilterInvokingAsyncContext(asyncContext, filterInvoker, this, servletResponse); - } - } - - // AsyncContext wrapper that is necessary for two reasons: - // 1) Run response filters when AsyncContext.complete() is called. - // 2) Eliminate paths where application code can get its hands on un-wrapped response object, circumventing - // running of response filters. - private static class FilterInvokingAsyncContext implements AsyncContext { - private final AsyncContext delegate; - private final OneTimeRunnable filterInvoker; - private final ServletRequest servletRequest; - private final ServletResponse servletResponse; - - public FilterInvokingAsyncContext( - AsyncContext delegate, - OneTimeRunnable filterInvoker, - ServletRequest servletRequest, - ServletResponse servletResponse) { - this.delegate = delegate; - this.filterInvoker = filterInvoker; - this.servletRequest = servletRequest; - this.servletResponse = servletResponse; - } - - @Override - public ServletRequest getRequest() { - return servletRequest; - } - - @Override - public ServletResponse getResponse() { - return servletResponse; - } - - @Override - public boolean hasOriginalRequestAndResponse() { - return delegate.hasOriginalRequestAndResponse(); - } - - @Override - public void dispatch() { - delegate.dispatch(); - } - - @Override - public void dispatch(String s) { - delegate.dispatch(s); - } - - @Override - public void dispatch(ServletContext servletContext, String s) { - delegate.dispatch(servletContext, s); - } - - @Override - public void complete() { - // Completing may commit the response, so this is the last chance to run response filters. - filterInvoker.runIfFirstInvocation(); - delegate.complete(); - } - - @Override - public void start(Runnable runnable) { - delegate.start(runnable); - } - - @Override - public void addListener(AsyncListener asyncListener) { - delegate.addListener(asyncListener); - } - - @Override - public void addListener(AsyncListener asyncListener, ServletRequest servletRequest, ServletResponse servletResponse) { - delegate.addListener(asyncListener, servletRequest, servletResponse); - } - - @Override - public <T extends AsyncListener> T createListener(Class<T> aClass) throws ServletException { - return delegate.createListener(aClass); - } - - @Override - public void setTimeout(long l) { - delegate.setTimeout(l); - } - - @Override - public long getTimeout() { - return delegate.getTimeout(); - } - } - - private static class FilterInvokingResponseWrapper extends HttpServletResponseWrapper { - private final OneTimeRunnable filterInvoker; - - public FilterInvokingResponseWrapper(HttpServletResponse response, OneTimeRunnable filterInvoker) { - super(response); - this.filterInvoker = filterInvoker; - } - - @Override - public ServletOutputStream getOutputStream() throws IOException { - ServletOutputStream delegate = super.getOutputStream(); - return new FilterInvokingServletOutputStream(delegate, filterInvoker); - } - - @Override - public PrintWriter getWriter() throws IOException { - PrintWriter delegate = super.getWriter(); - return new FilterInvokingPrintWriter(delegate, filterInvoker); - } - } -} diff --git a/container-core/src/main/java/com/yahoo/jdisc/http/server/jetty/JDiscServerConnector.java b/container-core/src/main/java/com/yahoo/jdisc/http/server/jetty/JDiscServerConnector.java index 0e511fd3eaf..79cdb8f67cf 100644 --- a/container-core/src/main/java/com/yahoo/jdisc/http/server/jetty/JDiscServerConnector.java +++ b/container-core/src/main/java/com/yahoo/jdisc/http/server/jetty/JDiscServerConnector.java @@ -73,7 +73,7 @@ class JDiscServerConnector extends ServerConnector { public Metric.Context createRequestMetricContext(HttpServletRequest request, Map<String, String> extraDimensions) { String method = request.getMethod(); String scheme = request.getScheme(); - boolean clientAuthenticated = request.getAttribute(com.yahoo.jdisc.http.servlet.ServletRequest.SERVLET_REQUEST_X509CERT) != null; + boolean clientAuthenticated = request.getAttribute(RequestUtils.SERVLET_REQUEST_X509CERT) != null; Map<String, Object> dimensions = createConnectorDimensions(listenPort, connectorName); dimensions.put(MetricDefinitions.METHOD_DIMENSION, method); dimensions.put(MetricDefinitions.SCHEME_DIMENSION, scheme); diff --git a/container-core/src/main/java/com/yahoo/jdisc/http/server/jetty/JettyHttpServer.java b/container-core/src/main/java/com/yahoo/jdisc/http/server/jetty/JettyHttpServer.java index 3f2a91c60b5..fca34f3bbd7 100644 --- a/container-core/src/main/java/com/yahoo/jdisc/http/server/jetty/JettyHttpServer.java +++ b/container-core/src/main/java/com/yahoo/jdisc/http/server/jetty/JettyHttpServer.java @@ -2,14 +2,12 @@ package com.yahoo.jdisc.http.server.jetty; import com.google.inject.Inject; -import com.yahoo.component.ComponentId; import com.yahoo.component.provider.ComponentRegistry; import com.yahoo.container.logging.ConnectionLog; import com.yahoo.container.logging.RequestLog; import com.yahoo.jdisc.Metric; import com.yahoo.jdisc.http.ConnectorConfig; import com.yahoo.jdisc.http.ServerConfig; -import com.yahoo.jdisc.http.ServletPathsConfig; import com.yahoo.jdisc.service.AbstractServerProvider; import com.yahoo.jdisc.service.CurrentContainer; import org.eclipse.jetty.http.HttpField; @@ -24,7 +22,6 @@ import org.eclipse.jetty.server.handler.HandlerCollection; import org.eclipse.jetty.server.handler.StatisticsHandler; import org.eclipse.jetty.server.handler.gzip.GzipHandler; import org.eclipse.jetty.server.handler.gzip.GzipHttpOutputInterceptor; -import org.eclipse.jetty.servlet.FilterHolder; import org.eclipse.jetty.servlet.ServletContextHandler; import org.eclipse.jetty.servlet.ServletHolder; import org.eclipse.jetty.util.log.JavaUtilLog; @@ -32,14 +29,12 @@ import org.eclipse.jetty.util.log.Log; import org.eclipse.jetty.util.thread.QueuedThreadPool; import javax.management.remote.JMXServiceURL; -import javax.servlet.DispatcherType; import java.io.IOException; import java.lang.management.ManagementFactory; import java.net.BindException; import java.net.MalformedURLException; import java.util.ArrayList; import java.util.Arrays; -import java.util.EnumSet; import java.util.List; import java.util.logging.Level; import java.util.logging.Logger; @@ -63,12 +58,9 @@ public class JettyHttpServer extends AbstractServerProvider { public JettyHttpServer(CurrentContainer container, Metric metric, ServerConfig serverConfig, - ServletPathsConfig servletPathsConfig, FilterBindings filterBindings, Janitor janitor, ComponentRegistry<ConnectorFactory> connectorFactories, - ComponentRegistry<ServletHolder> servletHolders, - FilterInvoker filterInvoker, RequestLog requestLog, ConnectionLog connectionLog) { super(container); @@ -98,18 +90,13 @@ public class JettyHttpServer extends AbstractServerProvider { serverConfig); ServletHolder jdiscServlet = new ServletHolder(new JDiscHttpServlet(jDiscContext)); - FilterHolder jDiscFilterInvokerFilter = new FilterHolder(new JDiscFilterInvokerFilter(jDiscContext, filterInvoker)); - List<JDiscServerConnector> connectors = Arrays.stream(server.getConnectors()) .map(JDiscServerConnector.class::cast) .collect(toList()); server.setHandler(getHandlerCollection(serverConfig, - servletPathsConfig, connectors, - jdiscServlet, - servletHolders, - jDiscFilterInvokerFilter)); + jdiscServlet)); this.metricsReporter = new ServerMetricReporter(metric, server); } @@ -150,19 +137,9 @@ public class JettyHttpServer extends AbstractServerProvider { } private HandlerCollection getHandlerCollection(ServerConfig serverConfig, - ServletPathsConfig servletPathsConfig, List<JDiscServerConnector> connectors, - ServletHolder jdiscServlet, - ComponentRegistry<ServletHolder> servletHolders, - FilterHolder jDiscFilterInvokerFilter) { + ServletHolder jdiscServlet) { ServletContextHandler servletContextHandler = createServletContextHandler(); - - servletHolders.allComponentsById().forEach((id, servlet) -> { - String path = getServletPath(servletPathsConfig, id); - servletContextHandler.addServlet(servlet, path); - servletContextHandler.addFilter(jDiscFilterInvokerFilter, path, EnumSet.allOf(DispatcherType.class)); - }); - servletContextHandler.addServlet(jdiscServlet, "/*"); List<ConnectorConfig> connectorConfigs = connectors.stream().map(JDiscServerConnector::connectorConfig).collect(toList()); @@ -191,10 +168,6 @@ public class JettyHttpServer extends AbstractServerProvider { return handlerCollection; } - private static String getServletPath(ServletPathsConfig servletPathsConfig, ComponentId id) { - return "/" + servletPathsConfig.servlets(id.stringValue()).path(); - } - private ServletContextHandler createServletContextHandler() { ServletContextHandler servletContextHandler = new ServletContextHandler(ServletContextHandler.NO_SECURITY | ServletContextHandler.NO_SESSIONS); servletContextHandler.setContextPath("/"); diff --git a/container-core/src/main/java/com/yahoo/jdisc/http/server/jetty/OneTimeRunnable.java b/container-core/src/main/java/com/yahoo/jdisc/http/server/jetty/OneTimeRunnable.java deleted file mode 100644 index 24cc41d009f..00000000000 --- a/container-core/src/main/java/com/yahoo/jdisc/http/server/jetty/OneTimeRunnable.java +++ /dev/null @@ -1,23 +0,0 @@ -// Copyright Yahoo. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root. -package com.yahoo.jdisc.http.server.jetty; - -import java.util.concurrent.atomic.AtomicBoolean; - -/** - * @author Tony Vaagenes - */ -public class OneTimeRunnable { - private final Runnable runnable; - private final AtomicBoolean hasRun = new AtomicBoolean(false); - - public OneTimeRunnable(Runnable runnable) { - this.runnable = runnable; - } - - public void runIfFirstInvocation() { - boolean previous = hasRun.getAndSet(true); - if (!previous) { - runnable.run(); - } - } -} diff --git a/container-core/src/main/java/com/yahoo/jdisc/http/server/jetty/RequestUtils.java b/container-core/src/main/java/com/yahoo/jdisc/http/server/jetty/RequestUtils.java index 1bddd491496..ae18c78a7d3 100644 --- a/container-core/src/main/java/com/yahoo/jdisc/http/server/jetty/RequestUtils.java +++ b/container-core/src/main/java/com/yahoo/jdisc/http/server/jetty/RequestUtils.java @@ -12,6 +12,11 @@ import javax.servlet.http.HttpServletRequest; * @author bjorncs */ public class RequestUtils { + public static final String JDISC_REQUEST_X509CERT = "jdisc.request.X509Certificate"; + public static final String JDISC_REQUEST_CHAIN = "jdisc.request.chain"; + public static final String JDISC_RESPONSE_CHAIN = "jdisc.response.chain"; + public static final String SERVLET_REQUEST_X509CERT = "javax.servlet.request.X509Certificate"; + private RequestUtils() {} public static Connection getConnection(Request request) { diff --git a/container-core/src/main/java/com/yahoo/jdisc/http/server/jetty/TlsClientAuthenticationEnforcer.java b/container-core/src/main/java/com/yahoo/jdisc/http/server/jetty/TlsClientAuthenticationEnforcer.java index b9293226528..3059f972ce9 100644 --- a/container-core/src/main/java/com/yahoo/jdisc/http/server/jetty/TlsClientAuthenticationEnforcer.java +++ b/container-core/src/main/java/com/yahoo/jdisc/http/server/jetty/TlsClientAuthenticationEnforcer.java @@ -3,7 +3,6 @@ package com.yahoo.jdisc.http.server.jetty; import com.yahoo.jdisc.Response; import com.yahoo.jdisc.http.ConnectorConfig; -import com.yahoo.jdisc.http.servlet.ServletRequest; import org.eclipse.jetty.server.Request; import org.eclipse.jetty.server.handler.HandlerWrapper; @@ -78,6 +77,6 @@ class TlsClientAuthenticationEnforcer extends HandlerWrapper { } private boolean isClientAuthenticated(HttpServletRequest servletRequest) { - return servletRequest.getAttribute(ServletRequest.SERVLET_REQUEST_X509CERT) != null; + return servletRequest.getAttribute(RequestUtils.SERVLET_REQUEST_X509CERT) != null; } } diff --git a/container-core/src/main/java/com/yahoo/jdisc/http/server/jetty/UnsupportedFilterInvoker.java b/container-core/src/main/java/com/yahoo/jdisc/http/server/jetty/UnsupportedFilterInvoker.java deleted file mode 100644 index 8d878b64e6f..00000000000 --- a/container-core/src/main/java/com/yahoo/jdisc/http/server/jetty/UnsupportedFilterInvoker.java +++ /dev/null @@ -1,32 +0,0 @@ -// Copyright Yahoo. 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.jdisc.handler.ResponseHandler; -import com.yahoo.jdisc.http.filter.RequestFilter; -import com.yahoo.jdisc.http.filter.ResponseFilter; - -import javax.servlet.http.HttpServletResponse; -import javax.servlet.http.HttpServletRequest; -import java.net.URI; - -/** - * @author Tony Vaagenes - */ -public class UnsupportedFilterInvoker implements FilterInvoker { - @Override - public HttpServletRequest invokeRequestFilterChain(RequestFilter requestFilterChain, - URI uri, - HttpServletRequest httpRequest, - ResponseHandler responseHandler) { - throw new UnsupportedOperationException(); - } - - @Override - public void invokeResponseFilterChain( - ResponseFilter responseFilterChain, - URI uri, - HttpServletRequest request, - HttpServletResponse response) { - throw new UnsupportedOperationException(); - } -} diff --git a/container-core/src/main/java/com/yahoo/jdisc/http/server/jetty/testutils/ServletModule.java b/container-core/src/main/java/com/yahoo/jdisc/http/server/jetty/testutils/ServletModule.java deleted file mode 100644 index bb69832d767..00000000000 --- a/container-core/src/main/java/com/yahoo/jdisc/http/server/jetty/testutils/ServletModule.java +++ /dev/null @@ -1,23 +0,0 @@ -// Copyright Yahoo. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root. -package com.yahoo.jdisc.http.server.jetty.testutils; - -import com.google.inject.Binder; -import com.google.inject.Module; -import com.google.inject.Provides; -import com.yahoo.component.provider.ComponentRegistry; - -import org.eclipse.jetty.servlet.ServletHolder; - -/** - * @author Tony Vaagenes - */ -public class ServletModule implements Module { - - @SuppressWarnings("unused") - @Provides - public ComponentRegistry<ServletHolder> servletHolderComponentRegistry() { - return new ComponentRegistry<>(); - } - - @Override public void configure(Binder binder) { } -} diff --git a/container-core/src/main/java/com/yahoo/jdisc/http/server/jetty/testutils/TestDriver.java b/container-core/src/main/java/com/yahoo/jdisc/http/server/jetty/testutils/TestDriver.java index 99c49527ea5..b0c1e7763ca 100644 --- a/container-core/src/main/java/com/yahoo/jdisc/http/server/jetty/testutils/TestDriver.java +++ b/container-core/src/main/java/com/yahoo/jdisc/http/server/jetty/testutils/TestDriver.java @@ -92,8 +92,7 @@ public class TestDriver implements AutoCloseable { bind(RequestLog.class).toInstance(new VoidRequestLog()); } }, - new ConnectorFactoryRegistryModule(connectorConfig), - new ServletModule()); + new ConnectorFactoryRegistryModule(connectorConfig)); } public static class Builder { |