You are viewing a plain text version of this content. The canonical link for it is here.
Posted to dev@tomcat.apache.org by ma...@apache.org on 2015/05/20 11:42:17 UTC
svn commit: r1680504 - in /tomcat/trunk: java/org/apache/coyote/
java/org/apache/coyote/http2/ java/org/apache/tomcat/util/net/
test/org/apache/coyote/http2/
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-unsubscribe@tomcat.apache.org
For additional commands, e-mail: dev-help@tomcat.apache.org