OLD | NEW |
---|---|
(Empty) | |
1 // Copyright 2015 The Chromium Authors. All rights reserved. | |
2 // Use of this source code is governed by a BSD-style license that can be | |
3 // found in the LICENSE file. | |
4 | |
5 package org.chromium.net; | |
6 | |
7 import org.chromium.base.Log; | |
8 | |
9 import java.util.Locale; | |
10 import java.util.Map; | |
11 | |
12 import static io.netty.buffer.Unpooled.copiedBuffer; | |
13 import static io.netty.buffer.Unpooled.unreleasableBuffer; | |
14 import static io.netty.handler.codec.http.HttpResponseStatus.OK; | |
15 import static io.netty.handler.logging.LogLevel.INFO; | |
16 | |
17 import io.netty.buffer.ByteBuf; | |
18 import io.netty.buffer.ByteBufUtil; | |
19 import io.netty.channel.ChannelHandlerContext; | |
20 import io.netty.handler.codec.http2.AbstractHttp2ConnectionHandlerBuilder; | |
21 import io.netty.handler.codec.http2.DefaultHttp2Headers; | |
22 import io.netty.handler.codec.http2.Http2ConnectionDecoder; | |
23 import io.netty.handler.codec.http2.Http2ConnectionEncoder; | |
24 import io.netty.handler.codec.http2.Http2ConnectionHandler; | |
25 import io.netty.handler.codec.http2.Http2Exception; | |
26 import io.netty.handler.codec.http2.Http2Flags; | |
27 import io.netty.handler.codec.http2.Http2FrameListener; | |
28 import io.netty.handler.codec.http2.Http2FrameLogger; | |
29 import io.netty.handler.codec.http2.Http2Headers; | |
30 import io.netty.handler.codec.http2.Http2Settings; | |
31 import io.netty.util.CharsetUtil; | |
32 | |
33 /** | |
34 * HTTP/2 test handler for Cronet BidirectionalStream tests. | |
35 */ | |
36 public final class Http2TestHandler extends Http2ConnectionHandler implements Ht tp2FrameListener { | |
37 // Some Url Paths have special meaning. | |
xunjieli
2016/01/27 16:16:38
nit: s/have/that.
mef
2016/01/27 19:06:47
Done.
| |
38 public static final String ECHO_ALL_HEADERS_PATH = "/echoallheaders"; | |
39 public static final String ECHO_HEADER_PATH = "/echoheader"; | |
40 public static final String ECHO_METHOD_PATH = "/echomethod"; | |
41 public static final String ECHO_STREAM_PATH = "/echostream"; | |
42 public static final String ECHO_TRAILERS_PATH = "/echotrailers"; | |
43 | |
44 private static final String TAG = "cr_Http2TestHandler"; | |
45 private static final Http2FrameLogger sLogger = | |
46 new Http2FrameLogger(INFO, Http2TestHandler.class); | |
47 private static final ByteBuf RESPONSE_BYTES = | |
48 unreleasableBuffer(copiedBuffer("HTTP/2 Test Server", CharsetUtil.UT F_8)); | |
49 private boolean mEchoStream; | |
50 private Http2Headers mResponseHeaders; | |
51 | |
52 static final class Builder | |
xunjieli
2016/01/27 16:16:38
nit: public?
mef
2016/01/27 19:06:47
Done.
| |
53 extends AbstractHttp2ConnectionHandlerBuilder<Http2TestHandler, Buil der> { | |
54 public Builder() { | |
55 frameLogger(sLogger); | |
56 } | |
57 | |
58 @Override | |
59 public Http2TestHandler build() { | |
60 return super.build(); | |
61 } | |
62 | |
63 @Override | |
64 protected Http2TestHandler build(Http2ConnectionDecoder decoder, | |
65 Http2ConnectionEncoder encoder, Http2Settings initialSettings) { | |
66 Http2TestHandler handler = new Http2TestHandler(decoder, encoder, in itialSettings); | |
67 frameListener(handler); | |
68 return handler; | |
69 } | |
70 } | |
71 | |
72 private Http2TestHandler(Http2ConnectionDecoder decoder, Http2ConnectionEnco der encoder, | |
73 Http2Settings initialSettings) { | |
74 super(decoder, encoder, initialSettings); | |
75 } | |
76 | |
77 @Override | |
78 public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) thro ws Exception { | |
79 super.exceptionCaught(ctx, cause); | |
80 Log.e(TAG, "An exception was caught", cause); | |
81 ctx.close(); | |
82 throw new Exception("Exception Caught", cause); | |
83 } | |
84 | |
85 private static Http2Headers createResponseHeadersFromRequestHeaders( | |
86 Http2Headers requestHeaders) { | |
87 // Create response headers by echoing request headers. | |
88 Http2Headers responseHeaders = new DefaultHttp2Headers().status(OK.codeA sText()); | |
89 for (Map.Entry<CharSequence, CharSequence> header : requestHeaders) { | |
90 if (!header.getKey().toString().startsWith(":")) { | |
91 responseHeaders.add("echo-" + header.getKey(), header.getValue() ); | |
92 } | |
93 } | |
94 | |
95 responseHeaders.add("echo-method", requestHeaders.get(":method").toStrin g()); | |
96 return responseHeaders; | |
97 } | |
98 | |
99 private static String getEchoAllHeadersResponse(Http2Headers headers) { | |
100 StringBuilder response = new StringBuilder(); | |
101 for (Map.Entry<CharSequence, CharSequence> header : headers) { | |
102 response.append(header.getKey() + ": " + header.getValue() + "\r\n") ; | |
103 } | |
104 return response.toString(); | |
105 } | |
106 | |
107 private static String getEchoHeaderResponse(Http2Headers headers) { | |
108 String[] splitPath = headers.path().toString().split("\\?"); | |
109 if (splitPath.length <= 1) return "Header name not found."; | |
110 | |
111 String headerName = splitPath[1].toLowerCase(Locale.US); | |
112 if (headers.get(headerName) == null) return "Header not found:" + header Name; | |
113 | |
114 return headers.get(headerName).toString(); | |
115 } | |
116 | |
117 private void doSendResponse(ChannelHandlerContext ctx, int streamId, ByteBuf payload) { | |
118 // Send a frame for the response status | |
119 encoder().writeHeaders(ctx, streamId, mResponseHeaders, 0, false, ctx.ne wPromise()); | |
120 encoder().writeData(ctx, streamId, payload, 0, true, ctx.newPromise()); | |
121 ctx.flush(); | |
122 } | |
123 | |
124 private void doEchoStream(ChannelHandlerContext ctx, int streamId, Http2Head ers headers, | |
125 int padding, boolean endOfStream) { | |
126 mEchoStream = true; | |
127 // Send a frame for the response headers. | |
128 encoder().writeHeaders(ctx, streamId, mResponseHeaders, 0, endOfStream, ctx.newPromise()); | |
129 ctx.flush(); | |
130 } | |
131 | |
132 private void doEchoTrailers(ChannelHandlerContext ctx, int streamId, Http2He aders headers, | |
xunjieli
2016/01/27 16:16:38
hmm. |header| from the args is not used. Should it
mef
2016/01/27 19:06:47
Done.
| |
133 int padding, boolean endOfStream) { | |
134 Http2Headers responseHeaders = new DefaultHttp2Headers().status(OK.codeA sText()); | |
135 encoder().writeHeaders(ctx, streamId, responseHeaders, 0, false, ctx.new Promise()); | |
136 encoder().writeData(ctx, streamId, RESPONSE_BYTES.duplicate(), 0, false, ctx.newPromise()); | |
137 Http2Headers responseTrailers = mResponseHeaders.add("trailer", "value1" , "Value2"); | |
138 encoder().writeHeaders(ctx, streamId, responseTrailers, 0, true, ctx.new Promise()); | |
139 ctx.flush(); | |
140 } | |
141 | |
142 @Override | |
143 public int onDataRead(ChannelHandlerContext ctx, int streamId, ByteBuf data, int padding, | |
144 boolean endOfStream) throws Http2Exception { | |
145 int processed = data.readableBytes() + padding; | |
146 if (mEchoStream) { | |
147 encoder().writeData(ctx, streamId, data.retain(), 0, endOfStream, ct x.newPromise()); | |
148 ctx.flush(); | |
149 } else if (endOfStream) { | |
150 doSendResponse(ctx, streamId, data.retain()); | |
151 } | |
152 return processed; | |
153 } | |
154 | |
155 @Override | |
156 public void onHeadersRead(ChannelHandlerContext ctx, int streamId, Http2Head ers headers, | |
157 int padding, boolean endOfStream) throws Http2Exception { | |
158 mResponseHeaders = createResponseHeadersFromRequestHeaders(headers); | |
159 String path = headers.path().toString(); | |
160 if (path.startsWith(ECHO_STREAM_PATH)) { | |
161 doEchoStream(ctx, streamId, headers, padding, endOfStream); | |
162 } else if (path.startsWith(ECHO_TRAILERS_PATH)) { | |
163 doEchoTrailers(ctx, streamId, headers, padding, endOfStream); | |
164 } else if (endOfStream) { | |
165 mResponseHeaders = new DefaultHttp2Headers().status(OK.codeAsText()) ; | |
166 ByteBuf content = ctx.alloc().buffer(); | |
167 try { | |
168 if (path.startsWith(ECHO_ALL_HEADERS_PATH)) { | |
169 ByteBufUtil.writeAscii(content, getEchoAllHeadersResponse(he aders)); | |
170 } else if (path.startsWith(ECHO_HEADER_PATH)) { | |
171 ByteBufUtil.writeAscii(content, getEchoHeaderResponse(header s)); | |
172 } else if (path.startsWith(ECHO_METHOD_PATH)) { | |
173 ByteBufUtil.writeAscii(content, headers.method()); | |
174 } else { | |
175 content.writeBytes(RESPONSE_BYTES.duplicate()); | |
176 ByteBufUtil.writeAscii(content, " - via HTTP/2"); | |
177 } | |
178 } catch (Exception e) { | |
179 ByteBufUtil.writeAscii(content, "Exception: " + e.toString()); | |
180 } | |
181 | |
182 doSendResponse(ctx, streamId, content); | |
183 } | |
184 } | |
185 | |
186 @Override | |
187 public void onHeadersRead(ChannelHandlerContext ctx, int streamId, Http2Head ers headers, | |
188 int streamDependency, short weight, boolean exclusive, int padding, boolean endOfStream) | |
189 throws Http2Exception { | |
190 onHeadersRead(ctx, streamId, headers, padding, endOfStream); | |
191 } | |
192 | |
193 @Override | |
194 public void onPriorityRead(ChannelHandlerContext ctx, int streamId, int stre amDependency, | |
195 short weight, boolean exclusive) throws Http2Exception {} | |
196 | |
197 @Override | |
198 public void onRstStreamRead(ChannelHandlerContext ctx, int streamId, long er rorCode) | |
199 throws Http2Exception {} | |
200 | |
201 @Override | |
202 public void onSettingsAckRead(ChannelHandlerContext ctx) throws Http2Excepti on {} | |
203 | |
204 @Override | |
205 public void onSettingsRead(ChannelHandlerContext ctx, Http2Settings settings ) | |
206 throws Http2Exception {} | |
207 | |
208 @Override | |
209 public void onPingRead(ChannelHandlerContext ctx, ByteBuf data) throws Http2 Exception {} | |
210 | |
211 @Override | |
212 public void onPingAckRead(ChannelHandlerContext ctx, ByteBuf data) throws Ht tp2Exception {} | |
213 | |
214 @Override | |
215 public void onPushPromiseRead(ChannelHandlerContext ctx, int streamId, int p romisedStreamId, | |
216 Http2Headers headers, int padding) throws Http2Exception {} | |
217 | |
218 @Override | |
219 public void onGoAwayRead(ChannelHandlerContext ctx, int lastStreamId, long e rrorCode, | |
220 ByteBuf debugData) throws Http2Exception {} | |
221 | |
222 @Override | |
223 public void onWindowUpdateRead(ChannelHandlerContext ctx, int streamId, int windowSizeIncrement) | |
224 throws Http2Exception {} | |
225 | |
226 @Override | |
227 public void onUnknownFrame(ChannelHandlerContext ctx, byte frameType, int st reamId, | |
228 Http2Flags flags, ByteBuf payload) throws Http2Exception {} | |
229 } | |
OLD | NEW |