@Override public void channelActive(final ChannelHandlerContext ctx) throws Exception { log.info("ECHO active " + NioUdtProvider.socketUDT(ctx.channel()).toStringOptions()); final MessageBuf<Object> out = ctx.nextOutboundMessageBuffer(); out.add(message); ctx.flush(); }
@Before public void initialize() { MockitoAnnotations.initMocks(this); when(context.nextInboundMessageBuffer()).thenReturn(buf); when(buf.add(anyObject())).thenReturn(true); when(context.nextOutboundMessageBuffer()).thenReturn(outboundBuf); }
@Override protected int doReadMessages(MessageBuf<Object> buf) throws Exception { DatagramChannel ch = javaChannel(); ByteBuf buffer = alloc().directBuffer(config().getReceivePacketSize()); boolean free = true; try { ByteBuffer data = buffer.nioBuffer(buffer.writerIndex(), buffer.writableBytes()); InetSocketAddress remoteAddress = (InetSocketAddress) ch.receive(data); if (remoteAddress == null) { return 0; } buf.add( new DatagramPacket( buffer.writerIndex(buffer.writerIndex() + data.remaining()), remoteAddress)); free = false; return 1; } catch (Throwable cause) { if (cause instanceof Error) { throw (Error) cause; } if (cause instanceof RuntimeException) { throw (RuntimeException) cause; } if (cause instanceof Exception) { throw (Exception) cause; } throw new ChannelException(cause); } finally { if (free) { buffer.free(); } } }
@Override protected void messageReceived(final ChannelHandlerContext ctx, final UdtMessage message) throws Exception { final ByteBuf byteBuf = message.data(); meter.mark(byteBuf.readableBytes()); final MessageBuf<Object> out = ctx.nextOutboundMessageBuffer(); out.add(message); ctx.flush(); }
@Override protected int doReadMessages(MessageBuf<Object> buf) throws Exception { SctpChannel ch = javaChannel().accept(); if (ch == null) { return 0; } buf.add(new NioSctpChannel(this, null, ch)); return 1; }
@Override public void flush(ChannelHandlerContext ctx, ChannelPromise promise) throws Exception { ByteBuf in = ctx.outboundByteBuffer(); try { MessageBuf<Object> out = ctx.nextOutboundMessageBuffer(); ByteBuf payload = Unpooled.buffer(in.readableBytes()); payload.writeBytes(in); out.add(new SctpMessage(streamIdentifier, protocolIdentifier, payload)); in.discardReadBytes(); } catch (Throwable t) { ctx.fireExceptionCaught(new EncoderException(t)); } ctx.flush(promise); }
@Override protected int doReadMessages(MessageBuf<Object> buf) throws Exception { if (readSuspended) { try { Thread.sleep(SO_TIMEOUT); } catch (InterruptedException e) { // ignore; } return 0; } int packetSize = config().getReceivePacketSize(); byte[] data = new byte[packetSize]; tmpPacket.setData(data); try { socket.receive(tmpPacket); InetSocketAddress remoteAddr = (InetSocketAddress) tmpPacket.getSocketAddress(); if (remoteAddr == null) { remoteAddr = remoteAddress(); } buf.add( new DatagramPacket( Unpooled.wrappedBuffer(data, tmpPacket.getOffset(), tmpPacket.getLength()), remoteAddr)); if (readSuspended) { return 0; } else { return 1; } } catch (SocketTimeoutException e) { // Expected return 0; } catch (SocketException e) { if (!e.getMessage().toLowerCase(Locale.US).contains("socket closed")) { throw e; } return -1; } }
@Override protected void decode( ChannelHandlerContext ctx, SpdyDataOrControlFrame msg, MessageBuf<Object> out) throws Exception { if (msg instanceof SpdySynStreamFrame) { // HTTP requests/responses are mapped one-to-one to SPDY streams. SpdySynStreamFrame spdySynStreamFrame = (SpdySynStreamFrame) msg; int streamId = spdySynStreamFrame.getStreamId(); if (SpdyCodecUtil.isServerId(streamId)) { // SYN_STREAM frames initiated by the server are pushed resources int associatedToStreamId = spdySynStreamFrame.getAssociatedToStreamId(); // If a client receives a SYN_STREAM with an Associated-To-Stream-ID of 0 // it must reply with a RST_STREAM with error code INVALID_STREAM if (associatedToStreamId == 0) { SpdyRstStreamFrame spdyRstStreamFrame = new DefaultSpdyRstStreamFrame(streamId, SpdyStreamStatus.INVALID_STREAM); ctx.write(spdyRstStreamFrame); } String URL = SpdyHeaders.getUrl(spdyVersion, spdySynStreamFrame); // If a client receives a SYN_STREAM without a 'url' header // it must reply with a RST_STREAM with error code PROTOCOL_ERROR if (URL == null) { SpdyRstStreamFrame spdyRstStreamFrame = new DefaultSpdyRstStreamFrame(streamId, SpdyStreamStatus.PROTOCOL_ERROR); ctx.write(spdyRstStreamFrame); } try { FullHttpResponse httpResponseWithEntity = createHttpResponse(spdyVersion, spdySynStreamFrame); // Set the Stream-ID, Associated-To-Stream-ID, Priority, and URL as headers SpdyHttpHeaders.setStreamId(httpResponseWithEntity, streamId); SpdyHttpHeaders.setAssociatedToStreamId(httpResponseWithEntity, associatedToStreamId); SpdyHttpHeaders.setPriority(httpResponseWithEntity, spdySynStreamFrame.getPriority()); SpdyHttpHeaders.setUrl(httpResponseWithEntity, URL); if (spdySynStreamFrame.isLast()) { HttpHeaders.setContentLength(httpResponseWithEntity, 0); out.add(httpResponseWithEntity); } else { // Response body will follow in a series of Data Frames putMessage(streamId, httpResponseWithEntity); } } catch (Exception e) { SpdyRstStreamFrame spdyRstStreamFrame = new DefaultSpdyRstStreamFrame(streamId, SpdyStreamStatus.PROTOCOL_ERROR); ctx.write(spdyRstStreamFrame); } } else { // SYN_STREAM frames initiated by the client are HTTP requests try { FullHttpRequest httpRequestWithEntity = createHttpRequest(spdyVersion, spdySynStreamFrame); // Set the Stream-ID as a header SpdyHttpHeaders.setStreamId(httpRequestWithEntity, streamId); if (spdySynStreamFrame.isLast()) { out.add(httpRequestWithEntity); } else { // Request body will follow in a series of Data Frames putMessage(streamId, httpRequestWithEntity); } } catch (Exception e) { // If a client sends a SYN_STREAM without all of the getMethod, url (host and path), // scheme, and version headers the server must reply with a HTTP 400 BAD REQUEST reply. // Also sends HTTP 400 BAD REQUEST reply if header name/value pairs are invalid SpdySynReplyFrame spdySynReplyFrame = new DefaultSpdySynReplyFrame(streamId); spdySynReplyFrame.setLast(true); SpdyHeaders.setStatus(spdyVersion, spdySynReplyFrame, HttpResponseStatus.BAD_REQUEST); SpdyHeaders.setVersion(spdyVersion, spdySynReplyFrame, HttpVersion.HTTP_1_0); ctx.write(spdySynReplyFrame); } } } else if (msg instanceof SpdySynReplyFrame) { SpdySynReplyFrame spdySynReplyFrame = (SpdySynReplyFrame) msg; int streamId = spdySynReplyFrame.getStreamId(); try { FullHttpResponse httpResponseWithEntity = createHttpResponse(spdyVersion, spdySynReplyFrame); // Set the Stream-ID as a header SpdyHttpHeaders.setStreamId(httpResponseWithEntity, streamId); if (spdySynReplyFrame.isLast()) { HttpHeaders.setContentLength(httpResponseWithEntity, 0); out.add(httpResponseWithEntity); } else { // Response body will follow in a series of Data Frames putMessage(streamId, httpResponseWithEntity); } } catch (Exception e) { // If a client receives a SYN_REPLY without valid getStatus and version headers // the client must reply with a RST_STREAM frame indicating a PROTOCOL_ERROR SpdyRstStreamFrame spdyRstStreamFrame = new DefaultSpdyRstStreamFrame(streamId, SpdyStreamStatus.PROTOCOL_ERROR); ctx.write(spdyRstStreamFrame); } } else if (msg instanceof SpdyHeadersFrame) { SpdyHeadersFrame spdyHeadersFrame = (SpdyHeadersFrame) msg; int streamId = spdyHeadersFrame.getStreamId(); FullHttpMessage fullHttpMessage = getMessage(streamId); // If message is not in map discard HEADERS frame. if (fullHttpMessage == null) { return; } for (Map.Entry<String, String> e : spdyHeadersFrame.headers().entries()) { fullHttpMessage.headers().add(e.getKey(), e.getValue()); } if (spdyHeadersFrame.isLast()) { HttpHeaders.setContentLength(fullHttpMessage, fullHttpMessage.content().readableBytes()); removeMessage(streamId); out.add(fullHttpMessage); } } else if (msg instanceof SpdyDataFrame) { SpdyDataFrame spdyDataFrame = (SpdyDataFrame) msg; int streamId = spdyDataFrame.getStreamId(); FullHttpMessage fullHttpMessage = getMessage(streamId); // If message is not in map discard Data Frame. if (fullHttpMessage == null) { return; } ByteBuf content = fullHttpMessage.content(); if (content.readableBytes() > maxContentLength - spdyDataFrame.content().readableBytes()) { removeMessage(streamId); throw new TooLongFrameException( "HTTP content length exceeded " + maxContentLength + " bytes."); } ByteBuf spdyDataFrameData = spdyDataFrame.content(); int spdyDataFrameDataLen = spdyDataFrameData.readableBytes(); content.writeBytes(spdyDataFrameData, spdyDataFrameData.readerIndex(), spdyDataFrameDataLen); if (spdyDataFrame.isLast()) { HttpHeaders.setContentLength(fullHttpMessage, content.readableBytes()); removeMessage(streamId); out.add(fullHttpMessage); } } else if (msg instanceof SpdyRstStreamFrame) { SpdyRstStreamFrame spdyRstStreamFrame = (SpdyRstStreamFrame) msg; int streamId = spdyRstStreamFrame.getStreamId(); removeMessage(streamId); } }
@Override protected void decode(ChannelHandlerContext ctx, HttpObject msg, MessageBuf<Object> out) throws Exception { FullHttpMessage currentMessage = this.currentMessage; if (msg instanceof HttpMessage) { assert currentMessage == null; HttpMessage m = (HttpMessage) msg; // Handle the 'Expect: 100-continue' header if necessary. // TODO: Respond with 413 Request Entity Too Large // and discard the traffic or close the connection. // No need to notify the upstream handlers - just log. // If decoding a response, just throw an exception. if (is100ContinueExpected(m)) { ctx.write(CONTINUE.duplicate()); } if (!m.getDecoderResult().isSuccess()) { removeTransferEncodingChunked(m); this.currentMessage = null; out.add(BufUtil.retain(m)); return; } if (msg instanceof HttpRequest) { HttpRequest header = (HttpRequest) msg; this.currentMessage = currentMessage = new DefaultFullHttpRequest( header.getProtocolVersion(), header.getMethod(), header.getUri(), Unpooled.compositeBuffer(maxCumulationBufferComponents)); } else if (msg instanceof HttpResponse) { HttpResponse header = (HttpResponse) msg; this.currentMessage = currentMessage = new DefaultFullHttpResponse( header.getProtocolVersion(), header.getStatus(), Unpooled.compositeBuffer(maxCumulationBufferComponents)); } else { throw new Error(); } currentMessage.headers().set(m.headers()); // A streamed message - initialize the cumulative buffer, and wait for incoming chunks. removeTransferEncodingChunked(currentMessage); } else if (msg instanceof HttpContent) { assert currentMessage != null; // Merge the received chunk into the content of the current message. HttpContent chunk = (HttpContent) msg; CompositeByteBuf content = (CompositeByteBuf) currentMessage.content(); if (content.readableBytes() > maxContentLength - chunk.content().readableBytes()) { // TODO: Respond with 413 Request Entity Too Large // and discard the traffic or close the connection. // No need to notify the upstream handlers - just log. // If decoding a response, just throw an exception. throw new TooLongFrameException( "HTTP content length exceeded " + maxContentLength + " bytes."); } // Append the content of the chunk if (chunk.content().isReadable()) { chunk.retain(); content.addComponent(chunk.content()); content.writerIndex(content.writerIndex() + chunk.content().readableBytes()); } final boolean last; if (!chunk.getDecoderResult().isSuccess()) { currentMessage.setDecoderResult(DecoderResult.failure(chunk.getDecoderResult().cause())); last = true; } else { last = chunk instanceof LastHttpContent; } if (last) { this.currentMessage = null; // Merge trailing headers into the message. if (chunk instanceof LastHttpContent) { LastHttpContent trailer = (LastHttpContent) chunk; currentMessage.headers().add(trailer.trailingHeaders()); } // Set the 'Content-Length' header. currentMessage .headers() .set(HttpHeaders.Names.CONTENT_LENGTH, String.valueOf(content.readableBytes())); // All done out.add(currentMessage); } } else { throw new Error(); } }