@Override public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception { logger.debug("================进入客户端InBoundHandler channelRead============"); // 如果是response if (msg instanceof HttpResponse) { HttpResponse response = (HttpResponse) msg; logger.debug( "客户端收到的响应CONTENT_TYPE:" + response.headers().get(HttpHeaders.Names.CONTENT_TYPE)); if (HttpHeaders.isContentLengthSet(response)) { reader = new ByteBufToBytes((int) HttpHeaders.getContentLength(response)); } } if (msg instanceof HttpContent) { HttpContent httpContent = (HttpContent) msg; ByteBuf content = httpContent.content(); reader.reading(content); content.release(); if (reader.isEnd()) { String resultStr = new String(reader.readFull()); logger.debug("收到的服务端的消息是:" + resultStr); ctx.close(); } } logger.debug("================出客户端InBoundHandler channelRead============"); }
@Test public void clientRequestMultipleEmptyDataFrames() throws Exception { final String text = ""; final ByteBuf content = Unpooled.copiedBuffer(text.getBytes()); final FullHttpRequest request = new DefaultFullHttpRequest( HttpVersion.HTTP_1_1, HttpMethod.GET, "/some/path/resource2", content, true); try { HttpHeaders httpHeaders = request.headers(); httpHeaders.set(HttpUtil.ExtensionHeaderNames.STREAM_ID.text(), 3); httpHeaders.set(HttpHeaders.Names.CONTENT_LENGTH, text.length()); final Http2Headers http2Headers = new DefaultHttp2Headers().method(as("GET")).path(as("/some/path/resource2")); runInChannel( clientChannel, new Http2Runnable() { @Override public void run() { frameWriter.writeHeaders(ctxClient(), 3, http2Headers, 0, false, newPromiseClient()); frameWriter.writeData(ctxClient(), 3, content.retain(), 0, false, newPromiseClient()); frameWriter.writeData(ctxClient(), 3, content.retain(), 0, false, newPromiseClient()); frameWriter.writeData(ctxClient(), 3, content.retain(), 0, true, newPromiseClient()); ctxClient().flush(); } }); awaitRequests(); ArgumentCaptor<FullHttpMessage> requestCaptor = ArgumentCaptor.forClass(FullHttpMessage.class); verify(serverListener).messageReceived(requestCaptor.capture()); capturedRequests = requestCaptor.getAllValues(); assertEquals(request, capturedRequests.get(0)); } finally { request.release(); } }
@Test public void testLastResponseWithTrailingHeader() { EmbeddedChannel ch = new EmbeddedChannel(new HttpResponseDecoder()); ch.writeInbound( Unpooled.copiedBuffer( "HTTP/1.1 200 OK\r\n" + "Transfer-Encoding: chunked\r\n" + "\r\n" + "0\r\n" + "Set-Cookie: t1=t1v1\r\n" + "Set-Cookie: t2=t2v2; Expires=Wed, 09-Jun-2021 10:18:14 GMT\r\n" + "\r\n", CharsetUtil.US_ASCII)); HttpResponse res = ch.readInbound(); assertThat(res.getProtocolVersion(), sameInstance(HttpVersion.HTTP_1_1)); assertThat(res.getStatus(), is(HttpResponseStatus.OK)); LastHttpContent lastContent = ch.readInbound(); assertThat(lastContent.content().isReadable(), is(false)); HttpHeaders headers = lastContent.trailingHeaders(); assertEquals(1, headers.names().size()); List<String> values = headers.getAll("Set-Cookie"); assertEquals(2, values.size()); assertTrue(values.contains("t1=t1v1")); assertTrue(values.contains("t2=t2v2; Expires=Wed, 09-Jun-2021 10:18:14 GMT")); lastContent.release(); assertThat(ch.finish(), is(false)); assertThat(ch.readInbound(), is(nullValue())); }
@Override public void send(final FileChannel channel) throws Exception { long len = channel.size(); DefaultHttpResponse rsp = new DefaultHttpResponse(HttpVersion.HTTP_1_1, status); if (!headers.contains(HttpHeaderNames.CONTENT_LENGTH)) { headers.remove(HttpHeaderNames.TRANSFER_ENCODING); headers.set(HttpHeaderNames.CONTENT_LENGTH, len); } if (keepAlive) { headers.set(HttpHeaderNames.CONNECTION, HttpHeaderValues.KEEP_ALIVE); } // dump headers rsp.headers().set(headers); ChannelHandlerContext ctx = this.ctx; ctx.attr(NettyRequest.NEED_FLUSH).set(false); ctx.channel() .eventLoop() .execute( () -> { // send headers ctx.write(rsp); ctx.write(new DefaultFileRegion(channel, 0, len)); keepAlive(ctx.writeAndFlush(LastHttpContent.EMPTY_LAST_CONTENT)); }); committed = true; }
private boolean exitAfterHandler( Channel channel, NettyResponseFuture<?> future, HttpResponse response, AsyncHandler<?> handler, NettyResponseStatus status, HttpRequest httpRequest, HttpResponseHeaders responseHeaders) throws IOException, Exception { boolean exit = exitAfterHandlingStatus(channel, future, response, handler, status, httpRequest) || // exitAfterHandlingHeaders( channel, future, response, handler, responseHeaders, httpRequest) || // exitAfterHandlingReactiveStreams(channel, future, response, handler, httpRequest); if (exit) finishUpdate( future, channel, HttpHeaders.isTransferEncodingChunked(httpRequest) || HttpHeaders.isTransferEncodingChunked(response)); return exit; }
private void send(final ByteBuf buffer) throws Exception { DefaultFullHttpResponse rsp = new DefaultFullHttpResponse(HttpVersion.HTTP_1_1, status, buffer); if (!headers.contains(HttpHeaderNames.CONTENT_LENGTH)) { headers .remove(HttpHeaderNames.TRANSFER_ENCODING) .set(HttpHeaderNames.CONTENT_LENGTH, buffer.readableBytes()); } if (keepAlive) { headers.set(HttpHeaderNames.CONNECTION, HttpHeaderValues.KEEP_ALIVE); } // dump headers rsp.headers().set(headers); Attribute<Boolean> async = ctx.attr(NettyRequest.ASYNC); boolean isAsync = async != null && async.get() == Boolean.TRUE; if (isAsync) { // we need flush, from async keepAlive(ctx.writeAndFlush(rsp)); } else { keepAlive(ctx.write(rsp)); } committed = true; }
@Test(groups = "online") public void asyncOptionsTest() throws Exception { final AtomicReference<HttpHeaders> responseHeaders = new AtomicReference<>(); try (AsyncHttpClient c = asyncHttpClient()) { final String[] expected = {"GET", "HEAD", "OPTIONS", "POST", "TRACE"}; Future<String> f = c.prepareOptions("http://www.apache.org/") .execute( new AsyncHandlerAdapter() { @Override public State onHeadersReceived(HttpResponseHeaders content) throws Exception { responseHeaders.set(content.getHeaders()); return State.ABORT; } @Override public String onCompleted() throws Exception { return "OK"; } }); f.get(20, TimeUnit.SECONDS); HttpHeaders h = responseHeaders.get(); assertNotNull(h); String[] values = h.get(HttpHeaders.Names.ALLOW).split(",|, "); assertNotNull(values); assertEquals(values.length, expected.length); Arrays.sort(values); assertEquals(values, expected); } }
/** * Sets the value of response headers after making sure that the response metadata is not already * sent. * * @param headerName The name of the header. * @param headerValue The intended value of the header. * @throws IllegalArgumentException if any of {@code headerName} or {@code headerValue} is null. * @throws IllegalStateException if response metadata has already been written to the channel. */ private void setResponseHeader(String headerName, Object headerValue) { if (headerName != null && headerValue != null) { long startTime = System.currentTimeMillis(); if (headerValue instanceof Date) { HttpHeaders.setDateHeader(responseMetadata, headerName, (Date) headerValue); } else { HttpHeaders.setHeader(responseMetadata, headerName, headerValue); } if (responseMetadataWritten.get()) { nettyMetrics.deadResponseAccessError.inc(); throw new IllegalStateException( "Response metadata changed after it has already been written to the channel"); } else { logger.trace( "Header {} set to {} for channel {}", headerName, responseMetadata.headers().get(headerName), ctx.channel()); nettyMetrics.headerSetTimeInMs.update(System.currentTimeMillis() - startTime); } } else { throw new IllegalArgumentException( "Header name [" + headerName + "] or header value [" + headerValue + "] null"); } }
private void ntlmChallenge( String authenticateHeader, // Request request, // HttpHeaders headers, // Realm realm, // NettyResponseFuture<?> future) { if (authenticateHeader.equals("NTLM")) { // server replied bare NTLM => we didn't preemptively sent Type1Msg String challengeHeader = NtlmEngine.INSTANCE.generateType1Msg(); // FIXME we might want to filter current NTLM and add (leave other // Authorization headers untouched) headers.set(HttpHeaders.Names.AUTHORIZATION, "NTLM " + challengeHeader); future.getInAuth().set(false); } else { String serverChallenge = authenticateHeader.substring("NTLM ".length()).trim(); String challengeHeader = NtlmEngine.INSTANCE.generateType3Msg( realm.getPrincipal(), realm.getPassword(), realm.getNtlmDomain(), realm.getNtlmHost(), serverChallenge); // FIXME we might want to filter current NTLM and add (leave other // Authorization headers untouched) headers.set(HttpHeaders.Names.AUTHORIZATION, "NTLM " + challengeHeader); } }
private static FullHttpRequest createHttpRequest(int spdyVersion, SpdyHeaderBlock requestFrame) throws Exception { // Create the first line of the request from the name/value pairs HttpMethod method = SpdyHeaders.getMethod(spdyVersion, requestFrame); String url = SpdyHeaders.getUrl(spdyVersion, requestFrame); HttpVersion httpVersion = SpdyHeaders.getVersion(spdyVersion, requestFrame); SpdyHeaders.removeMethod(spdyVersion, requestFrame); SpdyHeaders.removeUrl(spdyVersion, requestFrame); SpdyHeaders.removeVersion(spdyVersion, requestFrame); FullHttpRequest req = new DefaultFullHttpRequest(httpVersion, method, url); // Remove the scheme header SpdyHeaders.removeScheme(spdyVersion, requestFrame); if (spdyVersion >= 3) { // Replace the SPDY host header with the HTTP host header String host = SpdyHeaders.getHost(requestFrame); SpdyHeaders.removeHost(requestFrame); HttpHeaders.setHost(req, host); } for (Map.Entry<String, String> e : requestFrame.headers().entries()) { req.headers().add(e.getKey(), e.getValue()); } // The Connection and Keep-Alive headers are no longer valid HttpHeaders.setKeepAlive(req, true); // Transfer-Encoding header is not valid req.headers().remove(HttpHeaders.Names.TRANSFER_ENCODING); return req; }
/** * Writes response metadata to the channel if not already written previously and channel is * active. * * @param responseMetadata the {@link HttpResponse} that needs to be written. * @param listener the {@link GenericFutureListener} that needs to be attached to the write. * @return {@code true} if response metadata was written to the channel in this call. {@code * false} otherwise. */ private boolean maybeWriteResponseMetadata( HttpResponse responseMetadata, GenericFutureListener<ChannelFuture> listener) { long writeProcessingStartTime = System.currentTimeMillis(); boolean writtenThisTime = false; if (responseMetadataWritten.compareAndSet(false, true)) { // we do some manipulation here for chunking. According to the HTTP spec, we can have either a // Content-Length // or Transfer-Encoding:chunked, never both. So we check for Content-Length - if it is not // there, we add // Transfer-Encoding:chunked. Note that sending HttpContent chunks data anyway - we are just // explicitly specifying // this in the header. if (!HttpHeaders.isContentLengthSet(responseMetadata)) { // This makes sure that we don't stomp on any existing transfer-encoding. HttpHeaders.setTransferEncodingChunked(responseMetadata); } logger.trace( "Sending response with status {} on channel {}", responseMetadata.getStatus(), ctx.channel()); ChannelPromise writePromise = ctx.newPromise().addListener(listener); ctx.writeAndFlush(responseMetadata, writePromise); writtenThisTime = true; long writeProcessingTime = System.currentTimeMillis() - writeProcessingStartTime; nettyMetrics.responseMetadataProcessingTimeInMs.update(writeProcessingTime); } return writtenThisTime; }
private void handleChunk( HttpContent chunk, // final Channel channel, // final NettyResponseFuture<?> future, // AsyncHandler<?> handler) throws IOException, Exception { boolean interrupt = false; boolean last = chunk instanceof LastHttpContent; // Netty 4: the last chunk is not empty if (last) { LastHttpContent lastChunk = (LastHttpContent) chunk; HttpHeaders trailingHeaders = lastChunk.trailingHeaders(); if (!trailingHeaders.isEmpty()) { interrupt = handler.onHeadersReceived(new HttpResponseHeaders(trailingHeaders, true)) != State.CONTINUE; } } ByteBuf buf = chunk.content(); if (!interrupt && !(handler instanceof StreamedAsyncHandler) && (buf.readableBytes() > 0 || last)) { HttpResponseBodyPart part = config.getResponseBodyPartFactory().newResponseBodyPart(buf, last); interrupt = updateBodyAndInterrupt(future, handler, part); } if (interrupt || last) finishUpdate(future, channel, !last); }
private static void testLastResponseWithTrailingHeaderFragmented( byte[] content, int fragmentSize) { EmbeddedChannel ch = new EmbeddedChannel(new HttpResponseDecoder()); int headerLength = 47; // split up the header for (int a = 0; a < headerLength; ) { int amount = fragmentSize; if (a + amount > headerLength) { amount = headerLength - a; } // if header is done it should produce a HttpRequest boolean headerDone = a + amount == headerLength; assertEquals(headerDone, ch.writeInbound(Unpooled.wrappedBuffer(content, a, amount))); a += amount; } ch.writeInbound(Unpooled.wrappedBuffer(content, headerLength, content.length - headerLength)); HttpResponse res = ch.readInbound(); assertThat(res.getProtocolVersion(), sameInstance(HttpVersion.HTTP_1_1)); assertThat(res.getStatus(), is(HttpResponseStatus.OK)); LastHttpContent lastContent = ch.readInbound(); assertThat(lastContent.content().isReadable(), is(false)); HttpHeaders headers = lastContent.trailingHeaders(); assertEquals(1, headers.names().size()); List<String> values = headers.getAll("Set-Cookie"); assertEquals(2, values.size()); assertTrue(values.contains("t1=t1v1")); assertTrue(values.contains("t2=t2v2; Expires=Wed, 09-Jun-2021 10:18:14 GMT")); lastContent.release(); assertThat(ch.finish(), is(false)); assertThat(ch.readInbound(), is(nullValue())); }
private void encodeChunkedContent( ChannelHandlerContext ctx, Object msg, int contentLength, List<Object> out) { if (contentLength > 0) { byte[] length = Integer.toHexString(contentLength).getBytes(CharsetUtil.US_ASCII); ByteBuf buf = ctx.alloc().buffer(length.length + 2); buf.writeBytes(length); buf.writeBytes(CRLF); out.add(buf); out.add(encodeAndRetain(msg)); out.add(CRLF_BUF.duplicate()); } if (msg instanceof LastHttpContent) { HttpHeaders headers = ((LastHttpContent) msg).trailingHeaders(); if (headers.isEmpty()) { out.add(ZERO_CRLF_CRLF_BUF.duplicate()); } else { ByteBuf buf = ctx.alloc().buffer(); buf.writeBytes(ZERO_CRLF); HttpHeaders.encode(headers, buf); buf.writeBytes(CRLF); out.add(buf); } state = ST_INIT; } else { if (contentLength == 0) { // Need to produce some output otherwise an // IllegalstateException will be thrown out.add(EMPTY_BUFFER); } } }
/** * Verifies User metadata headers from output, to that sent in during input * * @param expectedHeaders the expected headers in the response. * @param response the {@link HttpResponse} which contains the headers of the response. * @param usermetadata if non-null, this is expected to come as the body. * @param content the content accompanying the response. */ private void verifyUserMetadata( HttpHeaders expectedHeaders, HttpResponse response, byte[] usermetadata, Queue<HttpObject> content) { if (usermetadata == null) { assertEquals("Content-Length is not 0", 0, HttpHeaders.getContentLength(response)); for (Map.Entry<String, String> header : expectedHeaders) { String key = header.getKey(); if (key.startsWith(RestUtils.Headers.USER_META_DATA_HEADER_PREFIX)) { assertEquals( "Value for " + key + " does not match in user metadata", header.getValue(), HttpHeaders.getHeader(response, key)); } } for (Map.Entry<String, String> header : response.headers()) { String key = header.getKey(); if (key.startsWith(RestUtils.Headers.USER_META_DATA_HEADER_PREFIX)) { assertTrue( "Key " + key + " does not exist in expected headers", expectedHeaders.contains(key)); } } discardContent(content, 1); } else { assertEquals( "Content-Length is not as expected", usermetadata.length, HttpHeaders.getContentLength(response)); byte[] receivedMetadata = getContent(content, HttpHeaders.getContentLength(response)).array(); assertArrayEquals("User metadata does not match original", usermetadata, receivedMetadata); } }
public void run() throws Exception { EventLoopGroup group = new NioEventLoopGroup(); try { Bootstrap b = new Bootstrap(); String protocol = uri.getScheme(); if (!"ws".equals(protocol)) { throw new IllegalArgumentException("Unsupported protocol: " + protocol); } HttpHeaders customHeaders = new DefaultHttpHeaders(); customHeaders.add("MyHeader", "MyValue"); // Connect with V13 (RFC 6455 aka HyBi-17). You can change it to V08 or V00. // If you change it to V00, ping is not supported and remember to change // HttpResponseDecoder to WebSocketHttpResponseDecoder in the pipeline. final WebSocketClientHandler handler = new WebSocketClientHandler( WebSocketClientHandshakerFactory.newHandshaker( uri, WebSocketVersion.V13, null, false, customHeaders)); b.group(group) .channel(NioSocketChannel.class) .handler( new ChannelInitializer<SocketChannel>() { @Override public void initChannel(SocketChannel ch) throws Exception { ChannelPipeline pipeline = ch.pipeline(); pipeline.addLast("http-codec", new HttpClientCodec()); pipeline.addLast("aggregator", new HttpObjectAggregator(8192)); pipeline.addLast("ws-handler", handler); } }); System.out.println("WebSocket Client connecting"); Channel ch = b.connect(uri.getHost(), uri.getPort()).sync().channel(); handler.handshakeFuture().sync(); // Send 10 messages and wait for responses System.out.println("WebSocket Client sending message"); for (int i = 0; i < 10; i++) { ch.writeAndFlush(new TextWebSocketFrame("Message #" + i)); } // Ping System.out.println("WebSocket Client sending ping"); ch.writeAndFlush( new PingWebSocketFrame(Unpooled.copiedBuffer(new byte[] {1, 2, 3, 4, 5, 6}))); // Close System.out.println("WebSocket Client sending close"); ch.writeAndFlush(new CloseWebSocketFrame()); // WebSocketClientHandler will close the connection when the server // responds to the CloseWebSocketFrame. ch.closeFuture().sync(); } finally { group.shutdownGracefully(); } }
protected void setCookie(FullHttpResponse response) { // Set<Cookie> cookies = CookieDecoder.decode(MessageFormat.format(COOKIE, sessionId)); Set<Cookie> cookies = CookieDecoder.decode(sessionId); HttpHeaders headers = response.headers(); for (Cookie cookie : cookies) { headers.add(HttpHeaders.Names.SET_COOKIE, ServerCookieEncoder.encode(cookie)); } }
/** * Gets the blob with blob ID {@code blobId} and verifies that the headers and content match with * what is expected. * * @param blobId the blob ID of the blob to GET. * @param range the {@link ByteRange} for the request. * @param expectedHeaders the expected headers in the response. * @param expectedContent the expected content of the blob. * @throws ExecutionException * @throws InterruptedException */ private void getBlobAndVerify( String blobId, ByteRange range, HttpHeaders expectedHeaders, ByteBuffer expectedContent) throws ExecutionException, InterruptedException, RestServiceException { HttpHeaders headers = null; if (range != null) { headers = new DefaultHttpHeaders() .add(RestUtils.Headers.RANGE, RestTestUtils.getRangeHeaderString(range)); } FullHttpRequest httpRequest = buildRequest(HttpMethod.GET, blobId, headers, null); Queue<HttpObject> responseParts = nettyClient.sendRequest(httpRequest, null, null).get(); HttpResponse response = (HttpResponse) responseParts.poll(); assertEquals( "Unexpected response status", range == null ? HttpResponseStatus.OK : HttpResponseStatus.PARTIAL_CONTENT, response.getStatus()); checkCommonGetHeadHeaders(response.headers()); assertEquals( "Content-Type does not match", expectedHeaders.get(RestUtils.Headers.AMBRY_CONTENT_TYPE), response.headers().get(HttpHeaders.Names.CONTENT_TYPE)); assertEquals( RestUtils.Headers.BLOB_SIZE + " does not match", expectedHeaders.get(RestUtils.Headers.BLOB_SIZE), response.headers().get(RestUtils.Headers.BLOB_SIZE)); assertEquals( "Accept-Ranges not set correctly", "bytes", response.headers().get(RestUtils.Headers.ACCEPT_RANGES)); byte[] expectedContentArray = expectedContent.array(); if (range != null) { long blobSize = Long.parseLong(expectedHeaders.get(RestUtils.Headers.BLOB_SIZE)); assertEquals( "Content-Range header not set correctly", RestUtils.buildContentRangeAndLength(range, blobSize).getFirst(), response.headers().get(RestUtils.Headers.CONTENT_RANGE)); ByteRange resolvedRange = range.toResolvedByteRange(blobSize); expectedContentArray = Arrays.copyOfRange( expectedContentArray, (int) resolvedRange.getStartOffset(), (int) resolvedRange.getEndOffset() + 1); } else { assertNull( "Content-Range header should not be set", response.headers().get(RestUtils.Headers.CONTENT_RANGE)); } if (expectedContentArray.length < FRONTEND_CONFIG.frontendChunkedGetResponseThresholdInBytes) { assertEquals( "Content-length not as expected", expectedContentArray.length, HttpHeaders.getContentLength(response)); } byte[] responseContentArray = getContent(responseParts, expectedContentArray.length).array(); assertArrayEquals( "GET content does not match original content", expectedContentArray, responseContentArray); assertTrue("Channel should be active", HttpHeaders.isKeepAlive(response)); }
public static void newHttpClientBootstrap(String url, ChannelHandler handler) throws Exception { URI uri = new URI(url); String scheme = uri.getScheme() == null ? "http" : uri.getScheme(); String host = uri.getHost() == null ? "127.0.0.1" : uri.getHost(); int port = uri.getPort(); if (port == -1) { if ("http".equalsIgnoreCase(scheme)) { port = 80; } else if ("https".equalsIgnoreCase(scheme)) { port = 443; } } if (!"http".equalsIgnoreCase(scheme) && !"https".equalsIgnoreCase(scheme)) { System.err.println("Only HTTP(S) is supported."); return; } // Configure SSL context if necessary. final boolean ssl = "https".equalsIgnoreCase(scheme); final SslContext sslCtx; if (ssl) { sslCtx = SslContext.newClientContext(InsecureTrustManagerFactory.INSTANCE); } else { sslCtx = null; } // Configure the client. EventLoopGroup group = new NioEventLoopGroup(); try { Bootstrap b = new Bootstrap(); b.group(group) .channel(NioSocketChannel.class) .handler(new HttpDownloadertInitializer(sslCtx, handler)); // Make the connection attempt. Channel ch = b.connect(host, port).sync().channel(); // Prepare the HTTP request. HttpRequest request = new DefaultFullHttpRequest(HttpVersion.HTTP_1_1, HttpMethod.GET, uri.getRawPath()); HttpHeaders headers = request.headers(); headers.set(HttpHeaders.Names.HOST, host); headers.set(HttpHeaders.Names.CONNECTION, HttpHeaders.Values.CLOSE); headers.set(HttpHeaders.Names.ACCEPT_ENCODING, HttpHeaders.Values.GZIP); // Set some example cookies. headers.set( HttpHeaders.Names.COOKIE, ClientCookieEncoder.encode(new DefaultCookie("my-cookie", "foo"))); ch.writeAndFlush(request); // Wait for the server to close the connection. ch.closeFuture().sync(); Thread.sleep(1000); } finally { // Shut down executor threads to exit. group.shutdownGracefully(); } }
private void write(XHROptionsMessage msg, ChannelHandlerContext ctx, ChannelPromise promise) { HttpResponse res = new DefaultHttpResponse(HTTP_1_1, HttpResponseStatus.OK); HttpHeaders.addHeader(res, "Set-Cookie", "io=" + msg.getSessionId()); HttpHeaders.addHeader(res, CONNECTION, KEEP_ALIVE); HttpHeaders.addHeader(res, ACCESS_CONTROL_ALLOW_HEADERS, CONTENT_TYPE); addOriginHeaders(ctx.channel(), res); ByteBuf out = encoder.allocateBuffer(ctx.alloc()); sendMessage(msg, ctx.channel(), out, res, promise); }
@Override protected void channelRead0(ChannelHandlerContext ctx, FullHttpMessage msg) throws Exception { // 1 // Request header 처리 if (msg instanceof HttpRequest) { // 2 this.request = (HttpRequest) msg; // 3 if (HttpHeaders.is100ContinueExpected(request)) { send100Continue(ctx); } HttpHeaders headers = request.headers(); // 4 if (!headers.isEmpty()) { for (Map.Entry<String, String> h : headers) { String key = h.getKey(); if (usingHeader.contains(key)) { // 5 reqData.put(key, h.getValue()); // 6 } } } reqData.put("REQUEST_URI", request.getUri()); // 7 reqData.put("REQUEST_METHOD", request.getMethod().name()); // 8 } if (msg instanceof HttpContent) { // 9 HttpContent httpContent = (HttpContent) msg; // 10 ByteBuf content = httpContent.content(); // 11 if (msg instanceof LastHttpContent) { // 12 System.out.println("LastHttpContent message received!!" + request.getUri()); LastHttpContent trailer = (LastHttpContent) msg; readPostData(); // 13 ApiRequest service = ServiceDispatcher.dispatch(reqData); // 14 try { service.executeService(); // 15 apiResult = service.getApiResult(); // 16 } finally { reqData.clear(); } if (!writeResponse(trailer, ctx)) { // 17 ctx.writeAndFlush(Unpooled.EMPTY_BUFFER).addListener(ChannelFutureListener.CLOSE); } reset(); } } }
/** * Verifies that a request returns the right response code once the blob has been deleted. * * @param httpRequest the {@link FullHttpRequest} to send to the server. * @param expectedStatusCode the expected {@link HttpResponseStatus}. * @throws ExecutionException * @throws InterruptedException */ private void verifyDeleted(FullHttpRequest httpRequest, HttpResponseStatus expectedStatusCode) throws ExecutionException, InterruptedException { Queue<HttpObject> responseParts = nettyClient.sendRequest(httpRequest, null, null).get(); HttpResponse response = (HttpResponse) responseParts.poll(); assertEquals("Unexpected response status", expectedStatusCode, response.getStatus()); assertTrue( "No Date header", HttpHeaders.getDateHeader(response, HttpHeaders.Names.DATE, null) != null); discardContent(responseParts, 1); assertTrue("Channel should be active", HttpHeaders.isKeepAlive(response)); }
@Override protected void channelRead0(ChannelHandlerContext ctx, final Object msg) throws Exception { if (msg instanceof HttpMessage) { logger.debug("Adding no cache headers"); HttpHeaders headers = ((HttpMessage) msg).headers(); headers.set("Cache-Control", "no-cache, no-store, must-revalidate"); headers.set("Pragma", "no-cache"); headers.set("Expires", "0"); } inboundChannel.writeAndFlush(msg); }
@Override public void send(final InputStream stream) throws Exception { byte[] chunk = new byte[bufferSize]; int count = ByteStreams.read(stream, chunk, 0, bufferSize); if (count <= 0) { return; } ByteBuf buffer = Unpooled.wrappedBuffer(chunk, 0, count); if (count < bufferSize) { send(buffer); } else { DefaultHttpResponse rsp = new DefaultHttpResponse(HttpVersion.HTTP_1_1, status); if (!headers.contains(HttpHeaderNames.CONTENT_LENGTH)) { headers.set(HttpHeaderNames.TRANSFER_ENCODING, HttpHeaderValues.CHUNKED); } else { if (keepAlive) { headers.set(HttpHeaderNames.CONNECTION, HttpHeaderValues.KEEP_ALIVE); } } // dump headers rsp.headers().set(headers); ChannelHandlerContext ctx = this.ctx; ctx.attr(NettyRequest.NEED_FLUSH).set(false); // add chunker ChannelPipeline pipeline = ctx.pipeline(); if (pipeline.get("chunker") == null) { pipeline.addAfter("encoder", "chunker", new ChunkedWriteHandler()); } // group all write ctx.channel() .eventLoop() .execute( () -> { // send headers ctx.write(rsp); // send head chunk ctx.write(buffer); // send tail ctx.write(new ChunkedStream(stream, bufferSize)); keepAlive(ctx.writeAndFlush(LastHttpContent.EMPTY_LAST_CONTENT)); }); } committed = true; }
protected void processHeadRequest( ChannelHandlerContext channelHandlerContext, FullHttpRequest fullHttpRequest) { if (_logger.isTraceEnabled()) { Channel channel = channelHandlerContext.channel(); _logger.trace( "Client {}: processing head request {}", channel.remoteAddress(), fullHttpRequest.uri()); } SyncFile syncFile = _getSyncFile(fullHttpRequest); if (syncFile == null) { _sendError(channelHandlerContext, NOT_FOUND); return; } String lanTokenKey = syncFile.getLanTokenKey(); if ((lanTokenKey == null) || lanTokenKey.isEmpty()) { _sendError(channelHandlerContext, NOT_FOUND); return; } String encryptedToken = null; try { encryptedToken = LanTokenUtil.createEncryptedToken(lanTokenKey); } catch (Exception e) { _sendError(channelHandlerContext, NOT_FOUND); return; } HttpResponse httpResponse = new DefaultFullHttpResponse(HTTP_1_1, OK); HttpHeaders httpHeaders = httpResponse.headers(); httpHeaders.set("connectionsCount", _syncTrafficShapingHandler.getConnectionsCount()); httpHeaders.set("downloadRate", _trafficCounter.lastWrittenBytes()); httpHeaders.set("encryptedToken", encryptedToken); httpHeaders.set("maxConnections", PropsValues.SYNC_LAN_SERVER_MAX_CONNECTIONS); channelHandlerContext.writeAndFlush(httpResponse); }
public void sendError() { if (request == null || status == null || shortDescription == null || detailedDescription == null || version == null || status == null) throw new IllegalStateException(); StringBuffer sb = new StringBuffer(); sb.append("Error ").append(status.code()).append(": ").append(shortDescription); sb.append("\n\n"); sb.append(detailedDescription); sb.append("\n\n"); sb.append("Request:\n").append(request.getUri()); sb.append("\n\n"); sb.append("Request Submitted:\n").append(FdsnwsDate.toString(new Date())); sb.append("\n\n"); sb.append("Service version:\n").append(version); String html = sb.toString(); FullHttpResponse response = new DefaultFullHttpResponse( request.getProtocolVersion(), status, Unpooled.copiedBuffer(html, Charset.forName("UTF-8"))); response.headers().set(HttpHeaders.Names.CONTENT_LENGTH, html.length()); response.headers().set(HttpHeaders.Names.CONTENT_TYPE, "text/plain; charset=UTF-8"); if (HttpHeaders.isKeepAlive(request)) { response.headers().set(HttpHeaders.Names.CONNECTION, HttpHeaders.Values.KEEP_ALIVE); } ctx.writeAndFlush(response); }
private static void sendHttpResponse( ChannelHandlerContext ctx, FullHttpRequest req, FullHttpResponse res) { // Generate an error page if response getStatus code is not OK (200). if (res.getStatus().code() != 200) { ByteBuf buf = Unpooled.copiedBuffer(res.getStatus().toString(), CharsetUtil.UTF_8); res.content().writeBytes(buf); buf.release(); HttpHeaders.setContentLength(res, res.content().readableBytes()); } // Send the response and close the connection if necessary. ChannelFuture f = ctx.channel().writeAndFlush(res); if (!HttpHeaders.isKeepAlive(req) || res.getStatus().code() != 200) { f.addListener(ChannelFutureListener.CLOSE); } }
void encode(ByteBuf buf) { if (bytes == null) { HttpHeaders.encodeAscii0(name, buf); } else { buf.writeBytes(bytes); } }
@Override public String toString() { StringBuilder sb = new StringBuilder(getUrl()); sb.append("\t"); sb.append(method); sb.append("\theaders:"); if (!headers.isEmpty()) { for (Map.Entry<String, String> header : headers) { sb.append("\t"); sb.append(header.getKey()); sb.append(":"); sb.append(header.getValue()); } } if (isNonEmpty(formParams)) { sb.append("\tformParams:"); for (Param param : formParams) { sb.append("\t"); sb.append(param.getName()); sb.append(":"); sb.append(param.getValue()); } } return sb.toString(); }
/** * Sets the value of the {@code "Connection"} header depending on the protocol version of the * specified message. This getMethod sets or removes the {@code "Connection"} header depending on * what the default keep alive mode of the message's protocol version is, as specified by {@link * HttpVersion#isKeepAliveDefault()}. * * <ul> * <li>If the connection is kept alive by default: * <ul> * <li>set to {@code "close"} if {@code keepAlive} is {@code false}. * <li>remove otherwise. * </ul> * <li>If the connection is closed by default: * <ul> * <li>set to {@code "keep-alive"} if {@code keepAlive} is {@code true}. * <li>remove otherwise. * </ul> * </ul> */ public static void setKeepAlive(HttpMessage message, boolean keepAlive) { HttpHeaders h = message.headers(); if (message.getProtocolVersion().isKeepAliveDefault()) { if (keepAlive) { h.remove(Names.CONNECTION); } else { h.set(Names.CONNECTION, Values.CLOSE); } } else { if (keepAlive) { h.set(Names.CONNECTION, Values.KEEP_ALIVE); } else { h.remove(Names.CONNECTION); } } }