@Override public void setBody(DataWrapper data) { if(data.getReadableSize() != 0) throw new IllegalArgumentException("Can't set body on HttpLastChunk according to http spec. It must be size=0"); super.setBody(data); }
private CompletableFuture<Void> writeDataFrame(DataFrame frame) { int streamId = frame.getStreamId(); log.info("actually writing data frame: " + frame); int dataSize = frame.getData().getReadableSize(); int paddingSize = frame.getPadding().getReadableSize(); if(paddingSize > 0) paddingSize += 1; int totalSize = dataSize + paddingSize; decrementOutgoingWindow(streamId, totalSize); return channel.write(ByteBuffer.wrap(marshal(frame).createByteArray())).thenAccept(c -> {}); }
public String getBodyAsString() { Charset charset = extractCharset(); //get charset from headers? DataWrapper body = getBody(); if(body == null) return null; return body.createStringFrom(0, body.getReadableSize(), charset); }
private void copyData(DataWrapper body, byte[] data, int offset) { for(int i = 0; i < body.getReadableSize(); i++) { //TODO: Think about using System.arrayCopy here(what is faster?) data[offset + i] = body.readByteAt(i); } }
private HttpMessage parseHttpMessage(DataWrapper toBeParsed, List<Integer> markedPositions) { List<String> lines = new ArrayList<>(); //Add the last line.. markedPositions.add(toBeParsed.getReadableSize()); int offset = 0; for(Integer mark : markedPositions) { int len = mark - offset; String line = toBeParsed.createStringFrom(offset, len, iso8859_1); lines.add(line.trim()); offset = mark; } markedPositions.clear(); //buffer processed...release to be re-used now.. toBeParsed.releaseUnderlyingBuffers(pool); String firstLine = lines.get(0).trim(); if(firstLine.startsWith("HTTP/")) { return parseResponse(lines); } else { return parseRequest(lines); } }
public void uncompressBodyAndAssertContainsString(String text) { Header header = getResponse().getHeaderLookupStruct().getHeader(KnownHeaderName.CONTENT_ENCODING); if(header == null) throw new IllegalStateException("Body is not compressed as no CONTENT_ENCODING header field exists"); else if(!"gzip".equals(header.getValue())) throw new IllegalStateException("Body has wrong compression type="+header.getValue()+" in CONTENT_ENCODING header field"); DataWrapper wrapper = getBody(); byte[] compressed = wrapper.createByteArray(); ByteArrayInputStream in = new ByteArrayInputStream(compressed); byte[] out = new byte[10000]; DataWrapper output = dataGen.emptyWrapper(); try (GZIPInputStream str = new GZIPInputStream(in)) { int read = 0; while((read = str.read(out)) > 0) { ByteBuffer buffer = ByteBuffer.wrap(out, 0, read); DataWrapper byteWrapper = dataGen.wrapByteBuffer(buffer); output = dataGen.chainDataWrappers(output, byteWrapper); out = new byte[10000]; } } catch(IOException e) { throw new RuntimeException(e); } Charset charset = extractCharset(); String bodyAsString = output.createStringFrom(0, output.getReadableSize(), charset); if(!bodyAsString.contains(text)) throw new IllegalStateException("Expected compressed body to contain='"+text+"' but body was="+bodyAsString); }
@Override public DataWrapper encrypt(DataWrapper data) { ByteBuffer b = ByteBuffer.wrap(data.createByteArray()); engine.feedPlainPacket(b); DataWrapper retVal = encryptedData; encryptedData = null; return retVal; } }
byte firstByte = dataToRead.readByteAt(i); byte secondByte = dataToRead.readByteAt(i+1); byte thirdByte = dataToRead.readByteAt(i+2); byte fourthByte = dataToRead.readByteAt(i+3);
@Override public CompletableFuture<List<SslAction>> parseIncoming(DataWrapper dataWrapper) { byte[] bytes = dataWrapper.createByteArray(); ByteBuffer buffer = ByteBuffer.wrap(bytes); encryptedData = null; decryptedData = null; engine.feedEncryptedPacket(buffer); return CompletableFuture.completedFuture(createResult()); }
private void processChunks(MementoImpl memento) { if(memento.getHalfParsedMessage() != null) { readInBody(memento, true); if(memento.getHalfParsedMessage() != null) return; //we are still reading in the body } int i = memento.getReadingHttpMessagePointer(); for(;i < memento.getLeftOverData().getReadableSize() - 1; i++) { DataWrapper dataToRead = memento.getLeftOverData(); byte firstByte = dataToRead.readByteAt(i); byte secondByte = dataToRead.readByteAt(i+1); boolean isFirstCr = conversion.isCarriageReturn(firstByte); boolean isSecondLineFeed = conversion.isLineFeed(secondByte); if(isFirstCr && isSecondLineFeed) { readChunk(memento, i); //since we swapped out memento.getLeftOverData to be //what's left, we can read from 0 again i = 0; if(!memento.isInChunkParsingMode() //we are done processing chunks || memento.getHalfParsedMessage() != null) //we are in the middle of processing chunk body break; } } memento.setReadingHttpMessagePointer(i); }
@Override public UnparsedState getUnParsedState() { if(inChunkParsingMode) { return new UnparsedState(ParsingState.CHUNK, leftOverData.getReadableSize()); } else if(halfParsedMessage != null) { return new UnparsedState(ParsingState.BODY, leftOverData.getReadableSize()); } return new UnparsedState(ParsingState.HEADERS, leftOverData.getReadableSize()); }
@Override public RequestId createInitialStream(HttpResponse r, HttpRequest req, ResponseListener listener, DataWrapper leftOverData) { int initialStreamId = getAndIncrementStreamId(); Stream initialStream = new Stream(); initialStream.setStreamId(initialStreamId); initializeFlowControl(initialStreamId); initialStream.setRequest(req); initialStream.setResponseListener(listener); initialStream.setResponse(r); // Since we already sent the entire request as the upgrade, the stream basically starts in // half closed local initialStream.setStatus(Stream.StreamStatus.HALF_CLOSED_LOCAL); activeStreams.put(initialStreamId, initialStream); DataWrapper responseBody = r.getBodyNonNull(); // Send the content of the response to the datalistener, if any // Not likely to happen but just in case if(responseBody.getReadableSize() > 0) { log.info("got a responsebody that we're passing on to the http2 parser"); dataListener.incomingData(getUnderlyingChannel(), ByteBuffer.wrap(responseBody.createByteArray())); } if(leftOverData.getReadableSize() > 0) { log.info("got leftover data (size="+leftOverData.getReadableSize()+") that we're passing on to the http2 parser"); dataListener.incomingData(getUnderlyingChannel(), ByteBuffer.wrap(leftOverData.createByteArray())); } return new RequestId(initialStreamId); }
private void readInBody(MementoImpl memento, boolean stripAndCompareLastTwo) { HttpPayload message = memento.getHalfParsedMessage(); DataWrapper dataToRead = memento.getLeftOverData(); int readableSize = dataToRead.getReadableSize(); int numBytesNeeded = memento.getNumBytesLeftToRead(); if(numBytesNeeded <= readableSize) { List<? extends DataWrapper> split = dataGen.split(dataToRead, numBytesNeeded); DataWrapper data = split.get(0); if(stripAndCompareLastTwo) { List<? extends DataWrapper> splitPieces = dataGen.split(data, data.getReadableSize()-2); data = splitPieces.get(0); DataWrapper trailer = splitPieces.get(1); String trailerStr = trailer.createStringFrom(0, trailer.getReadableSize(), iso8859_1); if(!TRAILER_STR.equals(trailerStr)) throw new IllegalStateException("The chunk did not end with \\r\\n . The format is invalid"); } message.setBody(data); memento.setLeftOverData(split.get(1)); memento.setNumBytesLeftToRead(0); memento.getParsedMessages().add(message); //clear any cached message we were waiting for more data for memento.setHalfParsedMessage(null); return; } }
private ByteBuffer translate(List<Http2Msg> frames) { DataWrapper allData = dataGen.emptyWrapper(); for(Http2Msg f : frames) { DataWrapper data = this.http2EngineImpl.marshal(f); allData = dataGen.chainDataWrappers(allData, data); } byte[] byteArray = allData.createByteArray(); return ByteBuffer.wrap(byteArray); }
private byte[] chunkedBytes(HttpChunk request) { DataWrapper dataWrapper = request.getBody(); int size = dataWrapper.getReadableSize(); String metaLine = request.createMetaLine(); String lastPart = request.createTrailer(); byte[] hex = metaLine.getBytes(iso8859_1); byte[] endData = lastPart.getBytes(iso8859_1); byte[] data = new byte[hex.length+size+endData.length]; //copy chunk header of <size>/r/n System.arraycopy(hex, 0, data, 0, hex.length); copyData(dataWrapper, data, hex.length); //copy closing /r/n (and headers if isLastChunk) System.arraycopy(endData, 0, data, data.length-endData.length, endData.length); return data; }
if(combined.getReadableSize() >= prefaceLength) { List<? extends DataWrapper> split = Http2EngineImpl.wrapperGen.split(combined, prefaceLength); if(Arrays.equals(split.get(0).createByteArray(), (DatatypeConverter.parseHexBinary(Http2EngineImpl.prefaceHexString)))) { gotPreface.set(true); DataWrapper afterPrefaceData = split.get(1);
String chunkMetaStr = chunkMetaData.createStringFrom(0, chunkMetaData.getReadableSize(), iso8859_1); String hexSize = chunkMetaStr.trim(); if(chunkMetaStr.contains(";")) {
void incrementIncomingWindow(int streamId, int length) { log.info("incrementing incoming window for {} by {}", streamId, length); incomingFlowControl.get(0x0).addAndGet(length); incomingFlowControl.get(streamId).addAndGet(length); WindowUpdateFrame frame = new WindowUpdateFrame(); frame.setWindowSizeIncrement(length); frame.setStreamId(0x0); channel.write(ByteBuffer.wrap(marshal(frame).createByteArray())); // reusing the frame! ack. frame.setStreamId(streamId); channel.write(ByteBuffer.wrap(marshal(frame).createByteArray())); log.info("stream {} incoming window is {} and connection window is {}", streamId, incomingFlowControl.get(streamId), incomingFlowControl.get(0)); }
public static HttpFullRequest createJsonRequest(KnownHttpMethod method, String url) { HttpRequest request = createBaseRequest(method, url); String json = "{ `query`: `cats and dogs`, `meta`: { `numResults`: 4 } }".replace("`", "\""); DataWrapper body = gen.wrapByteArray(json.getBytes()); request.addHeader(new Header(KnownHeaderName.CONTENT_LENGTH, body.getReadableSize()+"")); return new HttpFullRequest(request, body); }
@Override public void run() { PingFrame pingFrame = new PingFrame(); pingFrame.setOpaqueData(System.nanoTime()); channel.write(ByteBuffer.wrap(marshal(pingFrame).createByteArray())); } }