@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 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; }
/** * 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); } }
/** * Verifies blob properties from output, to that sent in during input * * @param expectedHeaders the expected headers in the response. * @param response the {@link HttpResponse} that contains the headers. */ private void verifyBlobProperties(HttpHeaders expectedHeaders, HttpResponse response) { assertEquals( "Blob size does not match", Long.parseLong(expectedHeaders.get(RestUtils.Headers.BLOB_SIZE)), Long.parseLong(HttpHeaders.getHeader(response, RestUtils.Headers.BLOB_SIZE))); assertEquals( RestUtils.Headers.SERVICE_ID + " does not match", expectedHeaders.get(RestUtils.Headers.SERVICE_ID), HttpHeaders.getHeader(response, RestUtils.Headers.SERVICE_ID)); assertEquals( RestUtils.Headers.PRIVATE + " does not match", expectedHeaders.get(RestUtils.Headers.PRIVATE), HttpHeaders.getHeader(response, RestUtils.Headers.PRIVATE)); assertEquals( RestUtils.Headers.AMBRY_CONTENT_TYPE + " does not match", expectedHeaders.get(RestUtils.Headers.AMBRY_CONTENT_TYPE), HttpHeaders.getHeader(response, RestUtils.Headers.AMBRY_CONTENT_TYPE)); assertTrue( "No " + RestUtils.Headers.CREATION_TIME, HttpHeaders.getHeader(response, RestUtils.Headers.CREATION_TIME, null) != null); if (Long.parseLong(expectedHeaders.get(RestUtils.Headers.TTL)) != Utils.Infinite_Time) { assertEquals( RestUtils.Headers.TTL + " does not match", expectedHeaders.get(RestUtils.Headers.TTL), HttpHeaders.getHeader(response, RestUtils.Headers.TTL)); } if (expectedHeaders.contains(RestUtils.Headers.OWNER_ID)) { assertEquals( RestUtils.Headers.OWNER_ID + " does not match", expectedHeaders.get(RestUtils.Headers.OWNER_ID), HttpHeaders.getHeader(response, RestUtils.Headers.OWNER_ID)); } }
private void keepAlive(final ChannelFuture future) { if (headers.contains(HttpHeaderNames.CONTENT_LENGTH)) { if (!keepAlive) { future.addListener(CLOSE); } } else { // content len is not set, just close the connection regardless keep alive or not. future.addListener(CLOSE); } }
private FullHttpRequest convertToHttpRequest(Invocation invocation) { requireNonNull(invocation, "invocation"); final ServiceInvocationContext ctx = invocation.invocationContext(); final FullHttpRequest request; final Object content = invocation.content(); if (content instanceof FullHttpRequest) { request = (FullHttpRequest) content; } else if (content instanceof ByteBuf) { request = new DefaultFullHttpRequest( HttpVersion.HTTP_1_1, HttpMethod.POST, ctx.path(), (ByteBuf) content); } else { throw new IllegalStateException( "content is not a ByteBuf or FullHttpRequest: " + content.getClass().getName()); } HttpHeaders headers = request.headers(); headers.set(HttpHeaderNames.HOST, ctx.host()); headers.set(ExtensionHeaderNames.SCHEME.text(), sessionProtocol.uriText()); headers.set(HttpHeaderNames.USER_AGENT, ARMERIA_USER_AGENT); headers.set(HttpHeaderNames.CONNECTION, HttpHeaderValues.KEEP_ALIVE); ByteBuf contentBuf = request.content(); if (contentBuf != null && contentBuf.isReadable()) { headers.set(HttpHeaderNames.CONTENT_LENGTH, contentBuf.readableBytes()); } invocation.options().get(ClientOption.HTTP_HEADERS).ifPresent(headers::add); if (ctx.scheme().serializationFormat() != SerializationFormat.NONE) { // we allow a user can set content type and accept headers String mimeType = ctx.scheme().serializationFormat().mimeType(); if (!headers.contains(HttpHeaderNames.CONTENT_TYPE)) { headers.set(HttpHeaderNames.CONTENT_TYPE, mimeType); } if (!headers.contains(HttpHeaderNames.ACCEPT)) { headers.set(HttpHeaderNames.ACCEPT, mimeType); } } return request; }
/** * Returns the content length of the specified web socket message. If the specified message is not * a web socket message, {@code -1} is returned. */ private static int getWebSocketContentLength(HttpMessage message) { // WebSockset messages have constant content-lengths. HttpHeaders h = message.headers(); if (message instanceof HttpRequest) { HttpRequest req = (HttpRequest) message; if (HttpMethod.GET.equals(req.getMethod()) && h.contains(Names.SEC_WEBSOCKET_KEY1) && h.contains(Names.SEC_WEBSOCKET_KEY2)) { return 8; } } else if (message instanceof HttpResponse) { HttpResponse res = (HttpResponse) message; if (res.getStatus().code() == 101 && h.contains(Names.SEC_WEBSOCKET_ORIGIN) && h.contains(Names.SEC_WEBSOCKET_LOCATION)) { return 16; } } // Not a web socket message return -1; }
@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; }
private void processHead(ChannelHandlerContext context, FullHttpRequest request) { HttpHeaders headers = request.headers(); FullHttpResponse response = null; if (headers.contains(Names.CONTENT_LENGTH)) { try { File file = getRequestedFile(request.getUri()); response = new DefaultFullHttpResponse( HTTP_1_1, request.getDecoderResult().isSuccess() ? OK : BAD_REQUEST); HttpHeaders.setContentLength(response, file.length()); } catch (FileNotFoundException | URISyntaxException e) { response = getBadRequest(e.getMessage()); } } context.writeAndFlush(response); }
private void prepareHeaders() { HttpHeaders headers = request.headers(); headers.remove(TRANSFER_ENCODING); if (!headers.contains(HOST)) { request.headers().set(HOST, conn.hostHeader()); } if (chunked) { HttpHeaders.setTransferEncodingChunked(request); } if (client.getOptions().isTryUseCompression() && request.headers().get(ACCEPT_ENCODING) == null) { // if compression should be used but nothing is specified by the user support deflate and // gzip. request.headers().set(ACCEPT_ENCODING, DEFLATE_GZIP); } if (!client.getOptions().isKeepAlive() && client.getOptions().getProtocolVersion() == io.vertx.core.http.HttpVersion.HTTP_1_1) { request.headers().set(CONNECTION, CLOSE); } else if (client.getOptions().isKeepAlive() && client.getOptions().getProtocolVersion() == io.vertx.core.http.HttpVersion.HTTP_1_0) { request.headers().set(CONNECTION, KEEP_ALIVE); } }
@Override protected Object encode(ChannelHandlerContext ctx, HttpObject msg) throws Exception { if (msg instanceof HttpResponse && ((HttpResponse) msg).getStatus().code() == 100) { // 100-continue response must be passed through. return msg; } // handle the case of single complete message without content if (msg instanceof FullHttpMessage && !((FullHttpMessage) msg).data().isReadable()) { // Remove content encoding String acceptEncoding = acceptEncodingQueue.poll(); if (acceptEncoding == null) { throw new IllegalStateException("cannot send more responses than requests"); } return msg; } if (msg instanceof HttpMessage) { assert message == null; // check if this message is also of type HttpContent is such case just make a safe copy of the // headers // as the content will get handled later and this simplify the handling if (msg instanceof HttpContent) { if (msg instanceof HttpRequest) { HttpRequest req = (HttpRequest) msg; message = new DefaultHttpRequest(req.getProtocolVersion(), req.getMethod(), req.getUri()); message.headers().set(req.headers()); } else if (msg instanceof HttpResponse) { HttpResponse res = (HttpResponse) msg; message = new DefaultHttpResponse(res.getProtocolVersion(), res.getStatus()); message.headers().set(res.headers()); } else { return msg; } } else { message = (HttpMessage) msg; } cleanup(); } if (msg instanceof HttpContent) { HttpContent c = (HttpContent) msg; if (!encodeStarted) { encodeStarted = true; HttpMessage message = this.message; HttpHeaders headers = message.headers(); this.message = null; // Determine the content encoding. String acceptEncoding = acceptEncodingQueue.poll(); if (acceptEncoding == null) { throw new IllegalStateException("cannot send more responses than requests"); } Result result = beginEncode(message, c, acceptEncoding); if (result == null) { if (c instanceof LastHttpContent) { return new Object[] {message, new DefaultLastHttpContent(c.data().retain())}; } else { return new Object[] {message, new DefaultHttpContent(c.data().retain())}; } } encoder = result.contentEncoder(); // Encode the content and remove or replace the existing headers // so that the message looks like a decoded message. headers.set(HttpHeaders.Names.CONTENT_ENCODING, result.targetContentEncoding()); Object[] encoded = encodeContent(message, c); if (!HttpHeaders.isTransferEncodingChunked(message) && encoded.length == 3) { if (headers.contains(HttpHeaders.Names.CONTENT_LENGTH)) { long length = ((ByteBufHolder) encoded[1]).data().readableBytes() + ((ByteBufHolder) encoded[2]).data().readableBytes(); headers.set(HttpHeaders.Names.CONTENT_LENGTH, Long.toString(length)); } } return encoded; } if (encoder != null) { return encodeContent(null, c); } c.retain(); return c; } return null; }