private Object decode(ChannelHandlerContext ctx, ByteBuf buffer) { int frameOffset = buffer.readerIndex(); try { TTransport transport = new TChannelBufferInputTransport(buffer); TProtocolReader protocol = protocolFactory.getProtocol(transport); protocol.readMessageBegin(); TProtocolUtil.skip(protocol, TType.STRUCT); protocol.readMessageEnd(); int frameLength = buffer.readerIndex() - frameOffset; if (frameLength > maxFrameSize) { ctx.fireExceptionCaught(new TooLongFrameException("Response message exceeds max size " + maxFrameSize + ": " + frameLength + " - discarded")); } return buffer.slice(frameOffset, frameLength).retain(); } catch (Throwable th) { buffer.readerIndex(frameOffset); return null; } }
@Override public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) { log.error("Unexpected exception from downstream.", cause); Channel ch = ctx.channel(); if (cause instanceof IllegalArgumentException) { ch.close(); } else { if (cause instanceof TooLongFrameException) { sendError(ctx, BAD_REQUEST); return; } if (ch.isActive()) { sendError(ctx, INTERNAL_SERVER_ERROR); } } // 关闭 ctx.close(); }
@Override public boolean process(byte value) throws Exception { char nextByte = (char) value; if (nextByte == HttpConstants.CR) { return true; } else if (nextByte == HttpConstants.LF) { return false; } else { if (size >= maxLineLength) { throw new TooLongFrameException( "Line is larger than " + maxLineLength + " bytes."); } size++; seq.append(nextByte); return true; } }
@Override public boolean process(byte value) throws Exception { char nextByte = (char) value; if (Character.isWhitespace(nextByte)) { return size == 0; } else { if (size >= maxWordLength) { throw new TooLongFrameException( "Word is larger than " + maxWordLength + " bytes."); } size++; seq.append(nextByte); return true; } }
@Override public boolean process(byte value) throws Exception { char nextByte = (char) value; if (Character.isWhitespace(nextByte)) { return size == 0; } else if (!Character.isDigit(nextByte)) { return false; } else { if (size >= maxLength) { throw new TooLongFrameException( "Number is larger than " + maxLength + " bytes."); } seq.append(nextByte); size++; return true; } }
@Override public void exceptionCaught(ChannelHandlerContext ctx, Throwable e) throws Exception { // handle the case of to big requests. if (e.getCause() instanceof TooLongFrameException) { DefaultHttpResponse response = new DefaultHttpResponse(HTTP_1_1, REQUEST_ENTITY_TOO_LARGE); ctx.write(response).addListener(ChannelFutureListener.CLOSE); } else { if(ctx.channel().isActive()){ // 连接已断开就不打印了 logger.warn("Exception caught by request handler", e); } ctx.close(); } }
private WebSocketFrame decodeBinaryFrame(ChannelHandlerContext ctx, byte type, ByteBuf buffer) { long frameSize = 0; int lengthFieldSize = 0; byte b; do { b = buffer.readByte(); frameSize <<= 7; frameSize |= b & 0x7f; if (frameSize > maxFrameSize) { throw new TooLongFrameException(); } lengthFieldSize++; if (lengthFieldSize > 8) { // Perhaps a malicious peer? throw new TooLongFrameException(); } } while ((b & 0x80) == 0x80); if (type == (byte) 0xFF && frameSize == 0) { receivedClosingHandshake = true; return new CloseWebSocketFrame(); } ByteBuf payload = ctx.alloc().buffer((int) frameSize); buffer.readBytes(payload); return new BinaryWebSocketFrame(payload); }
@Test public void testFailSlowTooLongFrameRecovery() throws Exception { EmbeddedChannel ch = new EmbeddedChannel( new DelimiterBasedFrameDecoder(1, true, false, Delimiters.nulDelimiter())); for (int i = 0; i < 2; i ++) { ch.writeInbound(Unpooled.wrappedBuffer(new byte[] { 1, 2 })); try { assertTrue(ch.writeInbound(Unpooled.wrappedBuffer(new byte[] { 0 }))); fail(DecoderException.class.getSimpleName() + " must be raised."); } catch (TooLongFrameException e) { // Expected } ch.writeInbound(Unpooled.wrappedBuffer(new byte[] { 'A', 0 })); ByteBuf buf = releaseLater((ByteBuf) ch.readInbound()); assertEquals("A", buf.toString(CharsetUtil.ISO_8859_1)); } }
@Test public void testFailFastTooLongFrameRecovery() throws Exception { EmbeddedChannel ch = new EmbeddedChannel( new DelimiterBasedFrameDecoder(1, Delimiters.nulDelimiter())); for (int i = 0; i < 2; i ++) { try { assertTrue(ch.writeInbound(Unpooled.wrappedBuffer(new byte[] { 1, 2 }))); fail(DecoderException.class.getSimpleName() + " must be raised."); } catch (TooLongFrameException e) { // Expected } ch.writeInbound(Unpooled.wrappedBuffer(new byte[] { 0, 'A', 0 })); ByteBuf buf = releaseLater((ByteBuf) ch.readInbound()); assertEquals("A", buf.toString(CharsetUtil.ISO_8859_1)); } }
@Test public void testFailSlowTooLongFrameRecovery() throws Exception { EmbeddedChannel ch = new EmbeddedChannel( new LengthFieldBasedFrameDecoder(5, 0, 4, 0, 4, false)); for (int i = 0; i < 2; i ++) { assertFalse(ch.writeInbound(Unpooled.wrappedBuffer(new byte[] { 0, 0, 0, 2 }))); try { assertTrue(ch.writeInbound(Unpooled.wrappedBuffer(new byte[] { 0, 0 }))); fail(DecoderException.class.getSimpleName() + " must be raised."); } catch (TooLongFrameException e) { // Expected } ch.writeInbound(Unpooled.wrappedBuffer(new byte[] { 0, 0, 0, 1, 'A' })); ByteBuf buf = releaseLater((ByteBuf) ch.readInbound()); assertEquals("A", buf.toString(CharsetUtil.ISO_8859_1)); buf.release(); } }
@Test public void testFailFastTooLongFrameRecovery() throws Exception { EmbeddedChannel ch = new EmbeddedChannel( new LengthFieldBasedFrameDecoder(5, 0, 4, 0, 4)); for (int i = 0; i < 2; i ++) { try { assertTrue(ch.writeInbound(Unpooled.wrappedBuffer(new byte[] { 0, 0, 0, 2 }))); fail(DecoderException.class.getSimpleName() + " must be raised."); } catch (TooLongFrameException e) { // Expected } ch.writeInbound(Unpooled.wrappedBuffer(new byte[] { 0, 0, 0, 0, 0, 1, 'A' })); ByteBuf buf = releaseLater((ByteBuf) ch.readInbound()); assertEquals("A", buf.toString(CharsetUtil.ISO_8859_1)); buf.release(); } }
@Test public void testMaxFrameLengthOverflow() throws Exception { Charset charset = CharsetUtil.ISO_8859_1; // maxFrameLength plus adjustment would overflow an int final long numBytes = Integer.MAX_VALUE - 1; final int lengthAdjustment = 10; EmbeddedChannel ch = getTestChannel(charset, (int) numBytes, lengthAdjustment, true); //this is a bad frame, but will still test the overflow condition String longString = String.valueOf(numBytes) + " abcd"; try { ch.writeInbound(Unpooled.copiedBuffer(longString, charset)); Assert.fail("TooLongFrameException should have been thrown"); } catch (TooLongFrameException ignored) { //ignored } Assert.assertNull(ch.readInbound()); ch.close(); }
@Test public void testFramesDecoded() { ByteBuf buf = Unpooled.buffer(); for (int i = 0; i < 9; i++) { buf.writeByte(i); } ByteBuf input = buf.duplicate(); EmbeddedChannel channel = new EmbeddedChannel(new FrameChunkDecoder(3)); Assert.assertTrue(channel.writeInbound(input.readBytes(2))); try { channel.writeInbound(input.readBytes(4)); Assert.fail(); } catch (TooLongFrameException e) { } Assert.assertTrue(channel.writeInbound(input.readBytes(3))); Assert.assertTrue(channel.finish()); Assert.assertEquals(buf.readBytes(2), channel.readInbound()); Assert.assertEquals(buf.skipBytes(4).readBytes(3), channel.readInbound()); }
@Override public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception { if (ctx.channel().isActive()) { LOG.error("Exception occurred while processing connection pipeline", cause); if ((cause instanceof InvalidEncodingException) || (cause instanceof TooLongFrameException || (cause instanceof DecoderException))) { LOG.info("Disconnecting channel to ovsdb {}", ctx.channel()); ctx.channel().disconnect(); return; } /* In cases where a connection is quickly established and the closed Catch the IOException and close the channel. Similarly if the peer is powered off, Catch the read time out exception and close the channel */ if ((cause instanceof IOException) || (cause instanceof ReadTimeoutException)) { LOG.info("Closing channel to ovsdb {}", ctx.channel()); ctx.channel().close(); return; } LOG.error("Exception was not handled by the exception handler, re-throwing it for next handler"); ctx.fireExceptionCaught(cause); } }
private WebSocketFrame decodeBinaryFrame(ChannelHandlerContext ctx, byte type, ByteBuf buffer) { long frameSize = 0; int lengthFieldSize = 0; byte b; do { b = buffer.readByte(); frameSize <<= 7; frameSize |= b & 0x7f; if (frameSize > maxFrameSize) { throw new TooLongFrameException(); } lengthFieldSize++; if (lengthFieldSize > 8) { // Perhaps a malicious peer? throw new TooLongFrameException(); } } while ((b & 0x80) == 0x80); if (type == (byte) 0xFF && frameSize == 0) { receivedClosingHandshake = true; return new CloseWebSocketFrame(); } ByteBuf payload = readBytes(ctx.alloc(), buffer, (int) frameSize); return new BinaryWebSocketFrame(payload); }
@Override public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception { logger.error("Exception caught", cause); if (sendingError || cause instanceof IOException) return; if (cause instanceof TooLongFrameException) { sendError(ctx, BAD_REQUEST); return; } if (ctx.channel().isActive()) { sendError(ctx, INTERNAL_SERVER_ERROR); } }
@Override public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception { logger.error("channel error:" + cause.getMessage()); if (cause instanceof NettoDecoderException || cause instanceof TooLongFrameException) { this.channelHandler.caught(ctx, cause); } else if (cause instanceof IOException) { ctx.close(); } }
private void append(AppendableCharSequence seq, char c) { if (size >= maxStringLength) { throw new TooLongFrameException("String is larger than " + maxStringLength + " bytes."); } size++; seq.append(c); }
@Override public String parse(ByteBuf in) { AppendableCharSequence seq = sequenceRef.get(); seq.reset(); size = 0; for (;;) { char nextByte = (char) in.readUnsignedByte(); if (Character.isWhitespace(nextByte)) { if (size > 0) { break; } } else if (!Character.isLetterOrDigit(nextByte) && nextByte != '.' && nextByte != '-') { in.readerIndex(in.readerIndex() - 1); break; } else { if (size >= maxWordLength) { throw new TooLongFrameException( "Word is larger than " + maxWordLength + " bytes."); } size++; seq.append(nextByte); } } return seq.toString(); }
private void fail(long frameLength) { if (frameLength > 0) { throw new TooLongFrameException( "Adjusted frame length exceeds " + maxFrameLength + ": " + frameLength + " - discarded" ); } else { throw new TooLongFrameException( "Adjusted frame length exceeds " + maxFrameLength + " - discarding" ); } }
private Packet decodeFrame(ByteBuf in) { int readableBytes = in.readableBytes(); int bodyLength = in.readInt(); if (readableBytes < (bodyLength + Packet.HEADER_LEN)) { return null; } if (bodyLength > maxPacketSize) { throw new TooLongFrameException("packet body length over limit:" + bodyLength); } return decodePacket(new Packet(in.readByte()), in, bodyLength); }
protected ByteBuf tryDecodeFramedMessage(ChannelHandlerContext ctx, Channel channel, ByteBuf buffer) { // Framed messages are prefixed by the size of the frame (which doesn't // include the // framing itself). int messageStartReaderIndex = buffer.readerIndex(); int messageContentsOffset; // if (stripFraming) { messageContentsOffset = messageStartReaderIndex + MESSAGE_FRAME_SIZE; // } else { // messageContentsOffset = messageStartReaderIndex; // } // The full message is larger by the size of the frame size prefix int messageLength = buffer.getInt(messageStartReaderIndex) + MESSAGE_FRAME_SIZE; int messageContentsLength = messageStartReaderIndex + messageLength - messageContentsOffset; logger.debug("messageLength={}, rIndex={}, offset={}, readableBytes={}", messageLength, messageStartReaderIndex, messageContentsOffset, buffer.readableBytes()); if (messageContentsLength > maxFrameSize) { throw new TooLongFrameException( String.format("Frame size exceeded on encode: frame was %d bytes, maximum allowed is %d bytes", messageLength, maxFrameSize)); } if (messageLength == 0) { // Zero-sized frame: just ignore it and return nothing buffer.readerIndex(messageContentsOffset); return null; } else if (buffer.readableBytes() < messageLength) { // Full message isn't available yet, return nothing for now return null; } else { // Full message is available, return it ByteBuf messageBuffer = extractFrame(buffer, messageContentsOffset, messageContentsLength); buffer.readerIndex(messageStartReaderIndex + messageLength); return messageBuffer; } }
@Override protected void decode(ChannelHandlerContext ctx, ByteBuf in, List<Object> out) throws Exception { int readableBytes = in.readableBytes(); if(readableBytes > maxFrameSize) { //discard the bytes in.clear(); throw new TooLongFrameException(); } ByteBuf buf = in.readBytes(readableBytes); out.add(buf); }
@Test public void testFrameDecoded() { ByteBuf buf = Unpooled.buffer(); for(int i=0;i<9;i++) { buf.writeByte(i); } ByteBuf input = buf.duplicate(); EmbeddedChannel channel = new EmbeddedChannel(new FrameChunkDecoder(3)); Assert.assertTrue(channel.writeInbound(input.readBytes(2))); try{ channel.writeInbound(input.readBytes(4)); Assert.fail(); } catch(TooLongFrameException e) { System.out.println("异常: " + e.getMessage()); } Assert.assertTrue(channel.writeInbound(input.readBytes(3))); Assert.assertTrue(channel.finish()); ByteBuf read = (ByteBuf) channel.readInbound(); Assert.assertEquals(buf.readSlice(2), read); read.release(); read = (ByteBuf) channel.readInbound(); Assert.assertEquals(buf.skipBytes(4).readBytes(3),read); read.release(); buf.release(); }
@Test public void shouldHandleTooLongFrameExceptionAndAddCauseMetadata() { ApiExceptionHandlerListenerResult result = listener.shouldHandleException(new TooLongFrameException()); assertThat(result.shouldHandleResponse).isTrue(); assertThat(result.errors).isEqualTo(singletonError(testProjectApiErrors.getMalformedRequestApiError())); assertThat(result.errors.first().getMetadata().get("cause")).isEqualTo(listener.TOO_LONG_FRAME_METADATA_MESSAGE); }
@DataProvider(value = { "true", "false" }) @Test public void shouldHandleInvalidHttpRequestExceptionWithNonNullCause(boolean useTooLongFrameExceptionAsCause) { // given Throwable cause = (useTooLongFrameExceptionAsCause) ? new TooLongFrameException("TooLongFrameException occurred") : new RuntimeException("runtime exception"); String expectedCauseMetadataMessage = (useTooLongFrameExceptionAsCause) ? listener.TOO_LONG_FRAME_METADATA_MESSAGE : "Invalid HTTP request"; String outerExceptionMessage = "message - " + UUID.randomUUID().toString(); // when ApiExceptionHandlerListenerResult result = listener.shouldHandleException( new InvalidHttpRequestException(outerExceptionMessage, cause) ); // then assertThat(result.shouldHandleResponse).isTrue(); assertThat(result.errors).isEqualTo(singletonError(testProjectApiErrors.getMalformedRequestApiError())); assertThat(result.errors.first().getMetadata().get("cause")).isEqualTo(expectedCauseMetadataMessage); assertThat(result.extraDetailsForLogging.get(0).getLeft()).isEqualTo("exception_message"); assertThat(result.extraDetailsForLogging.get(0).getRight()).isEqualTo(outerExceptionMessage); assertThat(result.extraDetailsForLogging.get(1).getLeft()).isEqualTo("cause_details"); assertThat(result.extraDetailsForLogging.get(1).getRight()).isEqualTo(cause.toString()); }
@Override public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception { Channel channel = ctx.channel(); log.error("exceptionCaught={}, cause={}", channel, cause); /* Content Length의 크기가 너무 큰 경우 */ if (cause instanceof TooLongFrameException) { sendHttpMessage(new DefaultFullHttpResponse(httpVersion, HttpResponseStatus.REQUEST_ENTITY_TOO_LARGE), ctx.channel()) .addListener(ChannelFutureListener.CLOSE); } else { ctx.close(); } }
private WebSocketFrame decodeTextFrame(ChannelHandlerContext ctx, ByteBuf buffer) { int ridx = buffer.readerIndex(); int rbytes = actualReadableBytes(); int delimPos = buffer.indexOf(ridx, ridx + rbytes, (byte) 0xFF); if (delimPos == -1) { // Frame delimiter (0xFF) not found if (rbytes > maxFrameSize) { // Frame length exceeded the maximum throw new TooLongFrameException(); } else { // Wait until more data is received return null; } } int frameSize = delimPos - ridx; if (frameSize > maxFrameSize) { throw new TooLongFrameException(); } ByteBuf binaryData = ctx.alloc().buffer(frameSize); buffer.readBytes(binaryData); buffer.skipBytes(1); int ffDelimPos = binaryData.indexOf(binaryData.readerIndex(), binaryData.writerIndex(), (byte) 0xFF); if (ffDelimPos >= 0) { throw new IllegalArgumentException("a text frame should not contain 0xFF."); } return new TextWebSocketFrame(binaryData); }
private static int toFrameLength(long l) { if (l > Integer.MAX_VALUE) { throw new TooLongFrameException("Length:" + l); } else { return (int) l; } }
/** * Complementary test case of {@link #testMaxHeaderSize1()}. When it actually exceeds the maximum, it should fail. */ @Test public void testMaxHeaderSize2() { final int maxHeaderSize = 8192; final EmbeddedChannel ch = new EmbeddedChannel(new HttpResponseDecoder(4096, maxHeaderSize, 8192)); final char[] bytes = new char[maxHeaderSize / 2 - 2]; Arrays.fill(bytes, 'a'); ch.writeInbound(Unpooled.copiedBuffer("HTTP/1.1 200 OK\r\n", CharsetUtil.US_ASCII)); // Write a 4096-byte header and a 4097-byte header to test an off-by-one case (= 8193 bytes) ch.writeInbound(Unpooled.copiedBuffer("A:", CharsetUtil.US_ASCII)); ch.writeInbound(Unpooled.copiedBuffer(bytes, CharsetUtil.US_ASCII)); ch.writeInbound(Unpooled.copiedBuffer("\r\n", CharsetUtil.US_ASCII)); assertNull(ch.readInbound()); ch.writeInbound(Unpooled.copiedBuffer("B: ", CharsetUtil.US_ASCII)); // Note an extra space. ch.writeInbound(Unpooled.copiedBuffer(bytes, CharsetUtil.US_ASCII)); ch.writeInbound(Unpooled.copiedBuffer("\r\n", CharsetUtil.US_ASCII)); ch.writeInbound(Unpooled.copiedBuffer("\r\n", CharsetUtil.US_ASCII)); HttpResponse res = (HttpResponse) ch.readInbound(); assertTrue(res.getDecoderResult().cause() instanceof TooLongFrameException); assertFalse(ch.finish()); assertNull(ch.readInbound()); }
@Override protected void decode(ChannelHandlerContext ctx, ByteBuf buffer, List<Object> out) throws Exception { if (discardingTooLongFrame) { buffer.skipBytes(actualReadableBytes()); checkpoint(); return; } Unmarshaller unmarshaller = provider.getUnmarshaller(ctx); ByteInput input = new ChannelBufferByteInput(buffer); if (maxObjectSize != Integer.MAX_VALUE) { input = new LimitingByteInput(input, maxObjectSize); } try { unmarshaller.start(input); Object obj = unmarshaller.readObject(); unmarshaller.finish(); out.add(obj); } catch (LimitingByteInput.TooBigObjectException ignored) { discardingTooLongFrame = true; throw new TooLongFrameException(); } finally { // Call close in a finally block as the ReplayingDecoder will throw an Error if not enough bytes are // readable. This helps to be sure that we do not leak resource unmarshaller.close(); } }