Author: markt Date: Wed May 20 09:42:17 2015 New Revision: 1680504 URL: http://svn.apache.org/r1680504 Log: Plumb in the basics (i.e. what I needed to get a request for http://localhost:8080/exmaple to progress) for reading the request. The response gets generated. Still figuring out how best to handle writing of the response.
Added: tomcat/trunk/java/org/apache/coyote/http2/StreamProcessor.java (with props) Modified: tomcat/trunk/java/org/apache/coyote/AbstractProcessor.java tomcat/trunk/java/org/apache/coyote/AbstractProtocol.java tomcat/trunk/java/org/apache/coyote/UpgradeProtocol.java tomcat/trunk/java/org/apache/coyote/http2/Http2Protocol.java tomcat/trunk/java/org/apache/coyote/http2/Http2UpgradeHandler.java tomcat/trunk/java/org/apache/coyote/http2/LocalStrings.properties tomcat/trunk/java/org/apache/coyote/http2/Stream.java tomcat/trunk/java/org/apache/tomcat/util/net/AprEndpoint.java tomcat/trunk/test/org/apache/coyote/http2/TestAbstractStream.java Modified: tomcat/trunk/java/org/apache/coyote/AbstractProcessor.java URL: http://svn.apache.org/viewvc/tomcat/trunk/java/org/apache/coyote/AbstractProcessor.java?rev=1680504&r1=1680503&r2=1680504&view=diff ============================================================================== --- tomcat/trunk/java/org/apache/coyote/AbstractProcessor.java (original) +++ tomcat/trunk/java/org/apache/coyote/AbstractProcessor.java Wed May 20 09:42:17 2015 @@ -61,16 +61,32 @@ public abstract class AbstractProcessor response = null; } + + /** + * Used by HTTP/2. + * + * @param coyoteRequest + * @param coyoteResponse + */ + protected AbstractProcessor(Request coyoteRequest, Response coyoteResponse) { + this(null, coyoteRequest, coyoteResponse); + } + + public AbstractProcessor(AbstractEndpoint<?> endpoint) { + this(endpoint, new Request(), new Response()); + } + + + private AbstractProcessor(AbstractEndpoint<?> endpoint, Request coyoteRequest, Response coyoteResponse) { this.endpoint = endpoint; asyncStateMachine = new AsyncStateMachine(this); - request = new Request(); - response = new Response(); + request = coyoteRequest; + response = coyoteResponse; response.setHook(this); request.setResponse(response); } - /** * Update the current error state to the new error state if the new error * state is more severe than the current error state. Modified: tomcat/trunk/java/org/apache/coyote/AbstractProtocol.java URL: http://svn.apache.org/viewvc/tomcat/trunk/java/org/apache/coyote/AbstractProtocol.java?rev=1680504&r1=1680503&r2=1680504&view=diff ============================================================================== --- tomcat/trunk/java/org/apache/coyote/AbstractProtocol.java (original) +++ tomcat/trunk/java/org/apache/coyote/AbstractProtocol.java Wed May 20 09:42:17 2015 @@ -648,7 +648,8 @@ public abstract class AbstractProtocol<S UpgradeProtocol upgradeProtocol = getProtocol().getNegotiatedProtocol(negotiatedProtocol); if (upgradeProtocol != null) { - processor = upgradeProtocol.getProcessor(wrapper); + processor = upgradeProtocol.getProcessor( + wrapper, getProtocol().getAdapter()); } else if (negotiatedProtocol.equals("http/1.1")) { // Explicitly negotiated the default protocol. // Obtain a processor below. Modified: tomcat/trunk/java/org/apache/coyote/UpgradeProtocol.java URL: http://svn.apache.org/viewvc/tomcat/trunk/java/org/apache/coyote/UpgradeProtocol.java?rev=1680504&r1=1680503&r2=1680504&view=diff ============================================================================== --- tomcat/trunk/java/org/apache/coyote/UpgradeProtocol.java (original) +++ tomcat/trunk/java/org/apache/coyote/UpgradeProtocol.java Wed May 20 09:42:17 2015 @@ -58,5 +58,5 @@ public interface UpgradeProtocol { * @return A processor instance for processing a connection using this * protocol. */ - public Processor getProcessor(SocketWrapperBase<?> socketWrapper); + public Processor getProcessor(SocketWrapperBase<?> socketWrapper, Adapter adapter); } Modified: tomcat/trunk/java/org/apache/coyote/http2/Http2Protocol.java URL: http://svn.apache.org/viewvc/tomcat/trunk/java/org/apache/coyote/http2/Http2Protocol.java?rev=1680504&r1=1680503&r2=1680504&view=diff ============================================================================== --- tomcat/trunk/java/org/apache/coyote/http2/Http2Protocol.java (original) +++ tomcat/trunk/java/org/apache/coyote/http2/Http2Protocol.java Wed May 20 09:42:17 2015 @@ -18,6 +18,7 @@ package org.apache.coyote.http2; import java.nio.charset.StandardCharsets; +import org.apache.coyote.Adapter; import org.apache.coyote.Processor; import org.apache.coyote.UpgradeProtocol; import org.apache.coyote.http11.upgrade.UpgradeProcessorInternal; @@ -45,9 +46,9 @@ public class Http2Protocol implements Up } @Override - public Processor getProcessor(SocketWrapperBase<?> socketWrapper) { + public Processor getProcessor(SocketWrapperBase<?> socketWrapper, Adapter adapter) { UpgradeProcessorInternal processor = - new UpgradeProcessorInternal(socketWrapper, null, new Http2UpgradeHandler()); + new UpgradeProcessorInternal(socketWrapper, null, new Http2UpgradeHandler(adapter)); return processor; } } Modified: tomcat/trunk/java/org/apache/coyote/http2/Http2UpgradeHandler.java URL: http://svn.apache.org/viewvc/tomcat/trunk/java/org/apache/coyote/http2/Http2UpgradeHandler.java?rev=1680504&r1=1680503&r2=1680504&view=diff ============================================================================== --- tomcat/trunk/java/org/apache/coyote/http2/Http2UpgradeHandler.java (original) +++ tomcat/trunk/java/org/apache/coyote/http2/Http2UpgradeHandler.java Wed May 20 09:42:17 2015 @@ -25,6 +25,7 @@ import java.util.Map; import javax.servlet.http.WebConnection; +import org.apache.coyote.Adapter; import org.apache.coyote.http11.upgrade.InternalHttpUpgradeHandler; import org.apache.juli.logging.Log; import org.apache.juli.logging.LogFactory; @@ -62,6 +63,7 @@ public class Http2UpgradeHandler extends private static final byte[] SETTINGS_ACK = { 0x00, 0x00, 0x00, 0x04, 0x01, 0x00, 0x00, 0x00, 0x00 }; private static final byte[] GOAWAY = { 0x07, 0x00, 0x00, 0x00, 0x00 }; + private final Adapter adapter; private volatile SocketWrapperBase<?> socketWrapper; private volatile boolean initialized = false; private volatile ConnectionPrefaceParser connectionPrefaceParser = @@ -79,8 +81,10 @@ public class Http2UpgradeHandler extends private final Map<Integer,Stream> streams = new HashMap<>(); - public Http2UpgradeHandler() { + + public Http2UpgradeHandler(Adapter adapter) { super (STREAM_ID_ZERO); + this.adapter = adapter; } @@ -129,6 +133,7 @@ public class Http2UpgradeHandler extends } connectionPrefaceParser = null; + // Process all the incoming data try { while (processFrame()) { } @@ -150,6 +155,8 @@ public class Http2UpgradeHandler extends return SocketState.CLOSED; } + // TODO process writes + return SocketState.LONG; case OPEN_WRITE: @@ -292,6 +299,10 @@ public class Http2UpgradeHandler extends if (padLength > 0) { swallowPayload(padLength); } + + // Process this stream on a container thread + StreamProcessor streamProcessor = new StreamProcessor(stream, adapter, socketWrapper); + socketWrapper.getEndpoint().getExecutor().execute(streamProcessor); } @@ -381,7 +392,6 @@ public class Http2UpgradeHandler extends } // Acknowledge the settings - // TODO Need to coordinate writes with other threads socketWrapper.write(true, SETTINGS_ACK, 0, SETTINGS_ACK.length); socketWrapper.flush(true); } @@ -593,6 +603,11 @@ public class Http2UpgradeHandler extends } + String getProperty(String key) { + return socketWrapper.getEndpoint().getProperty(key); + } + + @Override protected final Log getLog() { return log; Modified: tomcat/trunk/java/org/apache/coyote/http2/LocalStrings.properties URL: http://svn.apache.org/viewvc/tomcat/trunk/java/org/apache/coyote/http2/LocalStrings.properties?rev=1680504&r1=1680503&r2=1680504&view=diff ============================================================================== --- tomcat/trunk/java/org/apache/coyote/http2/LocalStrings.properties (original) +++ tomcat/trunk/java/org/apache/coyote/http2/LocalStrings.properties Wed May 20 09:42:17 2015 @@ -32,6 +32,8 @@ hpackhuffman.huffmanEncodedHpackValueDid stream.header.debug=Stream [{0}] recieved HTTP header [{1}] with value [{2}] +streamProcessor.httpupgrade.notsupported=HTTP upgrade is not supported within HTTP/2 streams + upgradeHandler.connectionError=An error occurred that requires the HTTP/2 connection to be closed. upgradeHandler.payloadTooBig=The payload is [{0}] bytes long but the maximum frame size is [{1}] upgradeHandler.processFrame=Processing frame of type [{0}] for stream [{2}] with flags [{1}] and payload size [{3}] Modified: tomcat/trunk/java/org/apache/coyote/http2/Stream.java URL: http://svn.apache.org/viewvc/tomcat/trunk/java/org/apache/coyote/http2/Stream.java?rev=1680504&r1=1680503&r2=1680504&view=diff ============================================================================== --- tomcat/trunk/java/org/apache/coyote/http2/Stream.java (original) +++ tomcat/trunk/java/org/apache/coyote/http2/Stream.java Wed May 20 09:42:17 2015 @@ -16,9 +16,15 @@ */ package org.apache.coyote.http2; +import java.io.IOException; + +import org.apache.coyote.OutputBuffer; +import org.apache.coyote.Request; +import org.apache.coyote.Response; import org.apache.coyote.http2.HpackDecoder.HeaderEmitter; import org.apache.juli.logging.Log; import org.apache.juli.logging.LogFactory; +import org.apache.tomcat.util.buf.ByteChunk; import org.apache.tomcat.util.res.StringManager; public class Stream extends AbstractStream implements HeaderEmitter { @@ -26,13 +32,19 @@ public class Stream extends AbstractStre private static final Log log = LogFactory.getLog(Stream.class); private static final StringManager sm = StringManager.getManager(Stream.class); + private final Http2UpgradeHandler handler; + private final Request coyoteRequest = new Request(); + private final Response coyoteResponse = new Response(); + private volatile long flowControlWindowSize; public Stream(Integer identifier, Http2UpgradeHandler handler) { super(identifier); + this.handler = handler; setParentStream(handler); flowControlWindowSize = handler.getRemoteSettings().getInitialWindowSize(); + coyoteResponse.setOutputBuffer(new StreamOutputBuffer()); } @@ -47,7 +59,49 @@ public class Stream extends AbstractStre log.debug(sm.getString("stream.header.debug", getIdentifier(), name, value)); } - // TODO: Do something with these headers + switch(name) { + case ":method": { + coyoteRequest.method().setString(value); + break; + } + case ":path": { + coyoteRequest.requestURI().setString(value); + // TODO: This is almost certainly wrong and needs to be decoded + coyoteRequest.decodedURI().setString(value); + break; + } + case ":authority": { + int i = value.lastIndexOf(':'); + if (i > -1) { + coyoteRequest.serverName().setString(value.substring(0, i)); + coyoteRequest.setServerPort(Integer.parseInt(value.substring(i + 1))); + } else { + coyoteRequest.serverName().setString(value); + boolean secure = Boolean.parseBoolean(handler.getProperty("secure")); + if (secure) { + coyoteRequest.setServerPort(443); + } else { + coyoteRequest.setServerPort(80); + } + } + break; + } + default: { + // Assume other HTTP header + coyoteRequest.getMimeHeaders().addValue(name).setString(value); + } + } + } + + + void writeHeaders() { + // Format the frames. + // TODO + } + + + void flushData() { + // TODO } @@ -55,4 +109,33 @@ public class Stream extends AbstractStre protected final Log getLog() { return log; } + + + public Request getCoyoteRequest() { + return coyoteRequest; + } + + + public Response getCoyoteResponse() { + return coyoteResponse; + } + + + private class StreamOutputBuffer implements OutputBuffer { + + private volatile long written = 0; + + @Override + public int doWrite(ByteChunk chunk) throws IOException { + // TODO Blocking. Write to buffer. flushData() if full. + log.debug("Write [" + chunk.getLength() + "] bytes"); + written += chunk.getLength(); + return chunk.getLength(); + } + + @Override + public long getBytesWritten() { + return written; + } + } } Added: tomcat/trunk/java/org/apache/coyote/http2/StreamProcessor.java URL: http://svn.apache.org/viewvc/tomcat/trunk/java/org/apache/coyote/http2/StreamProcessor.java?rev=1680504&view=auto ============================================================================== --- tomcat/trunk/java/org/apache/coyote/http2/StreamProcessor.java (added) +++ tomcat/trunk/java/org/apache/coyote/http2/StreamProcessor.java Wed May 20 09:42:17 2015 @@ -0,0 +1,147 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.coyote.http2; + +import java.io.IOException; +import java.nio.ByteBuffer; +import java.util.concurrent.atomic.AtomicBoolean; + +import javax.servlet.http.HttpUpgradeHandler; + +import org.apache.coyote.AbstractProcessor; +import org.apache.coyote.ActionCode; +import org.apache.coyote.Adapter; +import org.apache.juli.logging.Log; +import org.apache.juli.logging.LogFactory; +import org.apache.tomcat.util.net.AbstractEndpoint.Handler.SocketState; +import org.apache.tomcat.util.net.SSLSupport; +import org.apache.tomcat.util.net.SocketStatus; +import org.apache.tomcat.util.net.SocketWrapperBase; +import org.apache.tomcat.util.res.StringManager; + +public class StreamProcessor extends AbstractProcessor implements Runnable { + + private static final Log log = LogFactory.getLog(StreamProcessor.class); + private static final StringManager sm = StringManager.getManager(StreamProcessor.class); + + private final Stream stream; + + + public StreamProcessor(Stream stream, Adapter adapter, SocketWrapperBase<?> socketWrapper) { + super(stream.getCoyoteRequest(), stream.getCoyoteResponse()); + this.stream = stream; + setAdapter(adapter); + setSocketWrapper(socketWrapper); + } + + + @Override + public void run() { + try { + adapter.service(request, response); + // Ensure the response is complete + response.action(ActionCode.CLIENT_FLUSH, null); + } catch (Exception e) { + // TODO + e.printStackTrace(); + } + } + + + @Override + public SocketState process(SocketWrapperBase<?> socket) throws IOException { + // TODO Auto-generated method stub + return null; + } + + + @Override + public SocketState dispatch(SocketStatus status) { + // TODO Auto-generated method stub + return null; + } + + + @Override + public void action(ActionCode actionCode, Object param) { + switch (actionCode) { + case REQ_HOST_ATTRIBUTE: { + request.remoteHost().setString(socketWrapper.getRemoteHost()); + break; + } + case IS_ERROR: { + ((AtomicBoolean) param).set(getErrorState().isError()); + break; + } + case CLIENT_FLUSH: { + action(ActionCode.COMMIT, null); + stream.flushData(); + break; + } + case COMMIT: { + if (!response.isCommitted()) { + response.setCommitted(true); + stream.writeHeaders(); + } + break; + } + default: + // TODO + log.debug("TODO: Action: " + actionCode); + } + } + + + @Override + public void recycle() { + // TODO Auto-generated method stub + + } + + + @Override + public void setSslSupport(SSLSupport sslSupport) { + // TODO Auto-generated method stub + + } + + + @Override + public boolean isUpgrade() { + return false; + } + + + @Override + protected Log getLog() { + return log; + } + + + @Override + public HttpUpgradeHandler getHttpUpgradeHandler() { + // Should never happen + throw new IllegalStateException(sm.getString("streamProcessor.httpupgrade.notsupported")); + } + + + @Override + public ByteBuffer getLeftoverInput() { + // Should never happen + throw new IllegalStateException(sm.getString("streamProcessor.httpupgrade.notsupported")); + } +} Propchange: tomcat/trunk/java/org/apache/coyote/http2/StreamProcessor.java ------------------------------------------------------------------------------ svn:eol-style = native Modified: tomcat/trunk/java/org/apache/tomcat/util/net/AprEndpoint.java URL: http://svn.apache.org/viewvc/tomcat/trunk/java/org/apache/tomcat/util/net/AprEndpoint.java?rev=1680504&r1=1680503&r2=1680504&view=diff ============================================================================== --- tomcat/trunk/java/org/apache/tomcat/util/net/AprEndpoint.java (original) +++ tomcat/trunk/java/org/apache/tomcat/util/net/AprEndpoint.java Wed May 20 09:42:17 2015 @@ -2510,7 +2510,7 @@ public class AprEndpoint extends Abstrac if (result > 0) { socketReadBuffer.position(socketReadBuffer.position() + result); return result; - } else if (-result == Status.EAGAIN) { + } else if (result == 0 || -result == Status.EAGAIN) { return 0; } else if (-result == Status.APR_EGENERAL && isSecure()) { // Not entirely sure why this is necessary. Testing to date has not Modified: tomcat/trunk/test/org/apache/coyote/http2/TestAbstractStream.java URL: http://svn.apache.org/viewvc/tomcat/trunk/test/org/apache/coyote/http2/TestAbstractStream.java?rev=1680504&r1=1680503&r2=1680504&view=diff ============================================================================== --- tomcat/trunk/test/org/apache/coyote/http2/TestAbstractStream.java (original) +++ tomcat/trunk/test/org/apache/coyote/http2/TestAbstractStream.java Wed May 20 09:42:17 2015 @@ -28,7 +28,7 @@ public class TestAbstractStream { @Test public void testDependenciesFig3() { // Setup - Http2UpgradeHandler handler = new Http2UpgradeHandler(); + Http2UpgradeHandler handler = new Http2UpgradeHandler(null); Stream a = new Stream(Integer.valueOf(1), handler); Stream b = new Stream(Integer.valueOf(2), handler); Stream c = new Stream(Integer.valueOf(3), handler); @@ -59,7 +59,7 @@ public class TestAbstractStream { @Test public void testDependenciesFig4() { // Setup - Http2UpgradeHandler handler = new Http2UpgradeHandler(); + Http2UpgradeHandler handler = new Http2UpgradeHandler(null); Stream a = new Stream(Integer.valueOf(1), handler); Stream b = new Stream(Integer.valueOf(2), handler); Stream c = new Stream(Integer.valueOf(3), handler); @@ -90,7 +90,7 @@ public class TestAbstractStream { @Test public void testDependenciesFig5NonExclusive() { // Setup - Http2UpgradeHandler handler = new Http2UpgradeHandler(); + Http2UpgradeHandler handler = new Http2UpgradeHandler(null); Stream a = new Stream(Integer.valueOf(1), handler); Stream b = new Stream(Integer.valueOf(2), handler); Stream c = new Stream(Integer.valueOf(3), handler); @@ -132,7 +132,7 @@ public class TestAbstractStream { @Test public void testDependenciesFig5Exclusive() { // Setup - Http2UpgradeHandler handler = new Http2UpgradeHandler(); + Http2UpgradeHandler handler = new Http2UpgradeHandler(null); Stream a = new Stream(Integer.valueOf(1), handler); Stream b = new Stream(Integer.valueOf(2), handler); Stream c = new Stream(Integer.valueOf(3), handler); --------------------------------------------------------------------- To unsubscribe, e-mail: dev-unsubscr...@tomcat.apache.org For additional commands, e-mail: dev-h...@tomcat.apache.org