Http2Settings settings = HttpUtils.decodeSettings(settingsHeader); if (settings != null) { HandlerHolder<HttpHandlers> reqHandler = httpHandlerMgr.chooseHandler(ctx.channel().eventLoop()); if (reqHandler != null && reqHandler.context.isEventLoopContext()) { ChannelPipeline pipeline = ctx.pipeline(); DefaultFullHttpResponse res = new DefaultFullHttpResponse(HTTP_1_1, SWITCHING_PROTOCOLS, Unpooled.EMPTY_BUFFER, false); res.headers().add(HttpHeaderNames.CONNECTION, HttpHeaderValues.UPGRADE); res.headers().add(HttpHeaderNames.UPGRADE, Http2CodecUtil.HTTP_UPGRADE_PROTOCOL_NAME); res.headers().add(HttpHeaderNames.CONTENT_LENGTH, HttpHeaderValues.ZERO); ctx.writeAndFlush(res); pipeline.remove("httpEncoder"); pipeline.remove("handler"); pipeline.addLast("handler", handler); handler.serverUpgrade(ctx, settings, request); DefaultHttp2Headers headers = new DefaultHttp2Headers(); headers.method(request.method().name()); headers.path(request.uri()); headers.authority(request.headers().get("host")); headers.scheme("http"); request.headers().remove("http2-settings"); request.headers().remove("host"); request.headers().forEach(header -> headers.set(header.getKey().toLowerCase(), header.getValue())); ctx.fireChannelRead(new DefaultHttp2HeadersFrame(headers, false)); } else {
protected void sendHttp2Response(ChannelHandlerContext ctx, int streamId, HttpResponseStatus status, String result) { // Send a frame for the response status Http2Headers headers = new DefaultHttp2Headers().status(status.codeAsText()); if (!HttpResponseStatus.OK.equals(status)) { headers.set(RemotingConstants.HEAD_RESPONSE_ERROR, "true"); } if (StringUtils.isNotBlank(result)) { ByteBuf data = ctx.alloc().buffer(); data.writeBytes(result.getBytes(RpcConstants.DEFAULT_CHARSET)); encoder().writeHeaders(ctx, streamId, headers, 0, false, ctx.newPromise()); encoder().writeData(ctx, streamId, data, 0, true, ctx.newPromise()); } else { encoder().writeHeaders(ctx, streamId, headers, 0, true, ctx.newPromise()); } }
@Override public boolean contains(CharSequence name, CharSequence value) { return contains(name, value, false); }
@Override public HttpServerResponse writeContinue() { synchronized (conn) { checkHeadWritten(); stream.writeHeaders(new DefaultHttp2Headers().status("100"), false); ctx.flush(); return this; } }
@Override public void failure(Throwable error) { ctx.writeAndFlush(new DefaultHttp2Headers().status(HttpResponseStatus.INTERNAL_SERVER_ERROR.codeAsText())) .addListener(ChannelFutureListener.CLOSE); }
private static Http2Headers http1HeadersToHttp2Headers(FullHttpRequest request) { CharSequence host = request.headers().get(HttpHeaderNames.HOST); Http2Headers http2Headers = new DefaultHttp2Headers() .method(HttpMethod.GET.asciiName()) .path(request.uri()) .scheme(HttpScheme.HTTP.name()); if (host != null) { http2Headers.authority(host); } return http2Headers; }
@Override public void push(final String method, final String path, final Map<String, Object> headers) { ctx.channel().eventLoop().execute(() -> { AsciiString streamIdHeader = HttpConversionUtil.ExtensionHeaderNames.STREAM_ID.text(); Http2Connection connection = encoder.connection(); int nextStreamId = connection.local().incrementAndGetNextStreamId(); Http2Headers h2headers = new DefaultHttp2Headers() .path(path) .method(method) .authority(authority) .scheme(scheme); headers.forEach((n, v) -> h2headers.add(n, v.toString())); encoder.writePushPromise(ctx, streamId, nextStreamId, h2headers, 0, ctx.newPromise()); // TODO: Is there another way of handling a push promise? DefaultFullHttpRequest pushRequest = new DefaultFullHttpRequest(HttpVersion.HTTP_1_1, HttpMethod.valueOf(method.toUpperCase()), path, Unpooled.EMPTY_BUFFER, new DefaultHttpHeaders(false).set(streamIdHeader, nextStreamId), EmptyHttpHeaders.INSTANCE); ctx.pipeline().fireChannelRead(pushRequest); ctx.pipeline().fireChannelReadComplete(); }); }
final Http2Headers headers = new DefaultHttp2Headers() .method(HttpMethod.POST.asciiName()) .authority(this.authority) .path(APNS_PATH_PREFIX + pushNotification.getToken()) .addInt(APNS_EXPIRATION_HEADER, pushNotification.getExpiration() == null ? 0 : (int) (pushNotification.getExpiration().getTime() / 1000)); final ChannelPromise headersPromise = context.newPromise(); this.encoder().writeHeaders(context, streamId, headers, 0, false, headersPromise); log.trace("Wrote headers on stream {}: {}", streamId, headers); final ByteBuf payloadBuffer = context.alloc().ioBuffer(INITIAL_PAYLOAD_BUFFER_CAPACITY); payloadBuffer.writeBytes(pushNotification.getPayload().getBytes(StandardCharsets.UTF_8)); final ChannelPromise dataPromise = context.newPromise(); this.encoder().writeData(context, streamId, payloadBuffer, 0, true, dataPromise); log.trace("Wrote payload on stream {}: {}", streamId, pushNotification.getPayload());
: new HttpResponseStatus(statusCode, reasonPhrase); DefaultHttp2Headers response = new DefaultHttp2Headers(); response.status(Integer.toString(responseContext.getStatus())); response.add(e.getKey().toLowerCase(), e.getValue()); response.set(HttpHeaderNames.CONTENT_LENGTH, Long.toString(contentLength)); ctx.writeAndFlush(new DefaultHttp2HeadersFrame(response)); if (!headersFrame.headers().method().equals(HttpMethod.HEAD.asciiName()) && (contentLength > 0 || contentLength == -1)) { ctx.writeAndFlush(new DefaultHttp2DataFrame(true)); return null;
final AcceptNotificationResponse acceptNotificationResponse = (AcceptNotificationResponse) message; final Http2Headers headers = new DefaultHttp2Headers() .status(HttpResponseStatus.OK.codeAsText()) .add(APNS_ID_HEADER, FastUUID.toString(acceptNotificationResponse.getApnsId())); final RejectNotificationResponse rejectNotificationResponse = (RejectNotificationResponse) message; final Http2Headers headers = new DefaultHttp2Headers() .status(rejectNotificationResponse.getErrorReason().getHttpResponseStatus().codeAsText()) .add(HttpHeaderNames.CONTENT_TYPE, "application/json") .add(APNS_ID_HEADER, FastUUID.toString(rejectNotificationResponse.getApnsId())); final ChannelPromise headersPromise = context.newPromise(); this.encoder().writeHeaders(context, rejectNotificationResponse.getStreamId(), headers, 0, false, headersPromise); final ChannelPromise dataPromise = context.newPromise(); this.encoder().writeData(context, rejectNotificationResponse.getStreamId(), Unpooled.wrappedBuffer(payloadBytes), 0, true, dataPromise); context.write(message, writePromise);
@Override public void writeHead(HttpMethod method, String rawMethod, String uri, MultiMap headers, String hostHeader, boolean chunked, ByteBuf content, boolean end, StreamPriority priority) { Http2Headers h = new DefaultHttp2Headers(); h.method(method != HttpMethod.OTHER ? method.name() : rawMethod); if (method == HttpMethod.CONNECT) { if (hostHeader == null) { throw new IllegalArgumentException("Missing :authority / host header"); h.authority(hostHeader); } else { h.path(uri); h.scheme(conn.isSSL() ? "https" : "http"); if (hostHeader != null) { writeBuffer(content, end); } else { handlerContext.flush();
final RejectNotificationResponse rejectNotificationResponse = (RejectNotificationResponse) message; final Http2Headers headers = new DefaultHttp2Headers(); headers.status(rejectNotificationResponse.getErrorReason().getHttpResponseStatus().codeAsText()); headers.add(HttpHeaderNames.CONTENT_TYPE, "application/json"); headers.add(APNS_ID_HEADER, rejectNotificationResponse.getApnsId().toString()); final ChannelPromise headersPromise = context.newPromise(); this.encoder().writeHeaders(context, rejectNotificationResponse.getStreamId(), headers, 0, false, headersPromise); final ChannelPromise dataPromise = context.newPromise(); this.encoder().writeData(context, rejectNotificationResponse.getStreamId(), Unpooled.wrappedBuffer(payloadBytes), 0, true, dataPromise); final InternalServerErrorResponse internalServerErrorResponse = (InternalServerErrorResponse) message; final Http2Headers headers = new DefaultHttp2Headers(); headers.status(HttpResponseStatus.INTERNAL_SERVER_ERROR.codeAsText()); context.write(message, writePromise);
@Override public void write(final ChannelHandlerContext ctx, final Object msg, final ChannelPromise promise) throws Exception { if (isServer) { assert msg instanceof ByteBuf; sendAPushPromise(ctx, lastStreamId, lastStreamId + 1, (ByteBuf) msg); } else { final Http2Headers headers = new DefaultHttp2Headers(); try { long threadId = Thread.currentThread().getId(); long streamId = (threadId % 2 == 0) ? threadId + 1 : threadId + 2; encoder().writeHeaders(ctx, (int) streamId, headers, 0, false, promise); encoder().writeData(ctx, (int) streamId, (ByteBuf) msg, 0, false, ctx.newPromise()); ctx.flush(); } catch (Exception e) { e.printStackTrace(); } } }
@Test public void testFullResponse() throws Exception { outputReceived = new CountDownLatch(2); Http2Headers headersIn = new DefaultHttp2Headers().method("GET").path("/"); Http2Request requestIn = Http2Request.build(1, headersIn, true); FullResponse responseIn = ResponseBuilders.newOk().streamId(1).body(Unpooled.EMPTY_BUFFER).build(); channel.writeInbound(requestIn); channel.runPendingTasks(); // blocks channel.writeOutbound(responseIn); channel.runPendingTasks(); // blocks Uninterruptibles.awaitUninterruptibly(outputReceived); Http2Response responseOut = responses.remove(0); assertNotNull(responseOut); assertTrue(responseOut.payload instanceof Http2Headers); assertEquals("200", ((Http2Headers) responseOut.payload).status().toString()); assertTrue(responseOut.eos); assertEquals(1, responseOut.streamId); }
synchronized void sendPush(int streamId, String host, HttpMethod method, MultiMap headers, String path, StreamPriority streamPriority, Handler<AsyncResult<HttpServerResponse>> completionHandler) { Http2Headers headers_ = new DefaultHttp2Headers(); if (method == HttpMethod.OTHER) { throw new IllegalArgumentException("Cannot push HttpMethod.OTHER"); } else { headers_.method(method.name()); headers_.path(path); headers_.scheme(isSsl() ? "https" : "http"); if (host != null) { headers_.authority(host);
private void writeErrorResponse(ChannelHandlerContext ctx, int streamId, HttpResponseStatus status) throws Http2Exception { final byte[] content = status.toString().getBytes(StandardCharsets.UTF_8); writer.writeHeaders( ctx, streamId, new DefaultHttp2Headers(false) .status(status.codeAsText()) .set(HttpHeaderNames.CONTENT_TYPE, MediaType.PLAIN_TEXT_UTF_8.toString()) .setInt(HttpHeaderNames.CONTENT_LENGTH, content.length), 0, false, ctx.voidPromise()); writer.writeData(ctx, streamId, Unpooled.wrappedBuffer(content), 0, true, ctx.voidPromise()); final Http2Stream stream = writer.connection().stream(streamId); if (stream != null && writer.flowController().hasFlowControlled(stream)) { // Ensure to flush the error response if it's flow-controlled so that it is sent // before an RST_STREAM frame. writer.flowController().writePendingBytes(); } }
protected Http2Headers getHeadersForPushNotification(final ApnsPushNotification pushNotification, final int streamId) { final Http2Headers headers = new DefaultHttp2Headers() .method(HttpMethod.POST.asciiName()) .authority(this.authority) .path(APNS_PATH_PREFIX + pushNotification.getToken()) .scheme(HttpScheme.HTTPS.name()) .addInt(APNS_EXPIRATION_HEADER, pushNotification.getExpiration() == null ? 0 : (int) (pushNotification.getExpiration().getTime() / 1000)); if (pushNotification.getCollapseId() != null) { headers.add(APNS_COLLAPSE_ID_HEADER, pushNotification.getCollapseId()); } if (pushNotification.getPriority() != null) { headers.addInt(APNS_PRIORITY_HEADER, pushNotification.getPriority().getCode()); } if (pushNotification.getTopic() != null) { headers.add(APNS_TOPIC_HEADER, pushNotification.getTopic()); } if (pushNotification.getApnsId() != null) { headers.add(APNS_ID_HEADER, FastUUID.toString(pushNotification.getApnsId())); } return headers; }
private boolean handle100Continue(ChannelHandlerContext ctx, int streamId, Http2Headers headers) { final CharSequence expectValue = headers.get(HttpHeaderNames.EXPECT); if (expectValue == null) { // No 'expect' header. return true; } // '100-continue' is the only allowed expectation. if (!AsciiString.contentEqualsIgnoreCase(HttpHeaderValues.CONTINUE, expectValue)) { return false; } // Send a '100 Continue' response. writer.writeHeaders( ctx, streamId, new DefaultHttp2Headers(false).status(HttpStatus.CONTINUE.codeAsText()), 0, false, ctx.voidPromise()); // Remove the 'expect' header so that it's handled in a way invisible to a Service. headers.remove(HttpHeaderNames.EXPECT); return true; }
final Http2Headers out = new DefaultHttp2Headers(validateHeaders, inHeaders.size()); if (in instanceof HttpRequest) { HttpRequest request = (HttpRequest) in; URI requestTargetUri = URI.create(request.uri()); out.path(toHttp2Path(requestTargetUri)); out.method(request.method().asciiName()); setHttp2Scheme(inHeaders, requestTargetUri, out); out.status(response.status().codeAsText());
private void sendAPushPromise(ChannelHandlerContext ctx, int streamId, int pushPromiseStreamId, ByteBuf payload) throws Http2Exception { encoder().writePushPromise(ctx, streamId, pushPromiseStreamId, new DefaultHttp2Headers().status(OK.codeAsText()), 0, ctx.newPromise()); //Http2Stream stream = connection.local().reservePushStream(pushPromiseStreamId, connection.connectionStream()); Http2Headers headers = new DefaultHttp2Headers(); headers.status(OK.codeAsText()); encoder().writeHeaders(ctx, pushPromiseStreamId, headers, 0, false, ctx.newPromise()); encoder().writeData(ctx, pushPromiseStreamId, payload, 0, false, ctx.newPromise()); }