public static DataEmitter getBodyDecoder( DataEmitter emitter, RawHeaders headers, boolean server) { long _contentLength; try { _contentLength = Long.parseLong(headers.get("Content-Length")); } catch (Exception ex) { _contentLength = -1; } final long contentLength = _contentLength; if (-1 != contentLength) { if (contentLength < 0) { EndEmitter ender = EndEmitter.create( emitter.getServer(), new BodyDecoderException( "not using chunked encoding, and no content-length found.")); ender.setDataEmitter(emitter); emitter = ender; return emitter; } if (contentLength == 0) { EndEmitter ender = EndEmitter.create(emitter.getServer(), null); ender.setDataEmitter(emitter); emitter = ender; return emitter; } ContentLengthFilter contentLengthWatcher = new ContentLengthFilter(contentLength); contentLengthWatcher.setDataEmitter(emitter); emitter = contentLengthWatcher; } else if ("chunked".equalsIgnoreCase(headers.get("Transfer-Encoding"))) { ChunkedInputFilter chunker = new ChunkedInputFilter(); chunker.setDataEmitter(emitter); emitter = chunker; } else { if ((server || headers.getStatusLine().contains("HTTP/1.1")) && !"close".equalsIgnoreCase(headers.get("Connection"))) { // if this is the server, and the client has not indicated a request body, the client is // done EndEmitter ender = EndEmitter.create(emitter.getServer(), null); ender.setDataEmitter(emitter); emitter = ender; return emitter; } } if ("gzip".equals(headers.get("Content-Encoding"))) { GZIPInputFilter gunzipper = new GZIPInputFilter(); gunzipper.setDataEmitter(emitter); emitter = gunzipper; } else if ("deflate".equals(headers.get("Content-Encoding"))) { InflaterInputFilter inflater = new InflaterInputFilter(); inflater.setDataEmitter(emitter); emitter = inflater; } // conversely, if this is the client (http 1.0), and the server has not indicated a request // body, we do not report // the close/end event until the server actually closes the connection. return emitter; }
@Override @SuppressWarnings("unused") public void onDataAvailable(final DataEmitter emitter, ByteBufferList bb) { if (mNeedsHeader) { final PushParser parser = new PushParser(emitter); parser.readByteArray( 10, new ParseCallback<byte[]>() { int flags; boolean hcrc; public void parsed(byte[] header) { short magic = peekShort(header, 0, ByteOrder.LITTLE_ENDIAN); if (magic != (short) GZIPInputStream.GZIP_MAGIC) { report(new IOException(String.format("unknown format (magic number %x)", magic))); emitter.setDataCallback(new NullDataCallback()); return; } flags = header[3]; hcrc = (flags & FHCRC) != 0; if (hcrc) { crc.update(header, 0, header.length); } if ((flags & FEXTRA) != 0) { parser.readByteArray( 2, new ParseCallback<byte[]>() { public void parsed(byte[] header) { if (hcrc) { crc.update(header, 0, 2); } int length = peekShort(header, 0, ByteOrder.LITTLE_ENDIAN) & 0xffff; parser.readByteArray( length, new ParseCallback<byte[]>() { public void parsed(byte[] buf) { if (hcrc) { crc.update(buf, 0, buf.length); } next(); } }); } }); } else { next(); } } private void next() { PushParser parser = new PushParser(emitter); DataCallback summer = new DataCallback() { @Override public void onDataAvailable(DataEmitter emitter, ByteBufferList bb) { if (hcrc) { while (bb.size() > 0) { ByteBuffer b = bb.remove(); crc.update(b.array(), b.arrayOffset() + b.position(), b.remaining()); ByteBufferList.reclaim(b); } } bb.recycle(); done(); } }; if ((flags & FNAME) != 0) { parser.until((byte) 0, summer); return; } if ((flags & FCOMMENT) != 0) { parser.until((byte) 0, summer); return; } done(); } private void done() { if (hcrc) { parser.readByteArray( 2, new ParseCallback<byte[]>() { public void parsed(byte[] header) { short crc16 = peekShort(header, 0, ByteOrder.LITTLE_ENDIAN); if ((short) crc.getValue() != crc16) { report(new IOException("CRC mismatch")); return; } crc.reset(); mNeedsHeader = false; setDataEmitter(emitter); // emitter.setDataCallback(GZIPInputFilter.this); } }); } else { mNeedsHeader = false; setDataEmitter(emitter); } } }); } else { super.onDataAvailable(emitter, bb); } }