Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(342)

Unified Diff: components/cronet/android/test/src/org/chromium/net/Http2TestHandler.java

Issue 1412243012: Initial implementation of CronetBidirectionalStream. (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: Address Helen's comments. Created 4 years, 11 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
Index: components/cronet/android/test/src/org/chromium/net/Http2TestHandler.java
diff --git a/components/cronet/android/test/src/org/chromium/net/Http2TestHandler.java b/components/cronet/android/test/src/org/chromium/net/Http2TestHandler.java
new file mode 100644
index 0000000000000000000000000000000000000000..b647d8200d518df76d44298692b6f675d78b4838
--- /dev/null
+++ b/components/cronet/android/test/src/org/chromium/net/Http2TestHandler.java
@@ -0,0 +1,231 @@
+// Copyright 2015 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+package org.chromium.net;
+
+import org.chromium.base.Log;
+
+import java.util.Locale;
+import java.util.Map;
+
+import static io.netty.buffer.Unpooled.copiedBuffer;
+import static io.netty.buffer.Unpooled.unreleasableBuffer;
+import static io.netty.handler.codec.http.HttpResponseStatus.OK;
+import static io.netty.handler.logging.LogLevel.INFO;
+
+import io.netty.buffer.ByteBuf;
+import io.netty.buffer.ByteBufUtil;
+import io.netty.channel.ChannelHandlerContext;
+import io.netty.handler.codec.http2.AbstractHttp2ConnectionHandlerBuilder;
+import io.netty.handler.codec.http2.DefaultHttp2Headers;
+import io.netty.handler.codec.http2.Http2ConnectionDecoder;
+import io.netty.handler.codec.http2.Http2ConnectionEncoder;
+import io.netty.handler.codec.http2.Http2ConnectionHandler;
+import io.netty.handler.codec.http2.Http2Exception;
+import io.netty.handler.codec.http2.Http2Flags;
+import io.netty.handler.codec.http2.Http2FrameListener;
+import io.netty.handler.codec.http2.Http2FrameLogger;
+import io.netty.handler.codec.http2.Http2Headers;
+import io.netty.handler.codec.http2.Http2Settings;
+import io.netty.util.CharsetUtil;
+
+/**
+ * HTTP/2 test handler for Cronet BidirectionalStream tests.
+ */
+public final class Http2TestHandler extends Http2ConnectionHandler implements Http2FrameListener {
+ // Some Url Paths that have special meaning.
+ public static final String ECHO_ALL_HEADERS_PATH = "/echoallheaders";
+ public static final String ECHO_HEADER_PATH = "/echoheader";
+ public static final String ECHO_METHOD_PATH = "/echomethod";
+ public static final String ECHO_STREAM_PATH = "/echostream";
+ public static final String ECHO_TRAILERS_PATH = "/echotrailers";
+
+ private static final String TAG = "cr_Http2TestHandler";
+ private static final Http2FrameLogger sLogger =
+ new Http2FrameLogger(INFO, Http2TestHandler.class);
+ private static final ByteBuf RESPONSE_BYTES =
+ unreleasableBuffer(copiedBuffer("HTTP/2 Test Server", CharsetUtil.UTF_8));
+ private boolean mEchoStream;
xunjieli 2016/01/27 22:17:10 Seems like this handler can only handle one active
xunjieli 2016/01/27 22:23:24 Also bug here. If first url is echo stream, and th
mef 2016/01/29 00:15:30 Great catch! Currently there are no tests that use
mef 2016/01/29 00:15:30 Done.
+ private Http2Headers mResponseHeaders;
+
+ /**
+ * Builder for HTTP/2 test handler.
+ */
+ public static final class Builder
+ extends AbstractHttp2ConnectionHandlerBuilder<Http2TestHandler, Builder> {
+ public Builder() {
+ frameLogger(sLogger);
+ }
+
+ @Override
+ public Http2TestHandler build() {
+ return super.build();
+ }
+
+ @Override
+ protected Http2TestHandler build(Http2ConnectionDecoder decoder,
+ Http2ConnectionEncoder encoder, Http2Settings initialSettings) {
+ Http2TestHandler handler = new Http2TestHandler(decoder, encoder, initialSettings);
+ frameListener(handler);
+ return handler;
+ }
+ }
+
+ private Http2TestHandler(Http2ConnectionDecoder decoder, Http2ConnectionEncoder encoder,
+ Http2Settings initialSettings) {
+ super(decoder, encoder, initialSettings);
+ }
+
+ @Override
+ public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {
+ super.exceptionCaught(ctx, cause);
+ Log.e(TAG, "An exception was caught", cause);
+ ctx.close();
+ throw new Exception("Exception Caught", cause);
+ }
+
+ private static Http2Headers createResponseHeadersFromRequestHeaders(
+ Http2Headers requestHeaders) {
+ // Create response headers by echoing request headers.
+ Http2Headers responseHeaders = new DefaultHttp2Headers().status(OK.codeAsText());
+ for (Map.Entry<CharSequence, CharSequence> header : requestHeaders) {
+ if (!header.getKey().toString().startsWith(":")) {
+ responseHeaders.add("echo-" + header.getKey(), header.getValue());
+ }
+ }
+
+ responseHeaders.add("echo-method", requestHeaders.get(":method").toString());
+ return responseHeaders;
+ }
+
+ private static String getEchoAllHeadersResponse(Http2Headers headers) {
+ StringBuilder response = new StringBuilder();
+ for (Map.Entry<CharSequence, CharSequence> header : headers) {
+ response.append(header.getKey() + ": " + header.getValue() + "\r\n");
+ }
+ return response.toString();
+ }
+
+ private static String getEchoHeaderResponse(Http2Headers headers) {
+ String[] splitPath = headers.path().toString().split("\\?");
+ if (splitPath.length <= 1) return "Header name not found.";
+
+ String headerName = splitPath[1].toLowerCase(Locale.US);
+ if (headers.get(headerName) == null) return "Header not found:" + headerName;
+
+ return headers.get(headerName).toString();
+ }
+
+ private void doSendResponse(ChannelHandlerContext ctx, int streamId, ByteBuf payload) {
+ // Send a frame for the response status
+ encoder().writeHeaders(ctx, streamId, mResponseHeaders, 0, false, ctx.newPromise());
+ encoder().writeData(ctx, streamId, payload, 0, true, ctx.newPromise());
+ ctx.flush();
+ }
+
+ private void doEchoStream(ChannelHandlerContext ctx, int streamId, Http2Headers headers,
xunjieli 2016/01/27 22:17:10 This method is confusingly named. I was expecting
mef 2016/01/29 00:15:30 Done.
+ int padding, boolean endOfStream) {
+ mEchoStream = true;
+ // Send a frame for the response headers.
+ encoder().writeHeaders(ctx, streamId, mResponseHeaders, 0, endOfStream, ctx.newPromise());
+ ctx.flush();
+ }
+
+ private void doEchoTrailers(ChannelHandlerContext ctx, int streamId) {
+ Http2Headers responseHeaders = new DefaultHttp2Headers().status(OK.codeAsText());
+ encoder().writeHeaders(ctx, streamId, responseHeaders, 0, false, ctx.newPromise());
+ encoder().writeData(ctx, streamId, RESPONSE_BYTES.duplicate(), 0, false, ctx.newPromise());
+ Http2Headers responseTrailers = mResponseHeaders.add("trailer", "value1", "Value2");
+ encoder().writeHeaders(ctx, streamId, responseTrailers, 0, true, ctx.newPromise());
+ ctx.flush();
+ }
+
+ @Override
+ public int onDataRead(ChannelHandlerContext ctx, int streamId, ByteBuf data, int padding,
+ boolean endOfStream) throws Http2Exception {
+ int processed = data.readableBytes() + padding;
+ if (mEchoStream) {
+ encoder().writeData(ctx, streamId, data.retain(), 0, endOfStream, ctx.newPromise());
xunjieli 2016/01/27 22:17:10 use doEchoStream? see previous comment.
mef 2016/01/29 00:15:30 Done.
+ ctx.flush();
+ } else if (endOfStream) {
+ doSendResponse(ctx, streamId, data.retain());
+ }
+ return processed;
+ }
+
+ @Override
+ public void onHeadersRead(ChannelHandlerContext ctx, int streamId, Http2Headers headers,
+ int padding, boolean endOfStream) throws Http2Exception {
+ mResponseHeaders = createResponseHeadersFromRequestHeaders(headers);
+ String path = headers.path().toString();
+ if (path.startsWith(ECHO_STREAM_PATH)) {
+ doEchoStream(ctx, streamId, headers, padding, endOfStream);
+ } else if (path.startsWith(ECHO_TRAILERS_PATH)) {
+ doEchoTrailers(ctx, streamId);
+ } else if (endOfStream) {
+ mResponseHeaders = new DefaultHttp2Headers().status(OK.codeAsText());
+ ByteBuf content = ctx.alloc().buffer();
+ try {
+ if (path.startsWith(ECHO_ALL_HEADERS_PATH)) {
+ ByteBufUtil.writeAscii(content, getEchoAllHeadersResponse(headers));
+ } else if (path.startsWith(ECHO_HEADER_PATH)) {
+ ByteBufUtil.writeAscii(content, getEchoHeaderResponse(headers));
+ } else if (path.startsWith(ECHO_METHOD_PATH)) {
+ ByteBufUtil.writeAscii(content, headers.method());
+ } else {
+ content.writeBytes(RESPONSE_BYTES.duplicate());
+ ByteBufUtil.writeAscii(content, " - via HTTP/2");
+ }
+ } catch (Exception e) {
+ ByteBufUtil.writeAscii(content, "Exception: " + e.toString());
+ }
+
+ doSendResponse(ctx, streamId, content);
+ }
+ }
+
+ @Override
+ public void onHeadersRead(ChannelHandlerContext ctx, int streamId, Http2Headers headers,
+ int streamDependency, short weight, boolean exclusive, int padding, boolean endOfStream)
+ throws Http2Exception {
+ onHeadersRead(ctx, streamId, headers, padding, endOfStream);
+ }
+
+ @Override
+ public void onPriorityRead(ChannelHandlerContext ctx, int streamId, int streamDependency,
+ short weight, boolean exclusive) throws Http2Exception {}
+
+ @Override
+ public void onRstStreamRead(ChannelHandlerContext ctx, int streamId, long errorCode)
+ throws Http2Exception {}
+
+ @Override
+ public void onSettingsAckRead(ChannelHandlerContext ctx) throws Http2Exception {}
+
+ @Override
+ public void onSettingsRead(ChannelHandlerContext ctx, Http2Settings settings)
+ throws Http2Exception {}
+
+ @Override
+ public void onPingRead(ChannelHandlerContext ctx, ByteBuf data) throws Http2Exception {}
+
+ @Override
+ public void onPingAckRead(ChannelHandlerContext ctx, ByteBuf data) throws Http2Exception {}
+
+ @Override
+ public void onPushPromiseRead(ChannelHandlerContext ctx, int streamId, int promisedStreamId,
+ Http2Headers headers, int padding) throws Http2Exception {}
+
+ @Override
+ public void onGoAwayRead(ChannelHandlerContext ctx, int lastStreamId, long errorCode,
+ ByteBuf debugData) throws Http2Exception {}
+
+ @Override
+ public void onWindowUpdateRead(ChannelHandlerContext ctx, int streamId, int windowSizeIncrement)
+ throws Http2Exception {}
+
+ @Override
+ public void onUnknownFrame(ChannelHandlerContext ctx, byte frameType, int streamId,
+ Http2Flags flags, ByteBuf payload) throws Http2Exception {}
+}

Powered by Google App Engine
This is Rietveld 408576698