diff --git a/jetty-io/src/main/java/org/eclipse/jetty/io/AbstractConnection.java b/jetty-io/src/main/java/org/eclipse/jetty/io/AbstractConnection.java index 2af19391128..dfcd9066273 100644 --- a/jetty-io/src/main/java/org/eclipse/jetty/io/AbstractConnection.java +++ b/jetty-io/src/main/java/org/eclipse/jetty/io/AbstractConnection.java @@ -40,7 +40,7 @@ import org.eclipse.jetty.util.thread.NonBlockingThread; public abstract class AbstractConnection implements Connection { private static final Logger LOG = Log.getLogger(AbstractConnection.class); - + public static final boolean EXECUTE_ONFILLABLE=true; private final List listeners = new CopyOnWriteArrayList<>(); @@ -56,7 +56,7 @@ public abstract class AbstractConnection implements Connection { this(endp,executor,EXECUTE_ONFILLABLE); } - + protected AbstractConnection(EndPoint endp, Executor executor, final boolean executeOnfillable) { if (executor == null) @@ -88,7 +88,7 @@ public abstract class AbstractConnection implements Connection { return _executor; } - + protected void failedCallback(final Callback callback, final Throwable x) { if (NonBlockingThread.isNonBlockingThread()) @@ -115,7 +115,7 @@ public abstract class AbstractConnection implements Connection callback.failed(x); } } - + /** *

Utility method to be called to register read interest.

*

After a call to this method, {@link #onFillable()} or {@link #onFillInterestedFailed(Throwable)} @@ -126,7 +126,7 @@ public abstract class AbstractConnection implements Connection { if (LOG.isDebugEnabled()) LOG.debug("fillInterested {}",this); - + while(true) { State state=_state.get(); @@ -134,7 +134,7 @@ public abstract class AbstractConnection implements Connection break; } } - + public void fillInterested(Callback callback) { if (LOG.isDebugEnabled()) @@ -151,7 +151,7 @@ public abstract class AbstractConnection implements Connection break; } } - + /** *

Callback method invoked when the endpoint is ready to be read.

* @see #fillInterested() @@ -181,7 +181,7 @@ public abstract class AbstractConnection implements Connection } if (_endPoint.isOpen()) - fillInterested(); + fillInterested(); } /** @@ -258,9 +258,13 @@ public abstract class AbstractConnection implements Connection @Override public String toString() { - return String.format("%s@%x{%s}", getClass().getSimpleName(), hashCode(), _state.get()); + return String.format("%s@%x[%s,%s]", + getClass().getSimpleName(), + hashCode(), + _state.get(), + _endPoint); } - + public boolean next(State state, State next) { if (next==null) @@ -275,7 +279,7 @@ public abstract class AbstractConnection implements Connection } return false; } - + private static final class IdleState extends State { private IdleState() @@ -408,11 +412,11 @@ public abstract class AbstractConnection implements Connection { return _name; } - + void onEnter(AbstractConnection connection) { } - + State fillInterested() { throw new IllegalStateException(this.toString()); @@ -427,28 +431,28 @@ public abstract class AbstractConnection implements Connection { throw new IllegalStateException(this.toString()); } - + State onFailed() { throw new IllegalStateException(this.toString()); } } - + public static final State IDLE=new IdleState(); - + public static final State FILL_INTERESTED=new FillInterestedState(); - + public static final State FILLING=new FillingState(); - + public static final State REFILLING=new RefillingState(); public static final State FILLING_FILL_INTERESTED=new FillingFillInterestedState("FILLING_FILL_INTERESTED"); - + public class NestedState extends State { private final State _nested; - + NestedState(State nested) { super("NESTED("+nested+")"); @@ -471,19 +475,19 @@ public abstract class AbstractConnection implements Connection { return new NestedState(_nested.onFillable()); } - + @Override State onFilled() { return new NestedState(_nested.onFilled()); } } - - + + public class FillingInterestedCallback extends NestedState { private final Callback _callback; - + FillingInterestedCallback(Callback callback,State nested) { super("FILLING_INTERESTED_CALLBACK",nested==FILLING?REFILLING:nested); @@ -523,13 +527,13 @@ public abstract class AbstractConnection implements Connection break; } _callback.failed(x); - } + } }; - + connection.getEndPoint().fillInterested(callback); } } - + private final Runnable _runOnFillable = new Runnable() { @Override @@ -550,10 +554,10 @@ public abstract class AbstractConnection implements Connection } } }; - - + + private class ReadCallback implements Callback - { + { @Override public void succeeded() { @@ -583,7 +587,7 @@ public abstract class AbstractConnection implements Connection } }); } - + @Override public String 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 e5d20c39516..1a4ab43f904 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 @@ -26,6 +26,7 @@ import java.nio.charset.StandardCharsets; import java.util.List; import java.util.concurrent.atomic.AtomicBoolean; import java.util.concurrent.atomic.AtomicInteger; + import javax.servlet.DispatcherType; import javax.servlet.RequestDispatcher; import javax.servlet.http.HttpServletRequest; @@ -117,7 +118,7 @@ public class HttpChannel implements HttpParser.RequestHandler, Runnable, H input.init(_state); _request = new Request(this, input); _response = new Response(this, new HttpOutput(this)); - + if (LOG.isDebugEnabled()) LOG.debug("new {} -> {},{},{}",this,_endPoint,_endPoint.getConnection(),_state); } @@ -168,7 +169,7 @@ public class HttpChannel implements HttpParser.RequestHandler, Runnable, H { _endPoint.setIdleTimeout(timeoutMs); } - + public ByteBufferPool getByteBufferPool() { return _connector.getByteBufferPool(); @@ -335,8 +336,8 @@ public class HttpChannel implements HttpParser.RequestHandler, Runnable, H _response.setStatusWithReason(500,reason); - - ErrorHandler eh = ErrorHandler.getErrorHandler(getServer(),_state.getContextHandler()); + + ErrorHandler eh = ErrorHandler.getErrorHandler(getServer(),_state.getContextHandler()); if (eh instanceof ErrorHandler.ErrorPageMapper) { String error_page=((ErrorHandler.ErrorPageMapper)eh).getErrorPage((HttpServletRequest)_state.getAsyncContextEvent().getSuppliedRequest()); @@ -366,7 +367,7 @@ public class HttpChannel implements HttpParser.RequestHandler, Runnable, H else _response.getHttpOutput().run(); break; - } + } default: break loop; @@ -512,8 +513,7 @@ public class HttpChannel implements HttpParser.RequestHandler, Runnable, H _requests, _committed.get(), _state.getState(), - _state.getState()==HttpChannelState.State.IDLE?"-":_request.getRequestURI() - ); + _uri); } @Override @@ -524,7 +524,7 @@ public class HttpChannel implements HttpParser.RequestHandler, Runnable, H _request.setServerPort(dPort); _request.setRemoteAddr(InetSocketAddress.createUnresolved(sAddr,sPort)); } - + @Override public boolean startRequest(HttpMethod httpMethod, String method, ByteBuffer uri, HttpVersion version) { @@ -552,7 +552,7 @@ public class HttpChannel implements HttpParser.RequestHandler, Runnable, H LOG.ignore(e); path = _uri.getDecodedPath(StandardCharsets.ISO_8859_1); } - + String info = URIUtil.canonicalPath(path); if (info == null) @@ -741,7 +741,7 @@ public class HttpChannel implements HttpParser.RequestHandler, Runnable, H { if (_state.unhandle()==Action.COMPLETE) _state.completed(); - else + else throw new IllegalStateException(); } } 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 a4ae3496576..1a876c73c6a 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 @@ -67,8 +67,8 @@ public class HttpConnection extends AbstractConnection implements Runnable, Http /* ------------------------------------------------------------ */ /** Get the current connection that this thread is dispatched to. - * Note that a thread may be processing a request asynchronously and - * thus not be dispatched to the connection. + * Note that a thread may be processing a request asynchronously and + * thus not be dispatched to the connection. * @see Request#getAttribute(String) for a more general way to access the HttpConnection * @return the current HttpConnection or null */ @@ -110,17 +110,17 @@ public class HttpConnection extends AbstractConnection implements Runnable, Http { return new HttpGenerator(_config.getSendServerVersion(),_config.getSendXPoweredBy()); } - + protected HttpInput newHttpInput() { return new HttpInputOverHTTP(this); } - + protected HttpChannelOverHttp newHttpChannel(HttpInput httpInput) { return new HttpChannelOverHttp(_connector, _config, getEndPoint(), this, httpInput); } - + protected HttpParser newHttpParser() { return new HttpParser(newRequestHandler(), getHttpConfiguration().getRequestHeaderSize()); @@ -184,7 +184,7 @@ public class HttpConnection extends AbstractConnection implements Runnable, Http _bufferPool.release(buffer); } } - + public ByteBuffer getRequestBuffer() { if (_requestBuffer == null) @@ -217,10 +217,10 @@ public class HttpConnection extends AbstractConnection implements Runnable, Http // Do we need some data to parse if (BufferUtil.isEmpty(_requestBuffer)) { - // If the previous iteration filled 0 bytes or saw a close, then break here + // If the previous iteration filled 0 bytes or saw a close, then break here if (filled<=0) break; - + // Can we fill? if(getEndPoint().isInputShutdown()) { @@ -239,13 +239,13 @@ public class HttpConnection extends AbstractConnection implements Runnable, Http filled = getEndPoint().fill(_requestBuffer); if (filled==0) // Do a retry on fill 0 (optimization for SSL connections) filled = getEndPoint().fill(_requestBuffer); - + // tell parser if (filled < 0) _parser.atEOF(); } } - + // Parse the buffer if (_parser.parseNext(_requestBuffer==null?BufferUtil.EMPTY_BUFFER:_requestBuffer)) { @@ -278,7 +278,7 @@ public class HttpConnection extends AbstractConnection implements Runnable, Http close(); } finally - { + { setCurrentConnection(last); if (!suspended && getEndPoint().isOpen() && getEndPoint().getConnection()==this) { @@ -295,7 +295,7 @@ public class HttpConnection extends AbstractConnection implements Runnable, Http { // Not in a race here for the request buffer with #onFillable because an async consumer of // content would only be started after onFillable has given up control. - // In a little bit of a race with #completed, but then not sure if it is legal to be doing + // In a little bit of a race with #completed, but then not sure if it is legal to be doing // async calls to IO and have a completed call at the same time. ByteBuffer requestBuffer = getRequestBuffer(); @@ -315,7 +315,7 @@ public class HttpConnection extends AbstractConnection implements Runnable, Http if (parsed) break; - + // OK lets read some data int filled=getEndPoint().fill(requestBuffer); if (LOG.isDebugEnabled()) // Avoid boxing of variable 'filled' @@ -331,7 +331,7 @@ public class HttpConnection extends AbstractConnection implements Runnable, Http } } } - + @Override public void completed() { @@ -350,7 +350,7 @@ public class HttpConnection extends AbstractConnection implements Runnable, Http return; } } - + // Finish consuming the request // If we are still expecting if (_channel.isExpecting100Continue()) @@ -383,7 +383,7 @@ public class HttpConnection extends AbstractConnection implements Runnable, Http _parser.reset(); else _parser.close(); - + // Not in a race here with onFillable, because it has given up control before calling handle. // in a slight race with #completed, but not sure what to do with that anyway. releaseRequestBuffer(); @@ -426,7 +426,7 @@ public class HttpConnection extends AbstractConnection implements Runnable, Http getEndPoint().close(); } } - // else the parser must be closed, so seek the EOF if we are still open + // else the parser must be closed, so seek the EOF if we are still open else if (getEndPoint().isOpen()) fillInterested(); } @@ -466,7 +466,7 @@ public class HttpConnection extends AbstractConnection implements Runnable, Http if (info!=null && _channel.isExpecting100Continue()) // then we can't be persistent _generator.setPersistent(false); - + if(_sendCallback.reset(info,content,lastContent,callback)) _sendCallback.iterate(); } @@ -479,14 +479,32 @@ public class HttpConnection extends AbstractConnection implements Runnable, Http else if (_sendCallback.reset(null,content,lastContent,callback)) _sendCallback.iterate(); } - + + @Override + public void abort() + { + // Do a direct close of the output, as this may indicate to a client that the + // response is bad either with RST or by abnormal completion of chunked response. + getEndPoint().close(); + } + + @Override + public String toString() + { + return String.format("%s[p=%s,g=%s,c=%s]", + super.toString(), + _parser, + _generator, + _channel); + } + 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() { @@ -559,7 +577,7 @@ public class HttpConnection extends AbstractConnection implements Runnable, Http if (!super.headerComplete()) return false; - + // Should we delay dispatch until we have some content? // We should not delay if there is no content expect or client is expecting 100 or the response is already committed or the request buffer already has something in it to parse if (getHttpConfiguration().isDelayDispatchUntilContent() && _parser.getContentLength() > 0 && @@ -617,7 +635,7 @@ public class HttpConnection extends AbstractConnection implements Runnable, Http _shutdownOut = false; return true; } - + if (isClosed()) callback.failed(new EofException()); else @@ -630,7 +648,7 @@ public class HttpConnection extends AbstractConnection implements Runnable, Http { if (_callback==null) throw new IllegalStateException(); - + ByteBuffer chunk = _chunk; while (true) { @@ -648,7 +666,7 @@ public class HttpConnection extends AbstractConnection implements Runnable, Http { case NEED_HEADER: { - _header = _bufferPool.acquire(_config.getResponseHeaderSize(), HEADER_BUFFER_DIRECT); + _header = _bufferPool.acquire(_config.getResponseHeaderSize(), HEADER_BUFFER_DIRECT); continue; } case NEED_CHUNK: @@ -723,7 +741,7 @@ public class HttpConnection extends AbstractConnection implements Runnable, Http if (h!=null) _bufferPool.release(h); } - + @Override protected void onCompleteSuccess() { @@ -741,21 +759,11 @@ public class HttpConnection extends AbstractConnection implements Runnable, Http if (_shutdownOut) getEndPoint().shutdownOutput(); } - + @Override public String toString() { return String.format("%s[i=%s,cb=%s]",super.toString(),_info,_callback); } } - - - @Override - public void abort() - { - // Do a direct close of the output, as this may indicate to a client that the - // response is bad either with RST or by abnormal completion of chunked response. - getEndPoint().close(); - } - } diff --git a/jetty-server/src/main/java/org/eclipse/jetty/server/HttpInput.java b/jetty-server/src/main/java/org/eclipse/jetty/server/HttpInput.java index 315024a8f7a..e459fdc854e 100644 --- a/jetty-server/src/main/java/org/eclipse/jetty/server/HttpInput.java +++ b/jetty-server/src/main/java/org/eclipse/jetty/server/HttpInput.java @@ -20,6 +20,7 @@ package org.eclipse.jetty.server; import java.io.IOException; import java.util.Objects; + import javax.servlet.ReadListener; import javax.servlet.ServletInputStream; @@ -256,7 +257,7 @@ public abstract class HttpInput extends ServletInputStream implements Runnabl return _contentState==EARLY_EOF; } } - + /** * This method should be called to signal that all the expected * content arrived. @@ -312,7 +313,7 @@ public abstract class HttpInput extends ServletInputStream implements Runnabl return _contentState==ASYNC; } } - + /** * @return whether an EOF has been detected, even though there may be content to consume. */ @@ -332,7 +333,7 @@ public abstract class HttpInput extends ServletInputStream implements Runnabl return _contentState.isEOF(); } } - + @Override public boolean isReady() @@ -376,9 +377,9 @@ public abstract class HttpInput extends ServletInputStream implements Runnabl _contentState = ASYNC; _listener = readListener; _notReady = true; - + content = getNextContent()!=null || isEOF(); - + } if (content) _channelState.onReadPossible(); @@ -451,6 +452,18 @@ public abstract class HttpInput extends ServletInputStream implements Runnabl } } + @Override + public String toString() + { + return String.format("%s@%x[r=%d,s=%s,e=%s,f=%s]", + getClass().getSimpleName(), + hashCode(), + _contentRead, + _contentState, + _eofState, + _onError); + } + protected static abstract class State { public void waitForContent(HttpInput in) throws IOException diff --git a/jetty-server/src/main/java/org/eclipse/jetty/server/Request.java b/jetty-server/src/main/java/org/eclipse/jetty/server/Request.java index 811e1118ee6..6dd85f7a9f4 100644 --- a/jetty-server/src/main/java/org/eclipse/jetty/server/Request.java +++ b/jetty-server/src/main/java/org/eclipse/jetty/server/Request.java @@ -40,6 +40,7 @@ import java.util.HashMap; import java.util.List; import java.util.Locale; import java.util.Map; + import javax.servlet.AsyncContext; import javax.servlet.AsyncListener; import javax.servlet.DispatcherType; @@ -130,7 +131,7 @@ public class Request implements HttpServletRequest private final HttpFields _fields=new HttpFields(); private final List _requestAttributeListeners=new ArrayList<>(); private final HttpInput _input; - + public static class MultiPartCleanerListener implements ServletRequestListener { @Override @@ -162,10 +163,10 @@ public class Request implements HttpServletRequest { //nothing to do, multipart config set up by ServletHolder.handle() } - + } - - + + private boolean _secure; private boolean _asyncSupported = true; @@ -208,7 +209,7 @@ public class Request implements HttpServletRequest private HttpURI _uri; private MultiPartInputStreamParser _multiPartInputStream; //if the request is a multi-part mime private AsyncContextState _async; - + /* ------------------------------------------------------------ */ public Request(HttpChannel channel, HttpInput input) { @@ -398,7 +399,7 @@ public class Request implements HttpServletRequest HttpChannelState state = getHttpChannelState(); if (_async==null || !state.isAsyncStarted()) throw new IllegalStateException(state.getStatusString()); - + return _async; } @@ -531,7 +532,7 @@ public class Request implements HttpServletRequest { return _input.getContentRead(); } - + /* ------------------------------------------------------------ */ /* * @see javax.servlet.ServletRequest#getContentType() @@ -572,7 +573,7 @@ public class Request implements HttpServletRequest { if (_cookies == null || _cookies.getCookies().length == 0) return null; - + return _cookies.getCookies(); } @@ -596,7 +597,7 @@ public class Request implements HttpServletRequest //Javadoc for Request.getCookies() stipulates null for no cookies if (_cookies == null || _cookies.getCookies().length == 0) return null; - + return _cookies.getCookies(); } @@ -1016,7 +1017,7 @@ public class Request implements HttpServletRequest /* ------------------------------------------------------------ */ /** * Access the underlying Remote {@link InetSocketAddress} for this request. - * + * * @return the remote {@link InetSocketAddress} for this request, or null if the request has no remote (see {@link ServletRequest#getRemoteAddr()} for * conditions that result in no remote address) */ @@ -1039,14 +1040,14 @@ public class Request implements HttpServletRequest InetSocketAddress remote=_remote; if (remote==null) remote=_channel.getRemoteAddress(); - + if (remote==null) return ""; - + InetAddress address = remote.getAddress(); if (address==null) return remote.getHostString(); - + return address.getHostAddress(); } @@ -1207,7 +1208,7 @@ public class Request implements HttpServletRequest // Return host from header field String hostPort = _fields.getStringField(HttpHeader.HOST); - + _port=0; if (hostPort != null) { @@ -1238,7 +1239,7 @@ public class Request implements HttpServletRequest } if (hostPort.charAt(0)=='[') { - if (hostPort.charAt(len-1)!=']') + if (hostPort.charAt(len-1)!=']') { LOG.warn("Bad IPv6 "+hostPort); _serverName=hostPort; @@ -1394,7 +1395,7 @@ public class Request implements HttpServletRequest if (!create) return null; - + if (getResponse().isCommitted()) throw new IllegalStateException("Response is committed"); @@ -1482,7 +1483,7 @@ public class Request implements HttpServletRequest UserIdentity user = ((Authentication.User)_authentication).getUserIdentity(); return user.getUserPrincipal(); } - + return null; } @@ -1595,7 +1596,7 @@ public class Request implements HttpServletRequest { if (_context != null) throw new IllegalStateException("Request in context!"); - + if (_inputState == __READER) { try @@ -1718,7 +1719,7 @@ public class Request implements HttpServletRequest setQueryEncoding(value == null?null:value.toString()); else if ("org.eclipse.jetty.server.sendContent".equals(name)) LOG.warn("Deprecated: org.eclipse.jetty.server.sendContent"); - + if (_attributes == null) _attributes = new AttributesMap(); _attributes.setAttribute(name,value); @@ -1937,7 +1938,7 @@ public class Request implements HttpServletRequest { _remote = addr; } - + /* ------------------------------------------------------------ */ /** * @param requestedSessionId @@ -2084,7 +2085,13 @@ public class Request implements HttpServletRequest @Override public String toString() { - return (_handled?"[":"(") + getMethod() + " " + _uri + (_handled?"]@":")@") + hashCode() + " " + super.toString(); + return String.format("%s%s%s %s%s@%x", + getClass().getSimpleName(), + _handled ? "[" : "(", + getMethod(), + _uri, + _handled ? "]" : ")", + hashCode()); } /* ------------------------------------------------------------ */ @@ -2126,14 +2133,14 @@ public class Request implements HttpServletRequest if (_multiPartInputStream == null) { MultipartConfigElement config = (MultipartConfigElement)getAttribute(__MULTIPART_CONFIG_ELEMENT); - + if (config == null) throw new IllegalStateException("No multipart config for servlet"); - + _multiPartInputStream = new MultiPartInputStreamParser(getInputStream(), - getContentType(), config, + getContentType(), config, (_context != null?(File)_context.getAttribute("javax.servlet.context.tempdir"):null)); - + setAttribute(__MULTIPART_INPUT_STREAM, _multiPartInputStream); setAttribute(__MULTIPART_CONTEXT, _context); Collection parts = _multiPartInputStream.getParts(); //causes parsing @@ -2245,9 +2252,9 @@ public class Request implements HttpServletRequest { //Instantiate an instance and inject it T h = getContext().createInstance(handlerClass); - + //TODO handle the rest of the upgrade process - + return h; } catch (Exception e)