From fa06ae97629fec0d0e189deaaeb1112c954d562b Mon Sep 17 00:00:00 2001 From: Simone Bordet Date: Wed, 22 Aug 2012 09:39:03 +0200 Subject: [PATCH] Jetty9 - Removed old code not used anymore, greatly simplifying the implementation. --- .../org/eclipse/jetty/server/Dispatcher.java | 156 +++-- .../org/eclipse/jetty/server/HttpChannel.java | 554 +++++++-------- .../eclipse/jetty/server/HttpConnection.java | 594 +--------------- .../org/eclipse/jetty/server/Response.java | 648 ++++++------------ .../jetty/server/HttpConnectionTest.java | 30 +- 5 files changed, 589 insertions(+), 1393 deletions(-) diff --git a/jetty-server/src/main/java/org/eclipse/jetty/server/Dispatcher.java b/jetty-server/src/main/java/org/eclipse/jetty/server/Dispatcher.java index 7528db8a875..90954666c6f 100644 --- a/jetty-server/src/main/java/org/eclipse/jetty/server/Dispatcher.java +++ b/jetty-server/src/main/java/org/eclipse/jetty/server/Dispatcher.java @@ -22,7 +22,6 @@ import java.io.IOException; import java.util.Collections; import java.util.Enumeration; import java.util.HashSet; - import javax.servlet.DispatcherType; import javax.servlet.RequestDispatcher; import javax.servlet.ServletException; @@ -38,8 +37,8 @@ import org.eclipse.jetty.util.UrlEncoded; /* ------------------------------------------------------------ */ /** Servlet RequestDispatcher. - * - * + * + * */ public class Dispatcher implements RequestDispatcher { @@ -58,7 +57,7 @@ public class Dispatcher implements RequestDispatcher private final String _path; private final String _dQuery; private final String _named; - + /* ------------------------------------------------------------ */ /** * @param contextHandler @@ -77,7 +76,7 @@ public class Dispatcher implements RequestDispatcher /* ------------------------------------------------------------ */ - /** Constructor. + /** Constructor. * @param contextHandler * @param name */ @@ -90,9 +89,9 @@ public class Dispatcher implements RequestDispatcher _path=null; _dQuery=null; } - + /* ------------------------------------------------------------ */ - /* + /* * @see javax.servlet.RequestDispatcher#forward(javax.servlet.ServletRequest, javax.servlet.ServletResponse) */ @Override @@ -100,34 +99,34 @@ public class Dispatcher implements RequestDispatcher { forward(request, response, DispatcherType.FORWARD); } - + /* ------------------------------------------------------------ */ - /* + /* * @see javax.servlet.RequestDispatcher#forward(javax.servlet.ServletRequest, javax.servlet.ServletResponse) */ public void error(ServletRequest request, ServletResponse response) throws ServletException, IOException { forward(request, response, DispatcherType.ERROR); } - + /* ------------------------------------------------------------ */ - /* + /* * @see javax.servlet.RequestDispatcher#include(javax.servlet.ServletRequest, javax.servlet.ServletResponse) */ @Override public void include(ServletRequest request, ServletResponse response) throws ServletException, IOException { Request baseRequest=(request instanceof Request)?((Request)request):HttpChannel.getCurrentHttpChannel().getRequest(); - - + + if (!(request instanceof HttpServletRequest)) request = new ServletRequestHttpWrapper(request); if (!(response instanceof HttpServletResponse)) response = new ServletResponseHttpWrapper(response); - - + + // TODO - allow stream or writer???? - + final DispatcherType old_type = baseRequest.getDispatcherType(); final Attributes old_attr=baseRequest.getAttributes(); MultiMap old_params=baseRequest.getParameters(); @@ -137,10 +136,10 @@ public class Dispatcher implements RequestDispatcher baseRequest.getResponse().include(); if (_named!=null) _contextHandler.handle(_named,baseRequest, (HttpServletRequest)request, (HttpServletResponse)response); - else + else { String query=_dQuery; - + if (query!=null) { // force parameter extraction @@ -149,27 +148,27 @@ public class Dispatcher implements RequestDispatcher baseRequest.extractParameters(); old_params=baseRequest.getParameters(); } - + MultiMap parameters=new MultiMap<>(); UrlEncoded.decodeTo(query,parameters,baseRequest.getCharacterEncoding()); - + if(old_params != null) { // Merge parameters. parameters.addAllValues(old_params); } baseRequest.setParameters(parameters); } - - IncludeAttributes attr = new IncludeAttributes(old_attr); - + + IncludeAttributes attr = new IncludeAttributes(old_attr); + attr._requestURI=_uri; attr._contextPath=_contextHandler.getContextPath(); attr._servletPath=null; // set by ServletHandler attr._pathInfo=_path; attr._query=query; - + baseRequest.setAttributes(attr); - + _contextHandler.handle(_path,baseRequest, (HttpServletRequest)request, (HttpServletResponse)response); } } @@ -182,24 +181,23 @@ public class Dispatcher implements RequestDispatcher } } - + /* ------------------------------------------------------------ */ - /* + /* * @see javax.servlet.RequestDispatcher#forward(javax.servlet.ServletRequest, javax.servlet.ServletResponse) */ protected void forward(ServletRequest request, ServletResponse response, DispatcherType dispatch) throws ServletException, IOException { Request baseRequest=(request instanceof Request)?((Request)request):HttpChannel.getCurrentHttpChannel().getRequest(); Response base_response=baseRequest.getResponse(); - response.resetBuffer(); - base_response.fwdReset(); - + base_response.resetForForward(); + if (!(request instanceof HttpServletRequest)) request = new ServletRequestHttpWrapper(request); if (!(response instanceof HttpServletResponse)) response = new ServletResponseHttpWrapper(response); - + final boolean old_handled=baseRequest.isHandled(); final String old_uri=baseRequest.getRequestURI(); final String old_context_path=baseRequest.getContextPath(); @@ -209,17 +207,17 @@ public class Dispatcher implements RequestDispatcher final Attributes old_attr=baseRequest.getAttributes(); final DispatcherType old_type=baseRequest.getDispatcherType(); MultiMap old_params=baseRequest.getParameters(); - + try { baseRequest.setHandled(false); baseRequest.setDispatcherType(dispatch); - + if (_named!=null) _contextHandler.handle(_named,baseRequest, (HttpServletRequest)request, (HttpServletResponse)response); - else + else { - + // process any query string from the dispatch URL String query=_dQuery; if (query!=null) @@ -230,13 +228,13 @@ public class Dispatcher implements RequestDispatcher baseRequest.extractParameters(); old_params=baseRequest.getParameters(); } - + baseRequest.mergeQueryString(query); } - - ForwardAttributes attr = new ForwardAttributes(old_attr); - - //If we have already been forwarded previously, then keep using the established + + ForwardAttributes attr = new ForwardAttributes(old_attr); + + //If we have already been forwarded previously, then keep using the established //original value. Otherwise, this is the first forward and we need to establish the values. //Note: the established value on the original request for pathInfo and //for queryString is allowed to be null, but cannot be null for the other values. @@ -255,16 +253,16 @@ public class Dispatcher implements RequestDispatcher attr._requestURI=old_uri; attr._contextPath=old_context_path; attr._servletPath=old_servlet_path; - } - + } + baseRequest.setRequestURI(_uri); baseRequest.setContextPath(_contextHandler.getContextPath()); baseRequest.setServletPath(null); baseRequest.setPathInfo(_uri); baseRequest.setAttributes(attr); - + _contextHandler.handle(_path,baseRequest, (HttpServletRequest)request, (HttpServletResponse)response); - + if (!baseRequest.getAsyncContinuation().isAsyncStarted()) commitResponse(response,baseRequest); } @@ -318,41 +316,41 @@ public class Dispatcher implements RequestDispatcher private class ForwardAttributes implements Attributes { final Attributes _attr; - + String _requestURI; String _contextPath; String _servletPath; String _pathInfo; String _query; - + ForwardAttributes(Attributes attributes) { _attr=attributes; } - + /* ------------------------------------------------------------ */ public Object getAttribute(String key) { if (Dispatcher.this._named==null) { - if (key.equals(FORWARD_PATH_INFO)) + if (key.equals(FORWARD_PATH_INFO)) return _pathInfo; - if (key.equals(FORWARD_REQUEST_URI)) + if (key.equals(FORWARD_REQUEST_URI)) return _requestURI; - if (key.equals(FORWARD_SERVLET_PATH)) + if (key.equals(FORWARD_SERVLET_PATH)) return _servletPath; - if (key.equals(FORWARD_CONTEXT_PATH)) + if (key.equals(FORWARD_CONTEXT_PATH)) return _contextPath; - if (key.equals(FORWARD_QUERY_STRING)) + if (key.equals(FORWARD_QUERY_STRING)) return _query; } - + if (key.startsWith(__INCLUDE_PREFIX)) return null; - + return _attr.getAttribute(key); } - + /* ------------------------------------------------------------ */ public Enumeration getAttributeNames() { @@ -365,7 +363,7 @@ public class Dispatcher implements RequestDispatcher !name.startsWith(__FORWARD_PREFIX)) set.add(name); } - + if (_named==null) { if (_pathInfo!=null) @@ -383,37 +381,37 @@ public class Dispatcher implements RequestDispatcher return Collections.enumeration(set); } - + /* ------------------------------------------------------------ */ public void setAttribute(String key, Object value) { if (_named==null && key.startsWith("javax.servlet.")) { - if (key.equals(FORWARD_PATH_INFO)) + if (key.equals(FORWARD_PATH_INFO)) _pathInfo=(String)value; - else if (key.equals(FORWARD_REQUEST_URI)) + else if (key.equals(FORWARD_REQUEST_URI)) _requestURI=(String)value; - else if (key.equals(FORWARD_SERVLET_PATH)) + else if (key.equals(FORWARD_SERVLET_PATH)) _servletPath=(String)value; - else if (key.equals(FORWARD_CONTEXT_PATH)) + else if (key.equals(FORWARD_CONTEXT_PATH)) _contextPath=(String)value; - else if (key.equals(FORWARD_QUERY_STRING)) + else if (key.equals(FORWARD_QUERY_STRING)) _query=(String)value; - + else if (value==null) _attr.removeAttribute(key); else - _attr.setAttribute(key,value); + _attr.setAttribute(key,value); } else if (value==null) _attr.removeAttribute(key); else _attr.setAttribute(key,value); } - + /* ------------------------------------------------------------ */ @Override - public String toString() + public String toString() { return "FORWARD+"+_attr.toString(); } @@ -435,18 +433,18 @@ public class Dispatcher implements RequestDispatcher private class IncludeAttributes implements Attributes { final Attributes _attr; - + String _requestURI; String _contextPath; String _servletPath; String _pathInfo; String _query; - + IncludeAttributes(Attributes attributes) { _attr=attributes; } - + /* ------------------------------------------------------------ */ /* ------------------------------------------------------------ */ /* ------------------------------------------------------------ */ @@ -460,13 +458,13 @@ public class Dispatcher implements RequestDispatcher if (key.equals(INCLUDE_QUERY_STRING)) return _query; if (key.equals(INCLUDE_REQUEST_URI)) return _requestURI; } - else if (key.startsWith(__INCLUDE_PREFIX)) + else if (key.startsWith(__INCLUDE_PREFIX)) return null; - - + + return _attr.getAttribute(key); } - + /* ------------------------------------------------------------ */ public Enumeration getAttributeNames() { @@ -478,7 +476,7 @@ public class Dispatcher implements RequestDispatcher if (!name.startsWith(__INCLUDE_PREFIX)) set.add(name); } - + if (_named==null) { if (_pathInfo!=null) @@ -493,10 +491,10 @@ public class Dispatcher implements RequestDispatcher else set.remove(INCLUDE_QUERY_STRING); } - + return Collections.enumeration(set); } - + /* ------------------------------------------------------------ */ public void setAttribute(String key, Object value) { @@ -510,17 +508,17 @@ public class Dispatcher implements RequestDispatcher else if (value==null) _attr.removeAttribute(key); else - _attr.setAttribute(key,value); + _attr.setAttribute(key,value); } else if (value==null) _attr.removeAttribute(key); else _attr.setAttribute(key,value); } - + /* ------------------------------------------------------------ */ @Override - public String toString() + public String toString() { return "INCLUDE+"+_attr.toString(); } 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 c11f7a74e68..61198a2d264 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 @@ -23,6 +23,7 @@ import java.net.InetSocketAddress; import java.nio.ByteBuffer; import java.util.concurrent.ScheduledExecutorService; import java.util.concurrent.atomic.AtomicBoolean; +import java.util.concurrent.atomic.AtomicInteger; import javax.servlet.DispatcherType; import javax.servlet.RequestDispatcher; @@ -48,9 +49,9 @@ import org.eclipse.jetty.util.URIUtil; import org.eclipse.jetty.util.log.Log; import org.eclipse.jetty.util.log.Logger; -public class HttpChannel +public class HttpChannel implements HttpParser.RequestHandler { - protected static final Logger LOG = Log.getLogger(HttpChannel.class); + private static final Logger LOG = Log.getLogger(HttpChannel.class); private static final ThreadLocal __currentChannel = new ThreadLocal<>(); public static HttpChannel getCurrentHttpChannel() @@ -64,7 +65,7 @@ public class HttpChannel } private final AtomicBoolean _committed = new AtomicBoolean(); - private final ChannelEventHandler _handler = new ChannelEventHandler(); + private final AtomicInteger _requests = new AtomicInteger(); private final Connector _connector; private final HttpConfiguration _configuration; private final EndPoint _endPoint; @@ -73,7 +74,6 @@ public class HttpChannel private final HttpChannelState _state; private final Request _request; private final Response _response; - private int _requests; private HttpVersion _version = HttpVersion.HTTP_1_1; private boolean _expect = false; private boolean _expect100Continue = false; @@ -98,22 +98,22 @@ public class HttpChannel return _state; } - public EventHandler getEventHandler() - { - return _handler; - } - - public boolean isIdle() - { - return _state.isIdle(); - } - /** * @return the number of requests handled by this connection */ public int getRequests() { - return _requests; + return _requests.get(); + } + + public Connector getConnector() + { + return _connector; + } + + public HttpConfiguration getHttpConfiguration() + { + return _configuration; } public Server getServer() @@ -121,17 +121,11 @@ public class HttpChannel return _connector.getServer(); } - /** - * @return Returns the request. - */ public Request getRequest() { return _request; } - /** - * @return Returns the response. - */ public Response getResponse() { return _response; @@ -285,7 +279,7 @@ public class HttpChannel // do anything special here other than make the connection not persistent _expect100Continue = false; if (!isCommitted()) - _response.addHeader(HttpHeader.CONNECTION, HttpHeaderValue.CLOSE.toString()); + _response.addHeader(HttpHeader.CONNECTION.toString(), HttpHeaderValue.CLOSE.toString()); else LOG.warn("Cannot send 'Connection: close' for 100-Continue, response is already committed"); } @@ -310,78 +304,78 @@ public class HttpChannel // TODO: remove this method protected void completed() { -/* - // This method is called by handle() when it knows that its handling of the request/response cycle - // is complete. - // This may happen in the original thread dispatched to the connection that has called handle(), - // or it may be from a thread dispatched to call handle() as the result of a resumed suspended request. + /* + // This method is called by handle() when it knows that its handling of the request/response cycle + // is complete. + // This may happen in the original thread dispatched to the connection that has called handle(), + // or it may be from a thread dispatched to call handle() as the result of a resumed suspended request. - LOG.debug("{} complete", this); + LOG.debug("{} complete", this); - // Handle connection upgrades - if (_response.getStatus() == HttpStatus.SWITCHING_PROTOCOLS_101) - { - Connection connection = (Connection)getRequest().getAttribute(HttpConnection.UPGRADE_CONNECTION_ATTRIBUTE); - if (connection != null) - { - LOG.debug("Upgrade from {} to {}", this, connection); - getEndPoint().setConnection(connection); -// HttpConnection.this.reset(); // TODO: this should be done by the connection privately when handle returns - return; - } - } - - - // Reset everything for the next cycle. -// HttpConnection.this.reset(); // TODO: this should be done by the connection privately when handle returns - - // are called from non connection thread (ie dispatched from a resume) - if (getCurrentConnection()!=HttpConnection.this) - { - if (_parser.isStart()) - { - // it wants to eat more - if (_requestBuffer==null) - fillInterested(); - else if (getConnector().isStarted()) + // Handle connection upgrades + if (_response.getStatus() == HttpStatus.SWITCHING_PROTOCOLS_101) { - LOG.debug("{} pipelined",this); - - try + Connection connection = (Connection)getRequest().getAttribute(HttpConnection.UPGRADE_CONNECTION_ATTRIBUTE); + if (connection != null) { - execute(this); - } - catch(RejectedExecutionException e) - { - if (getConnector().isStarted()) - LOG.warn(e); - else - LOG.ignore(e); - getEndPoint().close(); + LOG.debug("Upgrade from {} to {}", this, connection); + getEndPoint().setConnection(connection); + // HttpConnection.this.reset(); // TODO: this should be done by the connection privately when handle returns + return; } } - else - getEndPoint().close(); - } - if (_parser.isClosed()&&!getEndPoint().isOutputShutdown()) - { - // TODO This is a catch all indicating some protocol handling failure - // Currently needed for requests saying they are HTTP/2.0. - // This should be removed once better error handling is in place - LOG.warn("Endpoint output not shutdown when seeking EOF"); - getEndPoint().shutdownOutput(); - } - } - // make sure that an oshut connection is driven towards close - // TODO this is a little ugly - if (getEndPoint().isOpen() && getEndPoint().isOutputShutdown()) - { - fillInterested(); - } -*/ + // Reset everything for the next cycle. + // HttpConnection.this.reset(); // TODO: this should be done by the connection privately when handle returns + + // are called from non connection thread (ie dispatched from a resume) + if (getCurrentConnection()!=HttpConnection.this) + { + if (_parser.isStart()) + { + // it wants to eat more + if (_requestBuffer==null) + fillInterested(); + else if (getConnector().isStarted()) + { + LOG.debug("{} pipelined",this); + + try + { + execute(this); + } + catch(RejectedExecutionException e) + { + if (getConnector().isStarted()) + LOG.warn(e); + else + LOG.ignore(e); + getEndPoint().close(); + } + } + else + getEndPoint().close(); + } + + if (_parser.isClosed()&&!getEndPoint().isOutputShutdown()) + { + // TODO This is a catch all indicating some protocol handling failure + // Currently needed for requests saying they are HTTP/2.0. + // This should be removed once better error handling is in place + LOG.warn("Endpoint output not shutdown when seeking EOF"); + getEndPoint().shutdownOutput(); + } + } + + // make sure that an oshut connection is driven towards close + // TODO this is a little ugly + if (getEndPoint().isOpen() && getEndPoint().isOutputShutdown()) + { + fillInterested(); + } + */ } /** @@ -390,6 +384,7 @@ public class HttpChannel *

It may happen that the application suspends, and then throws an exception, while an application * spawned thread writes the response content; in such case, we attempt to commit the error directly * bypassing the {@link ErrorHandler} mechanisms and the response OutputStream.

+ * * @param x the Throwable that caused the problem */ private void handleError(Throwable x) @@ -479,10 +474,10 @@ public class HttpChannel { // TODO: not sure why we need to modify the request when writing an error ? // TODO: or modify the response if the error code cannot have a body ? - // _channel.getRequest().getHttpFields().remove(HttpHeader.CONTENT_TYPE); - // _channel.getRequest().getHttpFields().remove(HttpHeader.CONTENT_LENGTH); - // _characterEncoding = null; - // _mimeType = null; + // _channel.getRequest().getHttpFields().remove(HttpHeader.CONTENT_TYPE); + // _channel.getRequest().getHttpFields().remove(HttpHeader.CONTENT_LENGTH); + // _characterEncoding = null; + // _mimeType = null; } complete(); @@ -510,16 +505,6 @@ public class HttpChannel return reason; } - public boolean isSuspended() - { - return _request.getAsyncContinuation().isSuspended(); - } - - public void onClose() - { - LOG.debug("closed {}", this); - } - public boolean isExpecting100Continue() { return _expect100Continue; @@ -533,206 +518,203 @@ public class HttpChannel @Override public String toString() { - return String.format("%s@%x{r=%d,a=%s}", + return String.format("%s@%x{r=%s,a=%s}", getClass().getSimpleName(), hashCode(), _requests, _state.getState()); } - private class ChannelEventHandler implements EventHandler + @Override + public boolean startRequest(HttpMethod httpMethod, String method, String uri, HttpVersion version) { - @Override - public boolean startRequest(HttpMethod httpMethod, String method, String uri, HttpVersion version) + _host = false; + _expect = false; + _expect100Continue = false; + _expect102Processing = false; + + if (_request.getTimeStamp() == 0) + _request.setTimeStamp(System.currentTimeMillis()); + _request.setMethod(httpMethod, method); + + if (httpMethod == HttpMethod.CONNECT) + _uri.parseConnect(uri); + else + _uri.parse(uri); + _request.setUri(_uri); + + String path; + try { - _host = false; - _expect = false; - _expect100Continue = false; - _expect102Processing = false; - - if (_request.getTimeStamp() == 0) - _request.setTimeStamp(System.currentTimeMillis()); - _request.setMethod(httpMethod, method); - - if (httpMethod == HttpMethod.CONNECT) - _uri.parseConnect(uri); - else - _uri.parse(uri); - _request.setUri(_uri); - - String path; - try - { - path = _uri.getDecodedPath(); - } - catch (Exception e) - { - LOG.warn("Failed UTF-8 decode for request path, trying ISO-8859-1"); - LOG.ignore(e); - path = _uri.getDecodedPath(StringUtil.__ISO_8859_1); - } - String info = URIUtil.canonicalPath(path); - - if (info == null) - info = "/"; - _request.setPathInfo(info); - _version = version == null ? HttpVersion.HTTP_0_9 : version; - _request.setHttpVersion(_version); - - return false; + path = _uri.getDecodedPath(); } - - @Override - public boolean parsedHeader(HttpHeader header, String name, String value) + catch (Exception e) { - if (value == null) - value = ""; - if (header != null) + LOG.warn("Failed UTF-8 decode for request path, trying ISO-8859-1"); + LOG.ignore(e); + path = _uri.getDecodedPath(StringUtil.__ISO_8859_1); + } + String info = URIUtil.canonicalPath(path); + + if (info == null) + info = "/"; + _request.setPathInfo(info); + _version = version == null ? HttpVersion.HTTP_0_9 : version; + _request.setHttpVersion(_version); + + return false; + } + + @Override + public boolean parsedHeader(HttpHeader header, String name, String value) + { + if (value == null) + value = ""; + if (header != null) + { + switch (header) { - switch (header) - { - case HOST: - // TODO check if host matched a host in the URI. - _host = true; - break; + case HOST: + // TODO check if host matched a host in the URI. + _host = true; + break; - case EXPECT: - HttpHeaderValue expect = HttpHeaderValue.CACHE.get(value); - switch (expect == null ? HttpHeaderValue.UNKNOWN : expect) - { - case CONTINUE: - _expect100Continue = true; - break; + case EXPECT: + HttpHeaderValue expect = HttpHeaderValue.CACHE.get(value); + switch (expect == null ? HttpHeaderValue.UNKNOWN : expect) + { + case CONTINUE: + _expect100Continue = true; + break; - case PROCESSING: - _expect102Processing = true; - break; + case PROCESSING: + _expect102Processing = true; + break; - default: - String[] values = value.split(","); - for (int i = 0; values != null && i < values.length; i++) + 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 { - expect = HttpHeaderValue.CACHE.get(values[i].trim()); - if (expect == null) - _expect = true; - else + switch (expect) { - switch (expect) - { - case CONTINUE: - _expect100Continue = true; - break; - case PROCESSING: - _expect102Processing = true; - break; - default: - _expect = true; - } + case CONTINUE: + _expect100Continue = true; + break; + case PROCESSING: + _expect102Processing = true; + break; + default: + _expect = true; } } - } - break; + } + } + break; - case CONTENT_TYPE: - MimeTypes.Type mime = MimeTypes.CACHE.get(value); - String charset = (mime == null || mime.getCharset() == null) ? MimeTypes.getCharsetFromContentType(value) : mime.getCharset().toString(); - if (charset != null) - _request.setCharacterEncodingUnchecked(charset); - break; + case CONTENT_TYPE: + MimeTypes.Type mime = MimeTypes.CACHE.get(value); + String charset = (mime == null || mime.getCharset() == null) ? MimeTypes.getCharsetFromContentType(value) : mime.getCharset().toString(); + if (charset != null) + _request.setCharacterEncodingUnchecked(charset); + break; + } + } + if (name != null) + _request.getHttpFields().add(name, value); + return false; + } + + @Override + public boolean headerComplete() + { + _requests.incrementAndGet(); + boolean persistent; + switch (_version) + { + case HTTP_0_9: + persistent = false; + break; + case HTTP_1_0: + persistent = _request.getHttpFields().contains(HttpHeader.CONNECTION, HttpHeaderValue.KEEP_ALIVE.asString()); + if (persistent) + _response.getHttpFields().add(HttpHeader.CONNECTION, HttpHeaderValue.KEEP_ALIVE); + + if (getServer().getSendDateHeader()) + _response.getHttpFields().putDateField(HttpHeader.DATE.toString(), _request.getTimeStamp()); + break; + + case HTTP_1_1: + persistent = !_request.getHttpFields().contains(HttpHeader.CONNECTION, HttpHeaderValue.CLOSE.asString()); + + if (!persistent) + _response.getHttpFields().add(HttpHeader.CONNECTION, HttpHeaderValue.CLOSE); + + if (getServer().getSendDateHeader()) + _response.getHttpFields().putDateField(HttpHeader.DATE.toString(), _request.getTimeStamp()); + + if (!_host) + { + _response.sendError(Response.SC_BAD_REQUEST, "No Host Header", null); + return true; } - } - if (name != null) - _request.getHttpFields().add(name, value); - return false; + + if (_expect) + { + _response.sendError(Response.SC_EXPECTATION_FAILED, null, null); + return true; + } + + break; + default: + throw new IllegalStateException(); } - @Override - public boolean headerComplete() + _request.setPersistent(persistent); + + // Either handle now or wait for first content/message complete + return _expect100Continue; + } + + @Override + public boolean content(ByteBuffer ref) + { + if (LOG.isDebugEnabled()) { - _requests++; - boolean persistent; - switch (_version) - { - case HTTP_0_9: - persistent = false; - break; - case HTTP_1_0: - persistent = _request.getHttpFields().contains(HttpHeader.CONNECTION, HttpHeaderValue.KEEP_ALIVE.asString()); - if (persistent) - _response.getHttpFields().add(HttpHeader.CONNECTION, HttpHeaderValue.KEEP_ALIVE); - - if (getServer().getSendDateHeader()) - _response.getHttpFields().putDateField(HttpHeader.DATE.toString(), _request.getTimeStamp()); - break; - - case HTTP_1_1: - persistent = !_request.getHttpFields().contains(HttpHeader.CONNECTION, HttpHeaderValue.CLOSE.asString()); - - if (!persistent) - _response.getHttpFields().add(HttpHeader.CONNECTION, HttpHeaderValue.CLOSE); - - if (getServer().getSendDateHeader()) - _response.getHttpFields().putDateField(HttpHeader.DATE.toString(), _request.getTimeStamp()); - - if (!_host) - { - _response.sendError(Response.SC_BAD_REQUEST, "No Host Header", null); - return true; - } - - if (_expect) - { - _response.sendError(Response.SC_EXPECTATION_FAILED, null, null); - return true; - } - - break; - default: - throw new IllegalStateException(); - } - - _request.setPersistent(persistent); - - // Either handle now or wait for first content/message complete - if (_expect100Continue) - return true; - - return false; + LOG.debug("{} content {}", this, BufferUtil.toDetailString(ref)); } + _request.getHttpInput().content(ref); + return true; + } - @Override - public boolean content(ByteBuffer ref) - { - if (LOG.isDebugEnabled()) - { - LOG.debug("{} content {}", this, BufferUtil.toDetailString(ref)); - } - _request.getHttpInput().content(ref); - return true; - } + @Override + public boolean messageComplete(long contentLength) + { + _request.getHttpInput().shutdownInput(); + return true; + } - @Override - public boolean messageComplete(long contentLength) - { - _request.getHttpInput().shutdownInput(); - return true; - } + @Override + public boolean earlyEOF() + { + _request.getHttpInput().shutdownInput(); + return false; + } - @Override - public boolean earlyEOF() - { - _request.getHttpInput().shutdownInput(); - return false; - } - - @Override - public void badMessage(int status, String reason) - { - if (status < 400 || status > 599) - status = HttpStatus.BAD_REQUEST_400; - _response.sendError(status, null, null); - } + @Override + public void badMessage(int status, String reason) + { + if (status < 400 || status > 599) + status = HttpStatus.BAD_REQUEST_400; + _response.sendError(status, null, null); + } + // TODO: port the logic present in this method + /* @Override public ResponseInfo commit() { @@ -744,13 +726,7 @@ public class HttpChannel } return _response.commit(); } - - @Override - public String toString() - { - return "CEH:" + HttpChannel.this.getEndPoint().toString(); - } - } + */ protected boolean commitResponse(ResponseInfo info, ByteBuffer content, boolean complete) throws IOException { @@ -788,23 +764,6 @@ public class HttpChannel } } - public Connector getConnector() - { - return _connector; - } - - public HttpConfiguration getHttpConfiguration() - { - return _configuration; - } - -// protected abstract void flush(ByteBuffer content, boolean last) throws IOException; - -// protected abstract FutureCallback write(ResponseInfo info, ByteBuffer content) throws IOException; - -// protected abstract void completed(); - - // TODO: remove protected void execute(Runnable task) { _connector.getExecutor().execute(task); @@ -815,9 +774,4 @@ public class HttpChannel { return _connector.getScheduler(); } - - public interface EventHandler extends HttpParser.RequestHandler - { - ResponseInfo commit(); - } } 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 b03907499a7..1301c22ba91 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 @@ -20,119 +20,81 @@ package org.eclipse.jetty.server; import java.io.IOException; import java.nio.ByteBuffer; -import java.util.concurrent.ExecutionException; import java.util.concurrent.RejectedExecutionException; -import java.util.concurrent.ScheduledExecutorService; import org.eclipse.jetty.http.HttpGenerator; -import org.eclipse.jetty.http.HttpGenerator.ResponseInfo; import org.eclipse.jetty.http.HttpParser; import org.eclipse.jetty.http.HttpStatus; import org.eclipse.jetty.io.AbstractConnection; import org.eclipse.jetty.io.ByteBufferPool; import org.eclipse.jetty.io.Connection; import org.eclipse.jetty.io.EndPoint; -import org.eclipse.jetty.io.EofException; import org.eclipse.jetty.util.BufferUtil; -import org.eclipse.jetty.util.FutureCallback; import org.eclipse.jetty.util.log.Log; import org.eclipse.jetty.util.log.Logger; /** - * A Connection that handles the HTTP protocol + *

A {@link Connection} that handles the HTTP protocol.

*/ public class HttpConnection extends AbstractConnection { - private static final Logger LOG = Log.getLogger(HttpConnection.class); - - private static final ThreadLocal __currentConnection = new ThreadLocal<>(); - private static final FutureCallback __completed = new FutureCallback<>(); - static - { - __completed.completed(null); - } - public static final String UPGRADE_CONNECTION_ATTRIBUTE = "org.eclispe.jetty.server.HttpConnection.UPGRADE"; - + private static final Logger LOG = Log.getLogger(HttpConnection.class); + private static final ThreadLocal __currentConnection = new ThreadLocal<>(); private final Server _server; - private final HttpConfiguration _httpConfig; + private final HttpConfiguration _configuration; private final Connector _connector; private final HttpParser _parser; private final HttpGenerator _generator; private final HttpChannel _channel; private final ByteBufferPool _bufferPool; - private ResponseInfo _info; - private ByteBuffer _requestBuffer=null; - private ByteBuffer _chunk=null; + private ByteBuffer _requestBuffer = null; private int _headerBytes; - /* ------------------------------------------------------------ */ public static HttpConnection getCurrentConnection() { return __currentConnection.get(); } - /* ------------------------------------------------------------ */ protected static void setCurrentConnection(HttpConnection connection) { __currentConnection.set(connection); } - /* ------------------------------------------------------------ */ public HttpConnection(HttpConfiguration config, Connector connector, EndPoint endPoint) { - super(endPoint,connector.getExecutor()); + super(endPoint, connector.getExecutor()); - _httpConfig=config; + _configuration = config; _connector = connector; - _bufferPool=_connector.getByteBufferPool(); + _bufferPool = _connector.getByteBufferPool(); _server = connector.getServer(); - _channel = new HttpChannel(connector, config, endPoint, new HttpTransportOverHttp(_bufferPool, _httpConfig, endPoint)); - _parser = new HttpParser(_channel.getEventHandler()); + _channel = new HttpChannel(connector, config, endPoint, new HttpTransportOverHttp(_bufferPool, _configuration, endPoint)); + _parser = new HttpParser(_channel); _generator = new HttpGenerator(); _generator.setSendServerVersion(_server.getSendServerVersion()); - LOG.debug("New HTTP Connection {}",this); + LOG.debug("New HTTP Connection {}", this); } - /* ------------------------------------------------------------ */ - /** - * @return the parser used by this connection - */ - public HttpParser getParser() - { - return _parser; - } - - - /* ------------------------------------------------------------ */ public Server getServer() { return _server; } - /* ------------------------------------------------------------ */ - /** - * @return Returns the connector. - */ public Connector getConnector() { return _connector; } - /* ------------------------------------------------------------ */ - /** - * @return Returns the HttpChannel. - */ public HttpChannel getHttpChannel() { return _channel; } - /* ------------------------------------------------------------ */ public void reset() { if (_generator.isPersistent()) @@ -143,21 +105,8 @@ public class HttpConnection extends AbstractConnection _generator.reset(); _channel.reset(); releaseRequestBuffer(); - if (_chunk!=null) - _bufferPool.release(_chunk); - _chunk=null; - _info=null; } - - /* ------------------------------------------------------------ */ - public HttpGenerator getGenerator() - { - return _generator; - } - - - /* ------------------------------------------------------------ */ @Override public String toString() { @@ -167,60 +116,52 @@ public class HttpConnection extends AbstractConnection _parser); } - /* ------------------------------------------------------------ */ private void releaseRequestBuffer() { - if (_requestBuffer!=null && !_requestBuffer.hasRemaining()) + if (_requestBuffer != null && !_requestBuffer.hasRemaining()) { _bufferPool.release(_requestBuffer); - _requestBuffer=null; + _requestBuffer = null; } } - /* ------------------------------------------------------------ */ - /** Parse and handle HTTP messages. - *

- * This method is normally called as the {@link AbstractConnection} onReadable callback. - * However, it can also be called {@link HttpChannelOverHttp#completed()} if there is unconsumed - * data in the _requestBuffer, as a result of resuming a suspended request when there is a pipelined - * request already read into the buffer. - *

- * This method will fill data and parse it until either: EOF is filled; 0 bytes are filled; - * the HttpChannel becomes !idle; or the connection has been changed + /** + *

Parses and handles HTTP messages.

+ *

This method is called when this {@link Connection} is ready to read bytes from the {@link EndPoint}. + * However, it can also be called if there is unconsumed data in the _requestBuffer, as a result of + * resuming a suspended request when there is a pipelined request already read into the buffer.

+ *

This method fills bytes and parses them until either: EOF is filled; 0 bytes are filled; + * the HttpChannel finishes handling; or the connection has changed.

*/ @Override public void onFillable() { - LOG.debug("{} onReadable {}",this,_channel.isIdle()); - - int filled=-2; + LOG.debug("{} onReadable {}", this, _channel.getState()); + setCurrentConnection(this); try { - setCurrentConnection(this); - - // TODO try to generalize this loop into AbstractConnection while (true) { // Fill the request buffer with data only if it is totally empty. if (BufferUtil.isEmpty(_requestBuffer)) { - if (_requestBuffer==null) - _requestBuffer=_bufferPool.acquire(_httpConfig.getRequestHeaderSize(),false); // TODO may acquire on speculative read. probably released to early + if (_requestBuffer == null) + _requestBuffer = _bufferPool.acquire(_configuration.getRequestHeaderSize(), false); - filled=getEndPoint().fill(_requestBuffer); + int filled = getEndPoint().fill(_requestBuffer); - LOG.debug("{} filled {}",this,filled); + LOG.debug("{} filled {}", this, filled); // If we failed to fill - if (filled==0) + if (filled == 0) { // Somebody wanted to read, we didn't so schedule another attempt releaseRequestBuffer(); fillInterested(); return; } - else if (filled<0) + else if (filled < 0) { _parser.inputShutdown(); // We were only filling if fully consumed, so if we have @@ -237,7 +178,7 @@ public class HttpConnection extends AbstractConnection } else { - _headerBytes+=filled; + _headerBytes += filled; } } @@ -245,7 +186,7 @@ public class HttpConnection extends AbstractConnection if (_parser.parseNext(_requestBuffer)) { // reset header count - _headerBytes=0; + _headerBytes = 0; // For most requests, there will not be a body, so we can try to recycle the buffer now releaseRequestBuffer(); @@ -256,7 +197,7 @@ public class HttpConnection extends AbstractConnection // The parser returned true, which indicates the channel is ready to handle a request. // Call the channel and this will either handle the request/response to completion OR, // if the request suspends, the request/response will be incomplete so the outer loop will exit. - boolean complete = _channel.handle(); + boolean complete = _channel.handle(); // TODO: should we perform special processing if we are complete ? // Handle connection upgrades if (_channel.getResponse().getStatus() == HttpStatus.SWITCHING_PROTOCOLS_101) @@ -330,10 +271,10 @@ public class HttpConnection extends AbstractConnection } // return if the connection has been changed - if (getEndPoint().getConnection()!=this) + if (getEndPoint().getConnection() != this) return; } - else if (_headerBytes>= _httpConfig.getRequestHeaderSize()) + else if (_headerBytes >= _configuration.getRequestHeaderSize()) { _parser.reset(); _parser.close(); @@ -342,17 +283,17 @@ public class HttpConnection extends AbstractConnection } } } - catch(IOException e) + catch (IOException e) { if (_parser.isIdle()) LOG.debug(e); else - LOG.warn(this.toString(),e); + LOG.warn(this.toString(), e); getEndPoint().close(); } - catch(Exception e) + catch (Exception e) { - LOG.warn(this.toString(),e); + LOG.warn(this.toString(), e); getEndPoint().close(); } finally @@ -361,471 +302,10 @@ public class HttpConnection extends AbstractConnection } } - /* ------------------------------------------------------------ */ @Override public void onOpen() { super.onOpen(); fillInterested(); } - - /* ------------------------------------------------------------ */ - @Override - public void onClose() - { - super.onClose(); - _channel.onClose(); - } - - - /* ------------------------------------------------------------ */ - /* ------------------------------------------------------------ */ - /* ------------------------------------------------------------ */ - private class HttpChannelOverHttp extends HttpChannel implements Runnable - { - private HttpChannelOverHttp(Server server) - { - super(_connector, _httpConfig, HttpConnection.this.getEndPoint(), new HttpTransportOverHttp(_bufferPool, _httpConfig, HttpConnection.this.getEndPoint())); - } - - public Connector getConnector() - { - return _connector; - } - - public HttpConfiguration getHttpConfiguration() - { - return _httpConfig; - } - -// @Override - protected boolean commitError(int status, String reason, String content) - { -// if (!super.commitError(status,reason,content)) - { - // TODO - should this just be a close and we don't worry about a RST overtaking a flushed response? - - // We could not send the error, so a shutdown of the connection will at least tell - // the client something is wrong - getEndPoint().shutdownOutput(); - _generator.abort(); -// return false; - } - return true; - } - - @Override - protected void completed() - { - // This is called by HttpChannel#handle when it knows that it's handling of the request/response cycle - // is complete. This may be in the original thread dispatched to the connection that has called process from - // the connection#onFillable method, or it may be from a thread dispatched to call process as the result - // of a resumed suspended request. - // At this point the HttpChannel will have completed the generation of any response (although it might remain to - // be asynchronously flushed TBD), but it may not have consumed the entire - - LOG.debug("{} completed"); - - // Handle connection upgrades - if (getResponse().getStatus()==HttpStatus.SWITCHING_PROTOCOLS_101) - { - Connection connection=(Connection)getRequest().getAttribute(UPGRADE_CONNECTION_ATTRIBUTE); - if (connection!=null) - { - LOG.debug("Upgrade from {} to {}",this,connection); - getEndPoint().setConnection(connection); - HttpConnection.this.reset(); - return; - } - } - - - // Reset everything for the next cycle. - HttpConnection.this.reset(); - - // are called from non connection thread (ie dispatched from a resume) - if (getCurrentConnection()!=HttpConnection.this) - { - if (_parser.isStart()) - { - // it wants to eat more - if (_requestBuffer==null) - fillInterested(); - else if (getConnector().isStarted()) - { - LOG.debug("{} pipelined",this); - - try - { - execute(this); - } - catch(RejectedExecutionException e) - { - if (getConnector().isStarted()) - LOG.warn(e); - else - LOG.ignore(e); - getEndPoint().close(); - } - } - else - getEndPoint().close(); - } - - if (_parser.isClosed()&&!getEndPoint().isOutputShutdown()) - { - // TODO This is a catch all indicating some protocol handling failure - // Currently needed for requests saying they are HTTP/2.0. - // This should be removed once better error handling is in place - LOG.warn("Endpoint output not shutdown when seeking EOF"); - getEndPoint().shutdownOutput(); - } - } - - // make sure that an oshut connection is driven towards close - // TODO this is a little ugly - if (getEndPoint().isOpen() && getEndPoint().isOutputShutdown()) - { - fillInterested(); - } - } - - /* ------------------------------------------------------------ */ - @Override - public void run() - { - onFillable(); - } - - /* ------------------------------------------------------------ */ -// @Override - public void flush(ByteBuffer content, boolean last) throws IOException - { - // Only one response writer at a time. - synchronized(this) - { - ByteBuffer header=null; - try - { - if (_generator.isEnd()) - { - // TODO do we need this escape? - if (last && BufferUtil.isEmpty(content)) - return; - throw new EofException(); - } - - loop: while (true) - { - HttpGenerator.Result result=_generator.generateResponse(_info,header,content,last); - if (LOG.isDebugEnabled()) - LOG.debug("{} generate: {} ({},{},{})@{}", - this, - result, - BufferUtil.toSummaryString(header), - BufferUtil.toSummaryString(content), - last, - _generator.getState()); - - switch(result) - { - case NEED_INFO: - if (_info==null) - _info=_channel.getEventHandler().commit(); - continue; - - case NEED_HEADER: - if (header!=null) - _bufferPool.release(header); - header=_bufferPool.acquire(_httpConfig.getResponseHeaderSize(),false); - continue; - - case NEED_CHUNK: - if (header!=null) - _bufferPool.release(header); - header=_bufferPool.acquire(HttpGenerator.CHUNK_SIZE,false); - continue; - - case FLUSH: - if (_info.isHead()) - { - write(header,null).get(); - BufferUtil.clear(content); - } - else - write(header,content).get(); - - continue; - - case SHUTDOWN_OUT: - getEndPoint().shutdownOutput(); - continue; - - case DONE: - break loop; - } - } - } - catch(InterruptedException e) - { - LOG.debug(e); - } - catch(ExecutionException e) - { - LOG.debug(e); - if (e.getCause() instanceof IOException) - throw (IOException)e.getCause(); - throw new RuntimeException(e); - } - finally - { - if (header!=null) - _bufferPool.release(header); - } - } - } - -// @Override - protected FutureCallback write(ResponseInfo info, ByteBuffer content) throws IOException - { - // Only one response writer at a time. - synchronized(this) - { - ByteBuffer header=null; - try - { - if (_generator.isEnd()) - throw new EofException(); - - FutureCallback fcb=null; - - loop: while (true) - { - HttpGenerator.Result result=_generator.generateResponse(info,header,content,true); - if (LOG.isDebugEnabled()) - LOG.debug("{} send: {} ({},{})@{}", - this, - result, - BufferUtil.toSummaryString(header), - BufferUtil.toSummaryString(content), - _generator.getState()); - - switch(result) - { - case NEED_INFO: - throw new IllegalStateException(); - - case NEED_HEADER: - if (header!=null) - _bufferPool.release(header); - header=_bufferPool.acquire(_httpConfig.getResponseHeaderSize(),false); - continue; - - case NEED_CHUNK: - if (header!=null) - _bufferPool.release(header); - header=_bufferPool.acquire(HttpGenerator.CHUNK_SIZE,false); - continue; - - case FLUSH: - if(info.isHead()) - { - BufferUtil.clear(content); - fcb=write(header,null); - } - else - fcb=write(header,content); - continue; - - case SHUTDOWN_OUT: - getEndPoint().shutdownOutput(); - continue; - - case DONE: - if (fcb==null) - fcb=__completed; - break loop; - } - } - return fcb; - } - finally - { - if (header!=null) - _bufferPool.release(header); - } - } - } - - @Override - public ScheduledExecutorService getScheduler() - { - return _connector.getScheduler(); - } - - @Override - protected void execute(Runnable task) - { - _connector.getExecutor().execute(task); - } - - private FutureCallback write(ByteBuffer b0,ByteBuffer b1) - { - FutureCallback fcb=new FutureCallback<>(); - if (BufferUtil.hasContent(b0)) - { - if (BufferUtil.hasContent(b1)) - { - getEndPoint().write(null,fcb,b0,b1); - } - else - { - getEndPoint().write(null,fcb,b0); - } - } - else - { - if (BufferUtil.hasContent(b1)) - { - getEndPoint().write(null,fcb,b1); - } - else - { - fcb.completed(null); - } - } - return fcb; - } - - } - - private class HttpHttpInput extends HttpInput - { - @Override - protected void blockForContent() throws IOException - { - /* We extend the blockForContent method to replace the - default implementation of a blocking queue with an implementation - that uses the calling thread to block on a readable callback and - then to do the parsing before before attempting the read. - */ - - // While progress and the connection has not changed - boolean parsed_event=_parser.parseNext(_requestBuffer==null?BufferUtil.EMPTY_BUFFER:_requestBuffer); - while (!parsed_event && !getEndPoint().isInputShutdown()) - { - try - { - // Do we have content ready to parse? - if (BufferUtil.isEmpty(_requestBuffer)) - { - // Wait until we can read - FutureCallback block=new FutureCallback<>(); - getEndPoint().fillInterested(null,block); - LOG.debug("{} block readable on {}",this,block); - block.get(); - - // We will need a buffer to read into - if (_requestBuffer==null) - _requestBuffer=_bufferPool.acquire(_httpConfig.getRequestBufferSize(),false); - - int filled=getEndPoint().fill(_requestBuffer); - LOG.debug("{} block filled {}",this,filled); - if (filled<0) - _parser.inputShutdown(); - } - - // If we parse to an event, return - while (BufferUtil.hasContent(_requestBuffer) && _parser.inContentState()) - parsed_event|=_parser.parseNext(_requestBuffer); - if (parsed_event) - return; - } - catch (InterruptedException e) - { - LOG.debug(e); - } - catch (ExecutionException e) - { - LOG.debug(e); - FutureCallback.rethrow(e); - } - } - } - - @Override - public int available() - { - int available=super.available(); - if (available==0 && _parser.isInContent() && BufferUtil.hasContent(_requestBuffer)) - return 1; - return available; - } - - @Override - public void consumeAll() - { - // Consume content only if the connection is persistent - if (!_generator.isPersistent()) - { - _parser.setState(HttpParser.State.CLOSED); - synchronized (lock()) - { - _inputQ.clear(); - } - } - else - { - while (true) - { - synchronized (lock()) - { - _inputQ.clear(); - } - if (_parser.isComplete() || _parser.isClosed()) - return; - try - { - blockForContent(); - } - catch(IOException e) - { - LOG.warn(e); - } - } - } - } - - - @Override - protected void onContentQueued(ByteBuffer ref) - { - /* This callback could be used to tell the connection - * that the request did contain content and thus the request - * buffer needs to be held until a call to #onAllContentConsumed - * - * However it turns out that nothing is needed here because either a - * request will have content, in which case the request buffer will be - * released by a call to onAllContentConsumed; or it will not have content. - * If it does not have content, either it will complete quickly and the - * buffers will be released in completed() or it will be suspended and - * onReadable() contains explicit handling to release if it is suspended. - * - * We extend this method anyway, to turn off the notify done by the - * default implementation as this is not needed by our implementation - * of blockForContent - */ - } - - - @Override - protected void onAllContentConsumed() - { - /* This callback tells the connection that all content that has - * been parsed has been consumed. Thus the request buffer may be - * released if it is empty. - */ - releaseRequestBuffer(); - } - } } diff --git a/jetty-server/src/main/java/org/eclipse/jetty/server/Response.java b/jetty-server/src/main/java/org/eclipse/jetty/server/Response.java index 19d9696fe9f..9ffe60307d4 100644 --- a/jetty-server/src/main/java/org/eclipse/jetty/server/Response.java +++ b/jetty-server/src/main/java/org/eclipse/jetty/server/Response.java @@ -24,7 +24,6 @@ import java.nio.channels.IllegalSelectorException; import java.util.Collection; import java.util.Collections; import java.util.Locale; -import java.util.concurrent.atomic.AtomicBoolean; import java.util.concurrent.atomic.AtomicInteger; import javax.servlet.ServletOutputStream; import javax.servlet.http.Cookie; @@ -47,10 +46,8 @@ import org.eclipse.jetty.util.URIUtil; import org.eclipse.jetty.util.log.Log; import org.eclipse.jetty.util.log.Logger; -/** Response. - *

- * Implements {@link javax.servlet.http.HttpServletResponse} from the javax.servlet.http package. - *

+/** + *

{@link Response} provides the implementation for {@link HttpServletResponse}.

*/ public class Response implements HttpServletResponse { @@ -58,7 +55,7 @@ public class Response implements HttpServletResponse public enum OutputType { - NONE,STREAM,WRITER + NONE, STREAM, WRITER } /** @@ -72,14 +69,13 @@ public class Response implements HttpServletResponse * If this string is found within the comment of a cookie added with {@link #addCookie(Cookie)}, then the cookie * will be set as HTTP ONLY. */ - public final static String HTTP_ONLY_COMMENT="__HTTP_ONLY__"; + public final static String HTTP_ONLY_COMMENT = "__HTTP_ONLY__"; private final HttpChannel _channel; private final HttpOutput _out; - private final HttpFields _fields=new HttpFields(); - private final AtomicBoolean _committed = new AtomicBoolean(false); + private final HttpFields _fields = new HttpFields(); private final AtomicInteger _include = new AtomicInteger(); - private int _status=HttpStatus.NOT_SET_000; + private int _status = HttpStatus.NOT_SET_000; private String _reason; private Locale _locale; private MimeTypes.Type _mimeType; @@ -87,97 +83,75 @@ public class Response implements HttpServletResponse private String _contentType; private OutputType _outputType = OutputType.NONE; private PrintWriter _writer; - private long _contentLength=-1; + private long _contentLength = -1; - /* ------------------------------------------------------------ */ - /** - * - */ public Response(HttpChannel channel, HttpOutput out) { - _channel=channel; - _out=out; + _channel = channel; + _out = out; } - /* ------------------------------------------------------------ */ - public HttpChannel getHttpChannel() + protected HttpChannel getHttpChannel() { return _channel; } - /* ------------------------------------------------------------ */ - /* - * @see javax.servlet.ServletResponse#reset() - */ protected void recycle() { - _status=HttpStatus.NOT_SET_000; - _reason=null; - _locale=null; - _mimeType=null; - _characterEncoding=null; - _contentType=null; - _writer=null; + _status = HttpStatus.NOT_SET_000; + _reason = null; + _locale = null; + _mimeType = null; + _characterEncoding = null; + _contentType = null; + _writer = null; _outputType = OutputType.NONE; - _contentLength=-1; - _committed.set(false); + _contentLength = -1; _out.reset(); _fields.clear(); } - /* ------------------------------------------------------------ */ public HttpOutput getHttpOutput() { return _out; } - /* ------------------------------------------------------------ */ public boolean isIncluding() { - return _include.get()>0; + return _include.get() > 0; } - /* ------------------------------------------------------------ */ public void include() { _include.incrementAndGet(); } - /* ------------------------------------------------------------ */ public void included() { _include.decrementAndGet(); _out.reopen(); } - /* ------------------------------------------------------------ */ - /* - * @see javax.servlet.http.HttpServletResponse#addCookie(javax.servlet.http.Cookie) - */ public void addCookie(HttpCookie cookie) { _fields.addSetCookie(cookie); } - /* ------------------------------------------------------------ */ - /* - * @see javax.servlet.http.HttpServletResponse#addCookie(javax.servlet.http.Cookie) - */ @Override public void addCookie(Cookie cookie) { - String comment=cookie.getComment(); - boolean http_only=false; + String comment = cookie.getComment(); + boolean httpOnly = false; - if (comment!=null) + if (comment != null) { - int i=comment.indexOf(HTTP_ONLY_COMMENT); - if (i>=0) + int i = comment.indexOf(HTTP_ONLY_COMMENT); + if (i >= 0) { - http_only=true; - comment=comment.replace(HTTP_ONLY_COMMENT,"").trim(); - if (comment.length()==0) - comment=null; + httpOnly = true; + comment = comment.replace(HTTP_ONLY_COMMENT, "").trim(); + if (comment.length() == 0) + comment = null; } } _fields.addSetCookie(cookie.getName(), @@ -187,30 +161,22 @@ public class Response implements HttpServletResponse cookie.getMaxAge(), comment, cookie.getSecure(), - http_only || cookie.isHttpOnly(), + httpOnly || cookie.isHttpOnly(), cookie.getVersion()); } - /* ------------------------------------------------------------ */ - /* - * @see javax.servlet.http.HttpServletResponse#containsHeader(java.lang.String) - */ @Override public boolean containsHeader(String name) { return _fields.containsKey(name); } - /* ------------------------------------------------------------ */ - /* - * @see javax.servlet.http.HttpServletResponse#encodeURL(java.lang.String) - */ @Override public String encodeURL(String url) { - final Request request=_channel.getRequest(); + final Request request = _channel.getRequest(); SessionManager sessionManager = request.getSessionManager(); - if (sessionManager==null) + if (sessionManager == null) return url; HttpURI uri = null; @@ -218,42 +184,42 @@ public class Response implements HttpServletResponse { uri = new HttpURI(url); String path = uri.getPath(); - path = (path == null?"":path); - int port=uri.getPort(); - if (port<0) - port = HttpScheme.HTTPS.asString().equalsIgnoreCase(uri.getScheme())?443:80; + path = (path == null ? "" : path); + int port = uri.getPort(); + if (port < 0) + port = HttpScheme.HTTPS.asString().equalsIgnoreCase(uri.getScheme()) ? 443 : 80; if (!request.getServerName().equalsIgnoreCase(uri.getHost()) || - request.getServerPort()!=port || - !path.startsWith(request.getContextPath())) //TODO the root context path is "", with which every non null string starts + request.getServerPort() != port || + !path.startsWith(request.getContextPath())) //TODO the root context path is "", with which every non null string starts return url; } String sessionURLPrefix = sessionManager.getSessionIdPathParameterNamePrefix(); - if (sessionURLPrefix==null) + if (sessionURLPrefix == null) return url; - if (url==null) + if (url == null) return null; // should not encode if cookies in evidence if (request.isRequestedSessionIdFromCookie()) { - int prefix=url.indexOf(sessionURLPrefix); - if (prefix!=-1) + int prefix = url.indexOf(sessionURLPrefix); + if (prefix != -1) { - int suffix=url.indexOf("?",prefix); - if (suffix<0) - suffix=url.indexOf("#",prefix); + int suffix = url.indexOf("?", prefix); + if (suffix < 0) + suffix = url.indexOf("#", prefix); - if (suffix<=prefix) - return url.substring(0,prefix); - return url.substring(0,prefix)+url.substring(suffix); + if (suffix <= prefix) + return url.substring(0, prefix); + return url.substring(0, prefix) + url.substring(suffix); } return url; } // get session; - HttpSession session=request.getSession(false); + HttpSession session = request.getSession(false); // no session if (session == null) @@ -263,54 +229,49 @@ public class Response implements HttpServletResponse if (!sessionManager.isValid(session)) return url; - String id=sessionManager.getNodeId(session); + String id = sessionManager.getNodeId(session); if (uri == null) - uri = new HttpURI(url); + uri = new HttpURI(url); // Already encoded - int prefix=url.indexOf(sessionURLPrefix); - if (prefix!=-1) + int prefix = url.indexOf(sessionURLPrefix); + if (prefix != -1) { - int suffix=url.indexOf("?",prefix); - if (suffix<0) - suffix=url.indexOf("#",prefix); + int suffix = url.indexOf("?", prefix); + if (suffix < 0) + suffix = url.indexOf("#", prefix); - if (suffix<=prefix) - return url.substring(0,prefix+sessionURLPrefix.length())+id; - return url.substring(0,prefix+sessionURLPrefix.length())+id+ - url.substring(suffix); + if (suffix <= prefix) + return url.substring(0, prefix + sessionURLPrefix.length()) + id; + return url.substring(0, prefix + sessionURLPrefix.length()) + id + + url.substring(suffix); } // edit the session - int suffix=url.indexOf('?'); - if (suffix<0) - suffix=url.indexOf('#'); - if (suffix<0) + int suffix = url.indexOf('?'); + if (suffix < 0) + suffix = url.indexOf('#'); + if (suffix < 0) { - return url+ - ((HttpScheme.HTTPS.is(uri.getScheme()) || HttpScheme.HTTP.is(uri.getScheme())) && uri.getPath()==null?"/":"") + //if no path, insert the root path - sessionURLPrefix+id; + return url + + ((HttpScheme.HTTPS.is(uri.getScheme()) || HttpScheme.HTTP.is(uri.getScheme())) && uri.getPath() == null ? "/" : "") + //if no path, insert the root path + sessionURLPrefix + id; } - return url.substring(0,suffix)+ - ((HttpScheme.HTTPS.is(uri.getScheme()) || HttpScheme.HTTP.is(uri.getScheme())) && uri.getPath()==null?"/":"")+ //if no path so insert the root path - sessionURLPrefix+id+url.substring(suffix); + return url.substring(0, suffix) + + ((HttpScheme.HTTPS.is(uri.getScheme()) || HttpScheme.HTTP.is(uri.getScheme())) && uri.getPath() == null ? "/" : "") + //if no path so insert the root path + sessionURLPrefix + id + url.substring(suffix); } - /* ------------------------------------------------------------ */ - /** - * @see javax.servlet.http.HttpServletResponse#encodeRedirectURL(java.lang.String) - */ @Override public String encodeRedirectURL(String url) { return encodeURL(url); } - /* ------------------------------------------------------------ */ @Override @Deprecated public String encodeUrl(String url) @@ -318,7 +279,6 @@ public class Response implements HttpServletResponse return encodeURL(url); } - /* ------------------------------------------------------------ */ @Override @Deprecated public String encodeRedirectUrl(String url) @@ -326,10 +286,15 @@ public class Response implements HttpServletResponse return encodeRedirectURL(url); } - /* ------------------------------------------------------------ */ - /* - * @see javax.servlet.http.HttpServletResponse#sendError(int, java.lang.String) - */ + @Override + public void sendError(int sc) throws IOException + { + if (sc == 102) + sendProcessing(); + else + sendError(sc, null); + } + @Override public void sendError(int code, String message) throws IOException { @@ -364,21 +329,8 @@ public class Response implements HttpServletResponse _channel.sendError(newResponseInfo(), content); } - /* ------------------------------------------------------------ */ - /* - * @see javax.servlet.http.HttpServletResponse#sendError(int) - */ - @Override - public void sendError(int sc) throws IOException - { - if (sc==102) - sendProcessing(); - else - sendError(sc,null); - } - - /* ------------------------------------------------------------ */ - /* Send a 102-Processing response. + /** + * Sends a 102-Processing response. * If the connection is a HTTP connection, the version is 1.1 and the * request has a Expect header starting with 102, then a 102 response is * sent. This indicates that the request still be processed and real response @@ -393,17 +345,13 @@ public class Response implements HttpServletResponse } } - /* ------------------------------------------------------------ */ - /* - * @see javax.servlet.http.HttpServletResponse#sendRedirect(java.lang.String) - */ @Override public void sendRedirect(String location) throws IOException { - if (isIncluding()) - return; + if (isIncluding()) + return; - if (location==null) + if (location == null) throw new IllegalArgumentException(); if (!URIUtil.hasScheme(location)) @@ -413,51 +361,46 @@ public class Response implements HttpServletResponse buf.append(location); else { - String path=_channel.getRequest().getRequestURI(); - String parent=(path.endsWith("/"))?path:URIUtil.parentPath(path); - location=URIUtil.addPaths(parent,location); - if(location==null) + String path = _channel.getRequest().getRequestURI(); + String parent = (path.endsWith("/")) ? path : URIUtil.parentPath(path); + location = URIUtil.addPaths(parent, location); + if (location == null) throw new IllegalStateException("path cannot be above root"); if (!location.startsWith("/")) buf.append('/'); buf.append(location); } - location=buf.toString(); + location = buf.toString(); HttpURI uri = new HttpURI(location); - String path=uri.getDecodedPath(); - String canonical=URIUtil.canonicalPath(path); - if (canonical==null) + String path = uri.getDecodedPath(); + String canonical = URIUtil.canonicalPath(path); + if (canonical == null) throw new IllegalArgumentException(); if (!canonical.equals(path)) { buf = _channel.getRequest().getRootURL(); buf.append(URIUtil.encodePath(canonical)); - if (uri.getQuery()!=null) + if (uri.getQuery() != null) { buf.append('?'); buf.append(uri.getQuery()); } - if (uri.getFragment()!=null) + if (uri.getFragment() != null) { buf.append('#'); buf.append(uri.getFragment()); } - location=buf.toString(); + location = buf.toString(); } } resetBuffer(); - setHeader(HttpHeader.LOCATION,location); + setHeader(HttpHeader.LOCATION, location); setStatus(HttpServletResponse.SC_MOVED_TEMPORARILY); complete(); - } - /* ------------------------------------------------------------ */ - /* - * @see javax.servlet.http.HttpServletResponse#setDateHeader(java.lang.String, long) - */ @Override public void setDateHeader(String name, long date) { @@ -465,10 +408,6 @@ public class Response implements HttpServletResponse _fields.putDateField(name, date); } - /* ------------------------------------------------------------ */ - /* - * @see javax.servlet.http.HttpServletResponse#addDateHeader(java.lang.String, long) - */ @Override public void addDateHeader(String name, long date) { @@ -476,10 +415,6 @@ public class Response implements HttpServletResponse _fields.addDateField(name, date); } - /* ------------------------------------------------------------ */ - /* - * @see javax.servlet.http.HttpServletResponse#setHeader(java.lang.String, java.lang.String) - */ public void setHeader(HttpHeader name, String value) { if (HttpHeader.CONTENT_TYPE == name) @@ -487,23 +422,20 @@ public class Response implements HttpServletResponse else { if (isIncluding()) - return; + return; _fields.put(name, value); - if (HttpHeader.CONTENT_LENGTH==name) + if (HttpHeader.CONTENT_LENGTH == name) { - if (value==null) - _contentLength=-1l; + if (value == null) + _contentLength = -1l; else - _contentLength=Long.parseLong(value); + _contentLength = Long.parseLong(value); } } } - /* ------------------------------------------------------------ */ - /* - * @see javax.servlet.http.HttpServletResponse#setHeader(java.lang.String, java.lang.String) - */ + @Override public void setHeader(String name, String value) { @@ -514,82 +446,51 @@ public class Response implements HttpServletResponse if (isIncluding()) { if (name.startsWith(SET_INCLUDE_HEADER_PREFIX)) - name=name.substring(SET_INCLUDE_HEADER_PREFIX.length()); + name = name.substring(SET_INCLUDE_HEADER_PREFIX.length()); else return; } _fields.put(name, value); if (HttpHeader.CONTENT_LENGTH.is(name)) { - if (value==null) - _contentLength=-1l; + if (value == null) + _contentLength = -1l; else - _contentLength=Long.parseLong(value); + _contentLength = Long.parseLong(value); } } } - - /* ------------------------------------------------------------ */ @Override public Collection getHeaderNames() { - final HttpFields fields=_fields; + final HttpFields fields = _fields; return fields.getFieldNamesCollection(); } - /* ------------------------------------------------------------ */ - /* - */ @Override public String getHeader(String name) { return _fields.getStringField(name); } - /* ------------------------------------------------------------ */ - /* - */ @Override public Collection getHeaders(String name) { - final HttpFields fields=_fields; + final HttpFields fields = _fields; Collection i = fields.getValuesCollection(name); - if (i==null) + if (i == null) return Collections.emptyList(); return i; } - /* ------------------------------------------------------------ */ - /* - * @see javax.servlet.http.HttpServletResponse#addHeader(java.lang.String, java.lang.String) - */ - public void addHeader(HttpHeader name, String value) - { - if (isIncluding()) - return; - - _fields.add(name, value); - if (HttpHeader.CONTENT_LENGTH==name) - { - if (value==null) - _contentLength=-1l; - else - _contentLength=Long.parseLong(value); - } - } - - /* ------------------------------------------------------------ */ - /* - * @see javax.servlet.http.HttpServletResponse#addHeader(java.lang.String, java.lang.String) - */ @Override public void addHeader(String name, String value) { if (isIncluding()) { if (name.startsWith(SET_INCLUDE_HEADER_PREFIX)) - name=name.substring(SET_INCLUDE_HEADER_PREFIX.length()); + name = name.substring(SET_INCLUDE_HEADER_PREFIX.length()); else return; } @@ -597,17 +498,13 @@ public class Response implements HttpServletResponse _fields.add(name, value); if (HttpHeader.CONTENT_LENGTH.is(name)) { - if (value==null) - _contentLength=-1l; + if (value == null) + _contentLength = -1l; else - _contentLength=Long.parseLong(value); + _contentLength = Long.parseLong(value); } } - /* ------------------------------------------------------------ */ - /* - * @see javax.servlet.http.HttpServletResponse#setIntHeader(java.lang.String, int) - */ @Override public void setIntHeader(String name, int value) { @@ -615,14 +512,10 @@ public class Response implements HttpServletResponse { _fields.putLongField(name, value); if (HttpHeader.CONTENT_LENGTH.is(name)) - _contentLength=value; + _contentLength = value; } } - /* ------------------------------------------------------------ */ - /* - * @see javax.servlet.http.HttpServletResponse#addIntHeader(java.lang.String, int) - */ @Override public void addIntHeader(String name, int value) { @@ -630,68 +523,43 @@ public class Response implements HttpServletResponse { _fields.add(name, Integer.toString(value)); if (HttpHeader.CONTENT_LENGTH.is(name)) - _contentLength=value; + _contentLength = value; } } - /* ------------------------------------------------------------ */ - /* - * @see javax.servlet.http.HttpServletResponse#setStatus(int) - */ @Override public void setStatus(int sc) { - setStatus(sc,null); + setStatus(sc, null); } - /* ------------------------------------------------------------ */ - /* - * @see javax.servlet.http.HttpServletResponse#setStatus(int, java.lang.String) - */ @Override + @Deprecated public void setStatus(int sc, String sm) { - if (sc<=0) + if (sc <= 0) throw new IllegalArgumentException(); if (!isIncluding()) { - _status=sc; - _reason=sm; + _status = sc; + _reason = sm; } } - /* ------------------------------------------------------------ */ - /* - * @see javax.servlet.ServletResponse#getCharacterEncoding() - */ @Override public String getCharacterEncoding() { - if (_characterEncoding==null) - _characterEncoding=StringUtil.__ISO_8859_1; + if (_characterEncoding == null) + _characterEncoding = StringUtil.__ISO_8859_1; return _characterEncoding; } - /* ------------------------------------------------------------ */ - String getSetCharacterEncoding() - { - return _characterEncoding; - } - - /* ------------------------------------------------------------ */ - /* - * @see javax.servlet.ServletResponse#getContentType() - */ @Override public String getContentType() { return _contentType; } - /* ------------------------------------------------------------ */ - /* - * @see javax.servlet.ServletResponse#getOutputStream() - */ @Override public ServletOutputStream getOutputStream() throws IOException { @@ -701,44 +569,31 @@ public class Response implements HttpServletResponse return _out; } - /* ------------------------------------------------------------ */ public boolean isWriting() { return _outputType == OutputType.WRITER; } - /* ------------------------------------------------------------ */ - public boolean isOutputing() - { - return _outputType != OutputType.NONE; - } - - /* ------------------------------------------------------------ */ - /* - * @see javax.servlet.ServletResponse#getWriter() - */ @Override public PrintWriter getWriter() throws IOException { if (_outputType == OutputType.STREAM) throw new IllegalStateException("STREAM"); + _outputType = OutputType.WRITER; - /* if there is no writer yet */ - if (_writer==null) + if (_writer == null) { /* get encoding from Content-Type header */ String encoding = _characterEncoding; - - if (encoding==null) + if (encoding == null) { - encoding=MimeTypes.inferCharsetFromContentType(_contentType); - if (encoding==null) + encoding = MimeTypes.inferCharsetFromContentType(_contentType); + if (encoding == null) encoding = StringUtil.__ISO_8859_1; - setCharacterEncoding(encoding); } - if (encoding == null || StringUtil.__ISO_8859_1.equalsIgnoreCase(encoding)) + if (StringUtil.__ISO_8859_1.equalsIgnoreCase(encoding)) { _writer = new PrintWriter(new Iso88591HttpWriter(_out)); } @@ -748,20 +603,12 @@ public class Response implements HttpServletResponse } else { - _writer = new PrintWriter(new EncodingHttpWriter(_out,encoding)); + _writer = new PrintWriter(new EncodingHttpWriter(_out, encoding)); } - } - _outputType = OutputType.WRITER; return _writer; } - - - /* ------------------------------------------------------------ */ - /* - * @see javax.servlet.ServletResponse#setContentLength(int) - */ @Override public void setContentLength(int len) { @@ -771,35 +618,33 @@ public class Response implements HttpServletResponse if (isCommitted() || isIncluding()) return; - long written=_out.getWritten(); - if (written>len) - throw new IllegalArgumentException("setContent("+len+") when already written "+written); + long written = _out.getWritten(); + if (written > len) + throw new IllegalArgumentException("setContent(" + len + ") when already written " + written); - _contentLength=len; + _contentLength = len; _fields.putLongField(HttpHeader.CONTENT_LENGTH.toString(), len); - if (_contentLength>0) + if (_contentLength > 0) checkAllContentWritten(written); } - /* ------------------------------------------------------------ */ public boolean checkAllContentWritten(long written) { - if (_contentLength>=0 && written>=_contentLength) + if (_contentLength >= 0 && written >= _contentLength) { try { - switch(_outputType) + switch (_outputType) { case WRITER: _writer.close(); break; case STREAM: getOutputStream().close(); - } } - catch(IOException e) + catch (IOException e) { throw new RuntimeException(e); } @@ -808,204 +653,172 @@ public class Response implements HttpServletResponse return false; } - /* ------------------------------------------------------------ */ public long getLongContentLength() { return _contentLength; } - /* ------------------------------------------------------------ */ - /* - * @see javax.servlet.ServletResponse#setContentLength(int) - */ public void setLongContentLength(long len) { // Protect from setting after committed as default handling // of a servlet HEAD request ALWAYS sets _content length, even // if the getHandling committed the response! if (isCommitted() || isIncluding()) - return; - _contentLength=len; + return; + _contentLength = len; _fields.putLongField(HttpHeader.CONTENT_LENGTH.toString(), len); } - /* ------------------------------------------------------------ */ - /* - * @see javax.servlet.ServletResponse#setCharacterEncoding(java.lang.String) - */ @Override public void setCharacterEncoding(String encoding) { if (isIncluding()) - return; + return; if (_outputType == OutputType.NONE && !isCommitted()) { - if (encoding==null) + if (encoding == null) { // Clear any encoding. - if (_characterEncoding!=null) + if (_characterEncoding != null) { - _characterEncoding=null; - if (_contentType!=null) + _characterEncoding = null; + if (_contentType != null) { - _contentType=MimeTypes.getContentTypeWithoutCharset(_contentType); - _fields.put(HttpHeader.CONTENT_TYPE,_contentType); + _contentType = MimeTypes.getContentTypeWithoutCharset(_contentType); + _fields.put(HttpHeader.CONTENT_TYPE, _contentType); } } } else { // No, so just add this one to the mimetype - _characterEncoding=StringUtil.normalizeCharset(encoding); - if (_contentType!=null) + _characterEncoding = StringUtil.normalizeCharset(encoding); + if (_contentType != null) { - _contentType=MimeTypes.getContentTypeWithoutCharset(_contentType)+";charset="+_characterEncoding; - _fields.put(HttpHeader.CONTENT_TYPE,_contentType); + _contentType = MimeTypes.getContentTypeWithoutCharset(_contentType) + ";charset=" + _characterEncoding; + _fields.put(HttpHeader.CONTENT_TYPE, _contentType); } } } - /* TODO merged code not used??? - else if (_mimeType!=null) - _contentType=_mimeType; +/* TODO merged code not used??? + else if (_mimeType!=null) + _contentType=_mimeType; - if (_contentType==null) - _connection.getResponseFields().remove(HttpHeaders.CONTENT_TYPE_BUFFER); - else - _connection.getResponseFields().put(HttpHeaders.CONTENT_TYPE_BUFFER,_contentType); + if (_contentType==null) + _connection.getResponseFields().remove(HttpHeaders.CONTENT_TYPE_BUFFER); + else + _connection.getResponseFields().put(HttpHeaders.CONTENT_TYPE_BUFFER,_contentType); */ - } + } - /* ------------------------------------------------------------ */ - /* - * @see javax.servlet.ServletResponse#setContentType(java.lang.String) - */ @Override public void setContentType(String contentType) { if (isCommitted() || isIncluding()) return; - if (contentType==null) + if (contentType == null) { - if (isWriting() && _characterEncoding!=null) + if (isWriting() && _characterEncoding != null) throw new IllegalSelectorException(); - if (_locale==null) - _characterEncoding=null; - _mimeType=null; - _contentType=null; + if (_locale == null) + _characterEncoding = null; + _mimeType = null; + _contentType = null; _fields.remove(HttpHeader.CONTENT_TYPE); } else { - _contentType=contentType; - _mimeType=MimeTypes.CACHE.get(contentType); + _contentType = contentType; + _mimeType = MimeTypes.CACHE.get(contentType); String charset; - if (_mimeType!=null && _mimeType.getCharset()!=null) - charset=_mimeType.getCharset().toString(); + if (_mimeType != null && _mimeType.getCharset() != null) + charset = _mimeType.getCharset().toString(); else - charset=MimeTypes.getCharsetFromContentType(contentType); + charset = MimeTypes.getCharsetFromContentType(contentType); - if (charset==null) + if (charset == null) { - if (_characterEncoding!=null) + if (_characterEncoding != null) { - _contentType=contentType+";charset="+_characterEncoding; - _mimeType=null; + _contentType = contentType + ";charset=" + _characterEncoding; + _mimeType = null; } } else if (isWriting() && !charset.equals(_characterEncoding)) { // too late to change the character encoding; - _mimeType=null; - _contentType=MimeTypes.getContentTypeWithoutCharset(_contentType); - if (_characterEncoding!=null) - _contentType=_contentType+";charset="+_characterEncoding; + _mimeType = null; + _contentType = MimeTypes.getContentTypeWithoutCharset(_contentType); + if (_characterEncoding != null) + _contentType = _contentType + ";charset=" + _characterEncoding; } else { - _characterEncoding=charset; + _characterEncoding = charset; } - _fields.put(HttpHeader.CONTENT_TYPE,_contentType); + _fields.put(HttpHeader.CONTENT_TYPE, _contentType); } } - /* ------------------------------------------------------------ */ - /* - * @see javax.servlet.ServletResponse#setBufferSize(int) - */ @Override public void setBufferSize(int size) { - if (isCommitted() || getContentCount()>0 ) + if (isCommitted() || getContentCount() > 0) throw new IllegalStateException("Committed or content written"); _out.setBufferSize(size); } - /* ------------------------------------------------------------ */ - /* - * @see javax.servlet.ServletResponse#getBufferSize() - */ @Override public int getBufferSize() { return _out.getBufferSize(); } - /* ------------------------------------------------------------ */ - /* - * @see javax.servlet.ServletResponse#flushBuffer() - */ @Override public void flushBuffer() throws IOException { _out.flush(); } - /* ------------------------------------------------------------ */ - /* - * @see javax.servlet.ServletResponse#reset() - */ @Override public void reset() { - resetBuffer(); - fwdReset(); - _status=200; - _reason=null; - _contentLength=-1; + resetForForward(); + _status = 200; + _reason = null; + _contentLength = -1; + _fields.clear(); - HttpFields response_fields=_fields; - - response_fields.clear(); - String connection=_channel.getRequest().getHttpFields().getStringField(HttpHeader.CONNECTION); - if (connection!=null) + String connection = _channel.getRequest().getHttpFields().getStringField(HttpHeader.CONNECTION); + if (connection != null) { String[] values = connection.split(","); - for (int i=0;values!=null && i0 && _characterEncoding==null) + if (charset != null && charset.length() > 0 && _characterEncoding == null) setCharacterEncoding(charset); } - /* ------------------------------------------------------------ */ - /* - * @see javax.servlet.ServletResponse#getLocale() - */ @Override public Locale getLocale() { - if (_locale==null) + if (_locale == null) return Locale.getDefault(); return _locale; } - /* ------------------------------------------------------------ */ - /** - * @return The HTTP status code that has been set for this request. This will be 200 - * ({@link HttpServletResponse#SC_OK}), unless explicitly set through one of the setStatus methods. - */ @Override public int getStatus() { return _status; } - /* ------------------------------------------------------------ */ - /** - * @return The reason associated with the current {@link #getStatus() status}. This will be null, - * unless one of the setStatus methods have been called. - */ public String getReason() { return _reason; } - /* ------------------------------------------------------------ */ - /** - */ - public void complete() - throws IOException + public void complete() throws IOException { _out.close(); } - /* ------------------------------------------------------------ */ public HttpFields getHttpFields() { return _fields; } - /* ------------------------------------------------------------ */ public long getContentCount() { return _out.getWritten(); } - /* ------------------------------------------------------------ */ @Override public String toString() { - return "HTTP/1.1 "+_status+" "+ (_reason==null?"":_reason) +System.getProperty("line.separator")+ - _fields.toString(); + return String.format("%s %d %s%n%s", _channel.getRequest().getHttpVersion(), _status, _reason == null ? "" : _reason, _fields); } } diff --git a/jetty-server/src/test/java/org/eclipse/jetty/server/HttpConnectionTest.java b/jetty-server/src/test/java/org/eclipse/jetty/server/HttpConnectionTest.java index fd1c5f8404b..e9ea5ced35e 100644 --- a/jetty-server/src/test/java/org/eclipse/jetty/server/HttpConnectionTest.java +++ b/jetty-server/src/test/java/org/eclipse/jetty/server/HttpConnectionTest.java @@ -24,16 +24,9 @@ */ package org.eclipse.jetty.server; -import static org.hamcrest.Matchers.greaterThan; -import static org.hamcrest.Matchers.startsWith; -import static org.junit.Assert.assertThat; -import static org.junit.Assert.assertTrue; -import static org.junit.Assert.fail; - import java.io.IOException; import java.io.PrintWriter; import java.util.concurrent.TimeUnit; - import javax.servlet.ServletException; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; @@ -50,6 +43,12 @@ import org.junit.Assert; import org.junit.Before; import org.junit.Test; +import static org.hamcrest.Matchers.greaterThan; +import static org.hamcrest.Matchers.startsWith; +import static org.junit.Assert.assertThat; +import static org.junit.Assert.assertTrue; +import static org.junit.Assert.fail; + /** * */ @@ -126,7 +125,7 @@ public class HttpConnectionTest System.err.println(response); } } - + @Test public void testNoPath() throws Exception { @@ -139,7 +138,7 @@ public class HttpConnectionTest offset = checkContains(response,offset,"HTTP/1.1 200"); checkContains(response,offset,"pathInfo=/"); } - + @Test public void testEmpty() throws Exception @@ -199,15 +198,15 @@ public class HttpConnectionTest "Connection: close\n"+ "\015\012"); checkContains(response,0,"HTTP/1.1 400"); - + response=connector.getResponses("GET /foo/bar%c0%00 HTTP/1.1\n"+ "Host: localhost\n"+ - "Connection: close\n"+ + "Connection: close\n"+ "\015\012"); checkContains(response,0,"HTTP/1.1 200"); //now fallback to iso-8859-1 response=connector.getResponses("GET /bad/utf8%c1 HTTP/1.1\n"+ - "Host: localhost\n"+ + "Host: localhost\n"+ "Connection: close\n"+ "\015\012"); checkContains(response,0,"HTTP/1.1 200"); //now fallback to iso-8859-1 @@ -360,10 +359,11 @@ public class HttpConnectionTest "\n"+ "abcdefghij\n"; + Logger logger = Log.getLogger(HttpChannel.class); try { - HttpChannel.LOG.info("EXPECTING: java.lang.IllegalStateException..."); - ((StdErrLog)Log.getLogger(HttpChannel.class)).setHideStacks(true); + logger.info("EXPECTING: java.lang.IllegalStateException..."); + ((StdErrLog)logger).setHideStacks(true); response=connector.getResponses(requests); offset = checkContains(response,offset,"HTTP/1.1 500"); offset = checkContains(response,offset,"Connection: close"); @@ -371,7 +371,7 @@ public class HttpConnectionTest } finally { - ((StdErrLog)Log.getLogger(HttpChannel.class)).setHideStacks(false); + ((StdErrLog)logger).setHideStacks(false); } }