private void encodeChunkedContent(ChannelHandlerContext ctx, Object msg, long contentLength, List<Object> out) { if (contentLength > 0) { String lengthHex = Long.toHexString(contentLength); ByteBuf buf = ctx.alloc().buffer(lengthHex.length() + 2); buf.writeCharSequence(lengthHex, CharsetUtil.US_ASCII); ByteBufUtil.writeShortBE(buf, CRLF_SHORT); 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((int) trailersEncodedSizeAccumulator); ByteBufUtil.writeMediumBE(buf, ZERO_CRLF_MEDIUM); encodeHeaders(headers, buf); ByteBufUtil.writeShortBE(buf, CRLF_SHORT); trailersEncodedSizeAccumulator = TRAILERS_WEIGHT_NEW * padSizeForAccumulation(buf.readableBytes()) + TRAILERS_WEIGHT_HISTORICAL * trailersEncodedSizeAccumulator; out.add(buf); } } else if (contentLength == 0) { // Need to produce some output otherwise an // IllegalStateException will be thrown out.add(encodeAndRetain(msg)); } }
private void encodeLastContent(LastHttpContent last, List<Object> out) { boolean needFiller = !(last instanceof FullHttpMessage) && last.trailingHeaders().isEmpty(); if (last.content().isReadable() || needFiller) { out.add(new DefaultHttp2DataFrame(last.content().retain(), last.trailingHeaders().isEmpty())); } if (!last.trailingHeaders().isEmpty()) { Http2Headers headers = HttpConversionUtil.toHttp2Headers(last.trailingHeaders(), validateHeaders); out.add(new DefaultHttp2HeadersFrame(headers, true)); } }
final String contentLengthStr = nettyHeaders.get(HttpHeaderNames.CONTENT_LENGTH); final boolean contentEmpty; if (contentLengthStr != null) { ctx.pipeline().fireUserEventTriggered(HttpExpectationFailedEvent.INSTANCE); fail(id, HttpResponseStatus.EXPECTATION_FAILED); return; nettyHeaders.set(ExtensionHeaderNames.SCHEME.text(), scheme); ctx.channel().eventLoop(), id, 1, ArmeriaHttpUtil.toArmeria(nettyReq), final DecoderResult decoderResult = content.decoderResult(); if (!decoderResult.isSuccess()) { fail(id, HttpResponseStatus.BAD_REQUEST); final ByteBuf data = content.content(); final int dataLength = data.readableBytes(); if (dataLength != 0) { req.increaseTransferredBytes(dataLength); req.write(new ByteBufHttpData(data.retain(), false)); final HttpHeaders trailingHeaders = ((LastHttpContent) msg).trailingHeaders(); if (!trailingHeaders.isEmpty()) { req.write(ArmeriaHttpUtil.toArmeria(trailingHeaders));
ctx.channel().attr(ClientRequestResponseConverter.DISCARD_CONNECTION).set(true); // SSE traffic should always discard connection on close. ChannelPipeline pipeline = ctx.channel().pipeline(); pipeline.addAfter(NAME, SSE_DECODER_HANDLER_NAME, new ServerSentEventDecoder()); ctx.fireChannelRead(msg); } else if (msg instanceof LastHttpContent) { LastHttpContent lastHttpContent = (LastHttpContent) msg; lastHttpContent.content().retain(); // pseudo retain so that the last handler of the pipeline can release it. if (lastHttpContent.content().isReadable()) { ctx.fireChannelRead(lastHttpContent.content()); ctx.fireChannelRead(((HttpContent) msg).content()); } else { ctx.fireChannelRead(msg);
ctx.write(msg, promise); return; new SimpleChannelPromiseAggregator(promise, ctx.channel(), ctx.executor()); try { Http2ConnectionEncoder encoder = encoder(); endStream = msg instanceof FullHttpMessage && !((FullHttpMessage) msg).content().isReadable(); writeHeaders(ctx, encoder, currentStreamId, httpMsg.headers(), http2Headers, endStream, promiseAggregator); trailers = lastContent.trailingHeaders(); http2Trailers = HttpConversionUtil.toHttp2Headers(trailers, validateHeaders); final ByteBuf content = ((HttpContent) msg).content(); endStream = isLastContent && trailers.isEmpty(); release = false; encoder.writeData(ctx, currentStreamId, content, 0, endStream, promiseAggregator.newPromise()); if (!trailers.isEmpty()) {
response.headers().add(resp.headers()); response.content().writeBytes(((HttpContent) msg).content()); if (msg instanceof LastHttpContent) { response.trailingHeaders().add(((LastHttpContent) msg).trailingHeaders()); try { handshakeComplete(ctx, response); chctx.pipeline().remove(HandshakeInboundHandler.this); for (;;) { Object m = buffered.poll(); break; ctx.fireChannelRead(m);
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()) { NettyResponseHeaders responseHeaders = new NettyResponseHeaders(future.getHttpHeaders(), trailingHeaders); interrupt = handler.onHeadersReceived(responseHeaders) != State.CONTINUE; } } ByteBuf buf = chunk.content(); try { if (!interrupt && (buf.readableBytes() > 0 || last)) { NettyResponseBodyPart part = nettyConfig.getBodyPartFactory().newResponseBodyPart(buf, last); interrupt = updateBodyAndInterrupt(future, handler, part); } } finally { buf.release(); } if (interrupt || last) finishUpdate(future, channel, !last); }
@Override public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception { if (!(msg instanceof HttpObject)) { ctx.fireChannelRead(msg); return; if (msg instanceof HttpContent) { final HttpContent content = (HttpContent) msg; final DecoderResult decoderResult = content.decoderResult(); if (!decoderResult.isSuccess()) { fail(ctx, new ProtocolViolationException(decoderResult.cause())); final ByteBuf data = content.content(); final int dataLength = data.readableBytes(); if (dataLength > 0) { assert res != null; final HttpHeaders trailingHeaders = ((LastHttpContent) msg).trailingHeaders(); if (!trailingHeaders.isEmpty()) { res.write(ArmeriaHttpUtil.toArmeria(trailingHeaders)); ctx.close();
private void handleReadHttpContent(ChannelHandlerContext ctx, HttpContent content) { if (!ignoreBodyRead) { if (content instanceof LastHttpContent) { if (content.content().readableBytes() > 0 || !((LastHttpContent) content).trailingHeaders().isEmpty()) { // It has data or trailing headers, send them ctx.fireChannelRead(content); } else { ReferenceCountUtil.release(content); } removeHandlerIfActive(ctx, ctx.name() + "-body-publisher"); currentlyStreamedMessage = null; consumedInMessage(ctx); } else { ctx.fireChannelRead(content); } } else { ReferenceCountUtil.release(content); if (content instanceof LastHttpContent) { ignoreBodyRead = false; if (currentlyStreamedMessage != null) { removeHandlerIfActive(ctx, ctx.name() + "-body-publisher"); } currentlyStreamedMessage = null; } } }
HttpMethod httpMethod = ((HttpRequest) msg).method(); String requestURI = ((HttpRequest) msg).uri(); InetSocketAddress remoteSocket = (InetSocketAddress) ctx.channel().remoteAddress(); InterAddress remoteAddress = new InterAddress("socket", remoteSocket.getAddress().getHostAddress(), remoteSocket.getPort(), "unknown"); InterAddress local = this.connector.getBindAddress(); this.httpResponse = new RsfHttpResponseObject(this.httpRequest); this.workStatus = WorkStatus.ReceiveRequest; this.httpRequest.getNettyRequest().headers().set(((HttpRequest) msg).headers()); ByteBuf content = ((LastHttpContent) msg).content(); this.httpRequest.getNettyRequest().content().writeBytes(content); if (HttpMethod.POST.equals(this.httpRequest.getNettyRequest().method())) { this.httpRequest.loadPostRequestBody(); ByteBuf content = http.content(); this.httpRequest.getNettyRequest().content().writeBytes(content); return;
HttpResponseStatus status = response.status(); if (status.equals(HttpResponseStatus.CONTINUE)) { ctx.write(msg, promise); return; accessLog.increaseContentLength(((LastHttpContent) msg).content().readableBytes()); ctx.write(msg, promise) .addListener(future -> { if (future.isSuccess()) { accessLog.increaseContentLength(((ByteBuf) msg).readableBytes()); accessLog.increaseContentLength(((ByteBufHolder) msg).content().readableBytes()); ctx.write(msg, promise);
assertEquals(expectSSL, soInt.isSsl()); ChannelHandlerContext chctx = soInt.channelHandlerContext(); ChannelPipeline pipeline = chctx.pipeline(); pipeline.addBefore("handler", "http", new HttpClientCodec()); AtomicInteger status = new AtomicInteger(); case 1: assertTrue(obj instanceof LastHttpContent); ByteBuf content = ((LastHttpContent) obj).content(); assertEquals(!expectSSL, content.isDirect()); assertEquals(1, content.refCnt()); String val = content.toString(StandardCharsets.UTF_8); assertTrue(content.release()); assertEquals("Hello World", val);
content[1] = new DefaultHttpContent(Unpooled.copiedBuffer(json1, CharsetUtil.UTF_8)); content[2] = new DefaultLastHttpContent(Unpooled.copiedBuffer(json2, CharsetUtil.UTF_8)); assertThat(t, instanceOf(ByteBuf.class)); ByteBuf b = (ByteBuf) t; assertThat(b.readCharSequence(b.readableBytes(), CharsetUtil.UTF_8), is("{\"some\": 1}")); b.release(); ((LastHttpContent) t).release();
chunk.retain(); rawContentLengthInBytes += chunk.content().readableBytes(); isCompleteRequestWithAllChunks = true; HttpHeaders chunkTrailingHeaders = ((LastHttpContent) chunk).trailingHeaders(); if (!trailingHeaders.isEmpty()) { throw new IllegalStateException("Received the final chunk, but trailingHeaders was already " + "populated. This should not be possible."); trailingHeaders.add(chunkTrailingHeaders);
@Override public void write(ChannelHandlerContext ctx, Object msg, ChannelPromise promise) throws Exception { HttpProcessingState state = ChannelAttributes.getHttpProcessingStateForChannel(ctx).get(); allowCompressionForThisRequest = false; if (state != null) { // We only want to allow compression if the endpoint being hit is *not* a ProxyRouterEndpoint, the response is full, and the response size // is greater than the threshold boolean isFull = msg instanceof HttpResponse && msg instanceof LastHttpContent; boolean endpointAllowed = endpointAllowsCompression(state.getEndpointForExecution()); boolean responseInfoAllowed = state.getResponseInfo() == null || !state.getResponseInfo().isPreventCompressedOutput(); if (isFull && endpointAllowed && responseInfoAllowed && ((LastHttpContent) msg).content().readableBytes() > responseSizeThresholdBytes) { allowCompressionForThisRequest = true; } } super.write(ctx, msg, promise); }
final FullHttpMessage fullMsg = newFullMessage(id, headers, ctx.alloc()); out.add(fullMsg); return; LastHttpContent last = new DefaultLastHttpContent(Unpooled.EMPTY_BUFFER, validateHeaders); HttpConversionUtil.addHttp2ToHttpHeaders(id, headers, last.trailingHeaders(), HttpVersion.HTTP_1_1, true, true); out.add(last); } else { FullHttpMessage full = newFullMessage(id, headers, ctx.alloc()); out.add(full); HttpMessage req = newMessage(id, headers); if (!HttpUtil.isContentLengthSet(req)) { req.headers().add(HttpHeaderNames.TRANSFER_ENCODING, HttpHeaderValues.CHUNKED); Http2DataFrame dataFrame = (Http2DataFrame) frame; if (dataFrame.isEndStream()) { out.add(new DefaultLastHttpContent(dataFrame.content().retain(), validateHeaders)); } else { out.add(new DefaultHttpContent(dataFrame.content().retain()));
@Test public void addNamedEncoderReplaysLastHttp() { ByteBuf buf = Unpooled.copiedBuffer("{\"foo\":1}", CharsetUtil.UTF_8); EmbeddedChannel channel = new EmbeddedChannel(); HttpClientOperations ops = new HttpClientOperations(() -> channel, ConnectionObserver.emptyListener(), ClientCookieEncoder.STRICT, ClientCookieDecoder.STRICT) .addHandler("json", new JsonObjectDecoder()); channel.writeInbound(new DefaultLastHttpContent(buf)); assertThat(channel.pipeline().names().iterator().next(), is("json$extractor")); Object content = channel.readInbound(); assertThat(content, instanceOf(ByteBuf.class)); ((ByteBuf) content).release(); content = channel.readInbound(); assertThat(content, instanceOf(LastHttpContent.class)); ((LastHttpContent) content).release(); assertThat(channel.readInbound(), nullValue()); }
@Override public LastHttpContent copy() { LastHttpContent content = new DefaultLastHttpContent(Unpooled.EMPTY_BUFFER); content.trailingHeaders().set(trailingHeaders()); return content; }
@Test public void StreamingChannel_doStreamChunk_works_as_expected_when_last_chunk_already_sent_downstream_and_incoming_chunk_is_empty_last_chunk() { // given streamingChannelSpy.downstreamLastChunkSentHolder.heldObject = true; LastHttpContent contentChunkMock = mock(LastHttpContent.class); ByteBuf contentByteBufMock = mock(ByteBuf.class); doReturn(contentByteBufMock).when(contentChunkMock).content(); doReturn(0).when(contentByteBufMock).readableBytes(); ChannelFuture successFutureMock = mock(ChannelFuture.class); doReturn(successFutureMock).when(channelMock).newSucceededFuture(); // when ChannelFuture result = streamingChannelSpy.doStreamChunk(contentChunkMock); // then verify(channelMock, never()).writeAndFlush(any(Object.class)); verify(contentChunkMock).release(); verify(channelMock).newSucceededFuture(); assertThat(result).isSameAs(successFutureMock); }
@Override public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception { // .请求头 if (msg instanceof HttpResponse) { HttpResponse response = (HttpResponse) msg; this.httpResponse = new RsfHttpResponseObject(response.protocolVersion(), response.status()); return; } // .请求数据(最后一个) if (msg instanceof LastHttpContent) { LastHttpContent http = (LastHttpContent) msg; ByteBuf content = http.content(); this.httpResponse.getHttpResponse().content().writeBytes(content); this.responseFuture.completed(this.httpResponse); return; } // 请求数据 if (msg instanceof HttpContent) { HttpContent http = (HttpContent) msg; ByteBuf content = http.content(); this.httpResponse.getHttpResponse().content().writeBytes(content); return; } // super.channelRead(ctx, msg); } @Override