public FullHttpRequest getHttpRequest() { if (h1Request != null) { return h1Request; } if (h2Headers != null) { try { // Fake out a full HTTP request. FullHttpRequest synthesizedRequest = HttpConversionUtil.toFullHttpRequest(0, h2Headers, alloc, true); if (data != null) { synthesizedRequest.replace(data); } return synthesizedRequest; } catch (Http2Exception e) { // TODO(JR): Do something more meaningful with this exception e.printStackTrace(); } } throw new IllegalStateException("Cannot get the http request for an empty XrpcRequest"); }
@Override public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception { LOGGER.info("[Client ({})] => [Server ({})] : {}", connectionInfo.getClientAddr(), connectionInfo.getServerAddr(), msg); if (msg instanceof FullHttpRequest) { String streamId = ((HttpRequest) msg).headers().get( HttpConversionUtil.ExtensionHeaderNames.STREAM_ID.text()); if (streamId == null) { throw new IllegalStateException("No streamId"); } streams.offer(streamId); } else if (msg instanceof HttpObject) { throw new IllegalStateException("Cannot handle message: " + msg.getClass()); } outboundChannel.writeAndFlush(msg); }
@Override public void write(ChannelHandlerContext ctx, Object msg, ChannelPromise promise) throws Exception { LOGGER.info("[Client ({})] <= [Server ({})] : {}", connectionInfo.getClientAddr(), connectionInfo.getServerAddr(), msg); if (msg instanceof HttpResponse) { HttpResponse response = (HttpResponse) msg; if (!response.headers().contains(HttpConversionUtil.ExtensionHeaderNames.STREAM_ID.text())) { if (streams.isEmpty()) { throw new IllegalStateException("No active streams"); } response.headers().add(HttpConversionUtil.ExtensionHeaderNames.STREAM_ID.text(), streams.poll()); } } ctx.write(msg, promise); }
@Override protected void channelRead0(ChannelHandlerContext ctx, FullHttpResponse msg) throws Exception { Integer streamId = msg.headers().getInt(HttpConversionUtil.ExtensionHeaderNames.STREAM_ID.text()); if (streamId == null) { System.err.println("HttpResponseHandler unexpected message received: " + msg); return; } Entry<ChannelFuture, ChannelPromise> entry = streamidPromiseMap.get(streamId); if (entry == null) { System.err.println("Message received for unknown stream id " + streamId); } else { // Do stuff with the message (for now just print it) ByteBuf content = msg.content(); if (content.isReadable()) { int contentLength = content.readableBytes(); byte[] arr = new byte[contentLength]; content.readBytes(arr); System.out.println(new String(arr, 0, contentLength, CharsetUtil.UTF_8)); } entry.getValue().setSuccess(); } }
@Override protected void channelRead0(ChannelHandlerContext ctx, FullHttpResponse msg) throws Exception { Integer streamId = msg.headers().getInt(HttpConversionUtil.ExtensionHeaderNames.STREAM_ID.text()); if (streamId == null) { log.error("HTTP2ResponseHandler unexpected message received: " + msg); return; } Entry<ChannelFuture, ChannelPromise> entry = streamIdPromiseMap.get(streamId); if (entry == null) { if (streamId == 1) { log.error("HTTP2 Upgrade request has received from stream : " + streamId); } } else { ByteBuf content = msg.content(); if (content.isReadable()) { int contentLength = content.readableBytes(); byte[] arr = new byte[contentLength]; content.readBytes(arr); streamIdResponseMap.put(streamId, new String(arr, 0, contentLength, CharsetUtil.UTF_8)); } entry.getValue().setSuccess(); } }
@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(); }); }
@Override protected void channelRead0(ChannelHandlerContext ctx, Object msg) throws Exception { if (msg instanceof Http2Settings) { settingsPromise.setSuccess(null); return; } if (msg instanceof FullHttpResponse) { FullHttpResponse res = (FullHttpResponse) msg; Integer streamId = res.headers().getInt( HttpConversionUtil.ExtensionHeaderNames.STREAM_ID.text()); if (streamId == null) { responsePromise.tryFailure(new AssertionError("message without stream ID: " + msg)); return; } if (streamId == 1) { // Response to the upgrade request, which is OK to ignore. return; } if (streamId != 3) { responsePromise.tryFailure(new AssertionError("unexpected stream ID: " + msg)); return; } responsePromise.setSuccess(res.content().retain()); return; } throw new IllegalStateException("unexpected message type: " + msg.getClass().getName()); }
public int send(FullHttpRequest request) throws Exception { // Configure ssl. int currentStreamId = streamId.addAndGet(2); request.headers().add(HttpHeaderNames.HOST, hostName); request.headers().add(HttpConversionUtil.ExtensionHeaderNames.SCHEME.text(), scheme.name()); responseHandler.put(currentStreamId, channel.write(request), channel.newPromise()); channel.flush(); log.info("Finished HTTP/2 request"); return currentStreamId; }
public HttpResponseStatus status() { try { return HttpConversionUtil.parseStatus(delegate.status()); } catch (Http2Exception e) { throw new RuntimeException(e); } }
/** * Throws a RuntimeException if the underlying status cannot be converted to an HttpResponseStatus */ @Override public HttpResponseStatus status() { try { return HttpConversionUtil.parseStatus(delegate.status()); } catch (Http2Exception e) { throw new RuntimeException(e); } }
/** Return an Http1 Headers object based on the values in the underlying Http2Headers object. */ @Override public HttpHeaders http1Headers(boolean isTrailer, boolean isRequest) { try { HttpHeaders headers = new DefaultHttpHeaders(); HttpConversionUtil.addHttp2ToHttpHeaders( -1, delegate, headers, HttpVersion.HTTP_1_1, isTrailer, isRequest); return headers; } catch (Http2Exception e) { throw new RuntimeException(e); } }
public NettyResponse(final ChannelHandlerContext ctx, final int bufferSize, final boolean keepAlive, final String streamId) { this.ctx = ctx; this.bufferSize = bufferSize; this.keepAlive = keepAlive; this.headers = new DefaultHttpHeaders(); if (streamId != null) { headers.set(HttpConversionUtil.ExtensionHeaderNames.STREAM_ID.text(), streamId); } this.status = HttpResponseStatus.OK; }
@SuppressWarnings("unchecked") @Override public <T> T upgrade(final Class<T> type) throws Exception { if (type == NativeWebSocket.class) { String protocol = ifSecure("wss", "ws"); String webSocketURL = protocol + "://" + req.headers().get(HttpHeaderNames.HOST) + path; WebSocketServerHandshakerFactory wsFactory = new WebSocketServerHandshakerFactory( webSocketURL, null, true, wsMaxMessageSize); WebSocketServerHandshaker handshaker = wsFactory.newHandshaker(req); NettyWebSocket result = new NettyWebSocket(ctx, handshaker, (ws) -> { handshaker.handshake(ctx.channel(), (FullHttpRequest) req) .addListener(FIRE_EXCEPTION_ON_FAILURE) .addListener(payload -> ws.connect()) .addListener(FIRE_EXCEPTION_ON_FAILURE); }); ctx.channel().attr(NettyWebSocket.KEY).set(result); return (T) result; } else if (type == Sse.class) { NettySse sse = new NettySse(ctx); return (T) sse; } else if (type == NativePushPromise.class) { return (T) new NettyPush(ctx, req.headers().getInt(HttpConversionUtil.ExtensionHeaderNames.STREAM_ID.text()), header("host").orElse(ip()), ifSecure("https", "http")); } throw new UnsupportedOperationException("Not Supported: " + type); }
private String streamId(FullHttpRequest request) { return request.headers().get(HttpConversionUtil.ExtensionHeaderNames.STREAM_ID.text()); }
private void setStreamId(FullHttpResponse response, String streamId) { response.headers().set(HttpConversionUtil.ExtensionHeaderNames.STREAM_ID.text(), streamId); }
@Override public Http2Headers http2Headers() { return HttpConversionUtil.toHttp2Headers(delegate, true); }