From b38bae36f1fc7795b0ffcb638dd7b348d087f560 Mon Sep 17 00:00:00 2001 From: Greg Wilkins Date: Tue, 10 Jun 2014 11:28:07 +0200 Subject: [PATCH] moved http/1.1 isms out of HttpChannel into HttpConnection --- .../authentication/FormAuthenticator.java | 3 +- .../org/eclipse/jetty/server/HttpChannel.java | 117 +------- .../jetty/server/HttpChannelOverHttp.java | 263 ++++++++++++++++++ .../eclipse/jetty/server/HttpConnection.java | 105 +------ .../jetty/server/ExtendedServerTest.java | 2 +- 5 files changed, 278 insertions(+), 212 deletions(-) create mode 100644 jetty-server/src/main/java/org/eclipse/jetty/server/HttpChannelOverHttp.java diff --git a/jetty-security/src/main/java/org/eclipse/jetty/security/authentication/FormAuthenticator.java b/jetty-security/src/main/java/org/eclipse/jetty/security/authentication/FormAuthenticator.java index dcfea4168c6..790d544536a 100644 --- a/jetty-security/src/main/java/org/eclipse/jetty/security/authentication/FormAuthenticator.java +++ b/jetty-security/src/main/java/org/eclipse/jetty/security/authentication/FormAuthenticator.java @@ -236,8 +236,7 @@ public class FormAuthenticator extends LoginAuthenticator //restore the original request's method on this request if (LOG.isDebugEnabled()) LOG.debug("Restoring original method {} for {} with method {}", method, juri,httpRequest.getMethod()); Request base_request = HttpChannel.getCurrentHttpChannel().getRequest(); - HttpMethod m = HttpMethod.fromString(method); - base_request.setMethod(m,m.asString()); + base_request.setMethod(method); } /* ------------------------------------------------------------ */ diff --git a/jetty-server/src/main/java/org/eclipse/jetty/server/HttpChannel.java b/jetty-server/src/main/java/org/eclipse/jetty/server/HttpChannel.java index b8abcaec280..09e92923581 100644 --- a/jetty-server/src/main/java/org/eclipse/jetty/server/HttpChannel.java +++ b/jetty-server/src/main/java/org/eclipse/jetty/server/HttpChannel.java @@ -67,7 +67,7 @@ import org.eclipse.jetty.util.thread.Scheduler; * HttpTransport.completed(). * */ -public class HttpChannel implements HttpParser.RequestHandler, Runnable, HttpParser.ProxyHandler +public class HttpChannel implements HttpParser.RequestHandler, Runnable { private static final Logger LOG = Log.getLogger(HttpChannel.class); private static final ThreadLocal> __currentChannel = new ThreadLocal<>(); @@ -102,9 +102,6 @@ public class HttpChannel implements HttpParser.RequestHandler, Runnable, H private final Request _request; private final Response _response; private HttpVersion _version = HttpVersion.HTTP_1_1; - private boolean _expect = false; - private boolean _expect100Continue = false; - private boolean _expect102Processing = false; public HttpChannel(Connector connector, HttpConfiguration configuration, EndPoint endPoint, HttpTransport transport, HttpInput input) { @@ -201,32 +198,12 @@ public class HttpChannel implements HttpParser.RequestHandler, Runnable, H */ public void continue100(int available) throws IOException { - // If the client is expecting 100 CONTINUE, then send it now. - // TODO: consider using an AtomicBoolean ? - if (isExpecting100Continue()) - { - _expect100Continue = false; - - // is content missing? - if (available == 0) - { - if (_response.isCommitted()) - throw new IOException("Committed before 100 Continues"); - - // TODO: break this dependency with HttpGenerator - boolean committed = sendResponse(HttpGenerator.CONTINUE_100_INFO, null, false); - if (!committed) - throw new IOException("Concurrent commit while trying to send 100-Continue"); - } - } + throw new UnsupportedOperationException(); } public void reset() { _committed.set(false); - _expect = false; - _expect100Continue = false; - _expect102Processing = false; _request.recycle(); _response.recycle(); } @@ -458,12 +435,12 @@ public class HttpChannel implements HttpParser.RequestHandler, Runnable, H public boolean isExpecting100Continue() { - return _expect100Continue; + return false; } public boolean isExpecting102Processing() { - return _expect102Processing; + return false; } @Override @@ -478,22 +455,9 @@ public class HttpChannel implements HttpParser.RequestHandler, Runnable, H ); } - @Override - public void proxied(String protocol, String sAddr, String dAddr, int sPort, int dPort) - { - _request.setAttribute("PROXY", protocol); - _request.setServerName(sAddr); - _request.setServerPort(dPort); - _request.setRemoteAddr(InetSocketAddress.createUnresolved(sAddr,sPort)); - } - @Override public boolean startRequest(String method, HttpURI uri, HttpVersion version) { - _expect = false; - _expect100Continue = false; - _expect102Processing = false; - _request.setTimeStamp(System.currentTimeMillis()); _request.setMethod(method); @@ -515,7 +479,7 @@ public class HttpChannel implements HttpParser.RequestHandler, Runnable, H if (info == null) { - if( path==null && uri.getScheme()!=null &&uri.getHost()!=null) + if( path==null && uri.getScheme()!=null && uri.getHost()!=null) { info = "/"; _request.setRequestURI(""); @@ -526,8 +490,9 @@ public class HttpChannel implements HttpParser.RequestHandler, Runnable, H return true; } } + _request.setPathInfo(info); - _version = version == null ? HttpVersion.HTTP_0_9 : version; + _version = version; _request.setHttpVersion(_version); return false; @@ -544,46 +509,6 @@ public class HttpChannel implements HttpParser.RequestHandler, Runnable, H { switch (header) { - case EXPECT: - if (_version.getVersion()>=HttpVersion.HTTP_1_1.getVersion()) - { - HttpHeaderValue expect = HttpHeaderValue.CACHE.get(value); - switch (expect == null ? HttpHeaderValue.UNKNOWN : expect) - { - case CONTINUE: - _expect100Continue = true; - break; - - case PROCESSING: - _expect102Processing = true; - break; - - default: - String[] values = value.split(","); - for (int i = 0; values != null && i < values.length; i++) - { - expect = HttpHeaderValue.CACHE.get(values[i].trim()); - if (expect == null) - _expect = true; - else - { - switch (expect) - { - case CONTINUE: - _expect100Continue = true; - break; - case PROCESSING: - _expect102Processing = true; - break; - default: - _expect = true; - } - } - } - } - } - break; - case CONTENT_TYPE: MimeTypes.Type mime = MimeTypes.CACHE.get(value); String charset = (mime == null || mime.getCharset() == null) ? MimeTypes.getCharsetFromContentType(value) : mime.getCharset().toString(); @@ -614,31 +539,9 @@ public class HttpChannel implements HttpParser.RequestHandler, Runnable, H public boolean headerComplete() { _requests.incrementAndGet(); - switch (_version) - { - case HTTP_0_9: - break; - - case HTTP_1_0: - if (_configuration.getSendDateHeader()) - _response.getHttpFields().put(_connector.getServer().getDateField()); - break; - - case HTTP_1_1: - if (_configuration.getSendDateHeader()) - _response.getHttpFields().put(_connector.getServer().getDateField()); - - if (_expect) - { - badMessage(HttpStatus.EXPECTATION_FAILED_417,null); - return true; - } - - break; - - default: - throw new IllegalStateException(); - } + // TODO make this a better field for h2 hpack generation + if (_configuration.getSendDateHeader()) + _response.getHttpFields().put(_connector.getServer().getDateField()); return true; } diff --git a/jetty-server/src/main/java/org/eclipse/jetty/server/HttpChannelOverHttp.java b/jetty-server/src/main/java/org/eclipse/jetty/server/HttpChannelOverHttp.java new file mode 100644 index 00000000000..bede165bcf9 --- /dev/null +++ b/jetty-server/src/main/java/org/eclipse/jetty/server/HttpChannelOverHttp.java @@ -0,0 +1,263 @@ +// +// ======================================================================== +// Copyright (c) 1995-2014 Mort Bay Consulting Pty. Ltd. +// ------------------------------------------------------------------------ +// All rights reserved. This program and the accompanying materials +// are made available under the terms of the Eclipse Public License v1.0 +// and Apache License v2.0 which accompanies this distribution. +// +// The Eclipse Public License is available at +// http://www.eclipse.org/legal/epl-v10.html +// +// The Apache License v2.0 is available at +// http://www.opensource.org/licenses/apache2.0.php +// +// You may elect to redistribute this code under either of these licenses. +// ======================================================================== +// + + +package org.eclipse.jetty.server; + +import java.io.IOException; +import java.net.InetSocketAddress; +import java.nio.ByteBuffer; + +import org.eclipse.jetty.http.HttpField; +import org.eclipse.jetty.http.HttpGenerator; +import org.eclipse.jetty.http.HttpHeader; +import org.eclipse.jetty.http.HttpHeaderValue; +import org.eclipse.jetty.http.HttpMethod; +import org.eclipse.jetty.http.HttpParser; +import org.eclipse.jetty.http.HttpStatus; +import org.eclipse.jetty.http.HttpURI; +import org.eclipse.jetty.http.HttpVersion; +import org.eclipse.jetty.io.EndPoint; + +/** + * A HttpChannel customized to be transported over the HTTP/1 protocol + */ +class HttpChannelOverHttp extends HttpChannel implements HttpParser.ProxyHandler +{ + /** + * + */ + private final HttpConnection _httpConnection; + private boolean _expect = false; + private boolean _expect100Continue = false; + private boolean _expect102Processing = false; + + public HttpChannelOverHttp(HttpConnection httpConnection, Connector connector, HttpConfiguration config, EndPoint endPoint, HttpTransport transport, HttpInput input) + { + super(connector,config,endPoint,transport,input); + _httpConnection = httpConnection; + } + + @Override + public void reset() + { + super.reset(); + _expect = false; + _expect100Continue = false; + _expect102Processing = false; + } + + @Override + public boolean isExpecting100Continue() + { + return _expect100Continue; + } + + @Override + public boolean isExpecting102Processing() + { + return _expect102Processing; + } + + @Override + public boolean startRequest(String method, HttpURI uri, HttpVersion version) + { + _expect = false; + _expect100Continue = false; + _expect102Processing = false; + return super.startRequest(method,uri,version); + } + + @Override + public void proxied(String protocol, String sAddr, String dAddr, int sPort, int dPort) + { + Request request = getRequest(); + request.setAttribute("PROXY", protocol); + request.setServerName(sAddr); + request.setServerPort(dPort); + request.setRemoteAddr(InetSocketAddress.createUnresolved(sAddr,sPort)); + } + + + @Override + public boolean parsedHeader(HttpField field) + { + HttpHeader header=field.getHeader(); + String value=field.getValue(); + if (getRequest().getHttpVersion().getVersion()==HttpVersion.HTTP_1_1.getVersion() && header == HttpHeader.EXPECT) + { + HttpHeaderValue expect = HttpHeaderValue.CACHE.get(value); + switch (expect == null ? HttpHeaderValue.UNKNOWN : expect) + { + case CONTINUE: + _expect100Continue = true; + break; + + case PROCESSING: + _expect102Processing = true; + break; + + default: + String[] values = value.split(","); + for (int i = 0; values != null && i < values.length; i++) + { + expect = HttpHeaderValue.CACHE.get(values[i].trim()); + if (expect == null) + _expect = true; + else + { + switch (expect) + { + case CONTINUE: + _expect100Continue = true; + break; + case PROCESSING: + _expect102Processing = true; + break; + default: + _expect = true; + } + } + } + } + } + return super.parsedHeader(field); + } + + /** + * If the associated response has the Expect header set to 100 Continue, + * then accessing the input stream indicates that the handler/servlet + * is ready for the request body and thus a 100 Continue response is sent. + * + * @throws IOException if the InputStream cannot be created + */ + @Override + public void continue100(int available) throws IOException + { + // If the client is expecting 100 CONTINUE, then send it now. + // TODO: consider using an AtomicBoolean ? + if (isExpecting100Continue()) + { + _expect100Continue = false; + + // is content missing? + if (available == 0) + { + if (getResponse().isCommitted()) + throw new IOException("Committed before 100 Continues"); + + // TODO: break this dependency with HttpGenerator + boolean committed = sendResponse(HttpGenerator.CONTINUE_100_INFO, null, false); + if (!committed) + throw new IOException("Concurrent commit while trying to send 100-Continue"); + } + } + } + + + @Override + public void earlyEOF() + { + // If we have no request yet, just close + if (getRequest().getMethod()==null) + _httpConnection.close(); + else + super.earlyEOF(); + } + + @Override + public boolean content(ByteBuffer item) + { + super.content(item); + return true; + } + + @Override + public void badMessage(int status, String reason) + { + _httpConnection._generator.setPersistent(false); + super.badMessage(status,reason); + } + + @Override + public boolean headerComplete() + { + boolean persistent; + HttpVersion version = getHttpVersion(); + + switch (version) + { + case HTTP_1_0: + { + persistent = getRequest().getHttpFields().contains(HttpHeader.CONNECTION, HttpHeaderValue.KEEP_ALIVE.asString()); + if (!persistent) + persistent = HttpMethod.CONNECT.is(getRequest().getMethod()); + if (persistent) + getResponse().getHttpFields().add(HttpHeader.CONNECTION, HttpHeaderValue.KEEP_ALIVE); + break; + } + + case HTTP_1_1: + { + if (_expect) + { + badMessage(HttpStatus.EXPECTATION_FAILED_417,null); + return true; + } + + persistent = !getRequest().getHttpFields().contains(HttpHeader.CONNECTION, HttpHeaderValue.CLOSE.asString()); + if (!persistent) + persistent = HttpMethod.CONNECT.is(getRequest().getMethod()); + if (!persistent) + getResponse().getHttpFields().add(HttpHeader.CONNECTION, HttpHeaderValue.CLOSE); + break; + } + + default: + { + throw new IllegalStateException(); + } + } + + if (!persistent) + _httpConnection._generator.setPersistent(false); + + return super.headerComplete(); + } + + @Override + protected void handleException(Throwable x) + { + _httpConnection._generator.setPersistent(false); + super.handleException(x); + } + + @Override + public void failed() + { + getEndPoint().shutdownOutput(); + } + + + @Override + public boolean messageComplete() + { + super.messageComplete(); + return false; + } +} \ No newline at end of file diff --git a/jetty-server/src/main/java/org/eclipse/jetty/server/HttpConnection.java b/jetty-server/src/main/java/org/eclipse/jetty/server/HttpConnection.java index 16cbbf93d6b..22a4326bd40 100644 --- a/jetty-server/src/main/java/org/eclipse/jetty/server/HttpConnection.java +++ b/jetty-server/src/main/java/org/eclipse/jetty/server/HttpConnection.java @@ -24,12 +24,9 @@ import java.util.concurrent.RejectedExecutionException; import org.eclipse.jetty.http.HttpGenerator; import org.eclipse.jetty.http.HttpGenerator.ResponseInfo; -import org.eclipse.jetty.http.HttpHeader; -import org.eclipse.jetty.http.HttpHeaderValue; -import org.eclipse.jetty.http.HttpMethod; import org.eclipse.jetty.http.HttpParser; import org.eclipse.jetty.http.HttpStatus; -import org.eclipse.jetty.http.HttpVersion; +import org.eclipse.jetty.http.MimeTypes; import org.eclipse.jetty.io.AbstractConnection; import org.eclipse.jetty.io.ByteBufferPool; import org.eclipse.jetty.io.Connection; @@ -56,7 +53,7 @@ public class HttpConnection extends AbstractConnection implements Runnable, Http private final HttpConfiguration _config; private final Connector _connector; private final ByteBufferPool _bufferPool; - private final HttpGenerator _generator; + final HttpGenerator _generator; private final HttpChannelOverHttp _channel; private final HttpParser _parser; private volatile ByteBuffer _requestBuffer = null; @@ -118,7 +115,7 @@ public class HttpConnection extends AbstractConnection implements Runnable, Http protected HttpChannelOverHttp newHttpChannel(HttpInput httpInput) { - return new HttpChannelOverHttp(_connector, _config, getEndPoint(), this, httpInput); + return new HttpChannelOverHttp(this, _connector, _config, getEndPoint(), this, httpInput); } protected HttpParser newHttpParser() @@ -447,102 +444,6 @@ public class HttpConnection extends AbstractConnection implements Runnable, Http } - protected class HttpChannelOverHttp extends HttpChannel - { - public HttpChannelOverHttp(Connector connector, HttpConfiguration config, EndPoint endPoint, HttpTransport transport, HttpInput input) - { - super(connector,config,endPoint,transport,input); - } - - @Override - public void earlyEOF() - { - // If we have no request yet, just close - if (getRequest().getMethod()==null) - close(); - else - super.earlyEOF(); - } - - @Override - public boolean content(ByteBuffer item) - { - super.content(item); - return true; - } - - @Override - public void badMessage(int status, String reason) - { - _generator.setPersistent(false); - super.badMessage(status,reason); - } - - @Override - public boolean headerComplete() - { - boolean persistent; - HttpVersion version = getHttpVersion(); - - switch (version) - { - case HTTP_0_9: - { - persistent = false; - break; - } - case HTTP_1_0: - { - persistent = getRequest().getHttpFields().contains(HttpHeader.CONNECTION, HttpHeaderValue.KEEP_ALIVE.asString()); - if (!persistent) - persistent = HttpMethod.CONNECT.is(getRequest().getMethod()); - if (persistent) - getResponse().getHttpFields().add(HttpHeader.CONNECTION, HttpHeaderValue.KEEP_ALIVE); - break; - } - case HTTP_1_1: - { - persistent = !getRequest().getHttpFields().contains(HttpHeader.CONNECTION, HttpHeaderValue.CLOSE.asString()); - if (!persistent) - persistent = HttpMethod.CONNECT.is(getRequest().getMethod()); - if (!persistent) - getResponse().getHttpFields().add(HttpHeader.CONNECTION, HttpHeaderValue.CLOSE); - break; - } - default: - { - throw new IllegalStateException(); - } - } - - if (!persistent) - _generator.setPersistent(false); - - return super.headerComplete(); - } - - @Override - protected void handleException(Throwable x) - { - _generator.setPersistent(false); - super.handleException(x); - } - - @Override - public void failed() - { - getEndPoint().shutdownOutput(); - } - - - @Override - public boolean messageComplete() - { - super.messageComplete(); - return false; - } - } - private class CommitCallback extends IteratingCallback { final ByteBuffer _content; diff --git a/jetty-server/src/test/java/org/eclipse/jetty/server/ExtendedServerTest.java b/jetty-server/src/test/java/org/eclipse/jetty/server/ExtendedServerTest.java index 9ddaaf56e15..7162da1d9c6 100644 --- a/jetty-server/src/test/java/org/eclipse/jetty/server/ExtendedServerTest.java +++ b/jetty-server/src/test/java/org/eclipse/jetty/server/ExtendedServerTest.java @@ -102,7 +102,7 @@ public class ExtendedServerTest extends HttpServerTestBase @Override protected HttpChannelOverHttp newHttpChannel(HttpInput httpInput) { - return new HttpChannelOverHttp(getConnector(), getHttpConfiguration(), getEndPoint(), this, httpInput) + return new HttpChannelOverHttp(this, getConnector(), getHttpConfiguration(), getEndPoint(), this, httpInput) { @Override public boolean startRequest(String method, HttpURI uri, HttpVersion version)