private CompositeBuffer toCompositeInputContentBuffer() { if (!inputContentBuffer.isComposite()) { final CompositeBuffer compositeBuffer = CompositeBuffer.newBuffer(connection.getMemoryManager()); compositeBuffer.allowBufferDispose(true); compositeBuffer.allowInternalBuffersDispose(true); int posAlign = 0; if (readAheadLimit > 0) { // the simple inputContentBuffer is marked // make the marked data still available inputContentBuffer.position(inputContentBuffer.position() - readCount); posAlign = readCount; markPos = 0; // for the CompositeBuffer markPos is 0 } compositeBuffer.append(inputContentBuffer); compositeBuffer.position(posAlign); inputContentBuffer = compositeBuffer; } return (CompositeBuffer) inputContentBuffer; }
/** {@inheritDoc} */ @Override public byte[] getResponseBodyAsBytes() throws IOException { final Buffer responseBody = getResponseBody0(); final byte[] responseBodyBytes = new byte[responseBody.remaining()]; final int origPos = responseBody.position(); responseBody.get(responseBodyBytes); responseBody.position(origPos); return responseBodyBytes; }
/** {@inheritDoc} */ public String getResponseBodyExcerpt(int maxLength, String charset) throws IOException { charset = calculateCharset(charset); final Buffer responseBody = getResponseBody0(); final int len = Math.min(responseBody.remaining(), maxLength); final int pos = responseBody.position(); return responseBody.toStringContent(getCharset(charset), pos, len + pos); }
/** * Supported with binary and character data. * * @see java.io.InputStream#mark(int) * @see java.io.Reader#mark(int) */ public void mark(final int readAheadLimit) { if (readAheadLimit > 0) { markPos = inputContentBuffer.position(); readCount = 0; this.readAheadLimit = readAheadLimit; } }
/** * Skips the specified number of bytes/characters. * * @see java.io.InputStream#skip(long) * @see java.io.Reader#skip(long) */ public long skip(final long n) throws IOException { if (LOGGER.isLoggable(LOGGER_LEVEL)) { log("InputBuffer %s skip %s bytes. Ready content: %s", this, n, inputContentBuffer); } if (closed) { throw new IOException(); } if (!processingChars) { if (n <= 0) { return 0L; } if (!inputContentBuffer.hasRemaining()) { if (fill((int) n) == -1) { return -1; } } if (inputContentBuffer.remaining() < n) { fill((int) n); } long nlen = Math.min(inputContentBuffer.remaining(), n); inputContentBuffer.position(inputContentBuffer.position() + (int) nlen); if (!checkMarkAfterRead(n)) { inputContentBuffer.shrink(); } return nlen; } else { if (n < 0) { // required by java.io.Reader.skip() throw new IllegalArgumentException(); } if (n == 0) { return 0L; } final CharBuffer skipBuffer = CharBuffer.allocate((int) n); if (fillChars((int) n, skipBuffer) == -1) { return 0; } return Math.min(skipBuffer.remaining(), n); } }
/** * Used to convert pre-read (buffered) bytes to chars. * * @param requestedLen how much content should attempt to be read * @return the number of chars actually read */ private int fillAvailableChars(final int requestedLen, final CharBuffer dst) { final CharsetDecoder decoderLocal = getDecoder(); final ByteBuffer bb = inputContentBuffer.toByteBuffer(); final int oldBBPos = bb.position(); int producedChars = 0; int consumedBytes = 0; int producedCharsNow; int consumedBytesNow; CoderResult result; int remaining = requestedLen; do { final int charPos = dst.position(); final int bbPos = bb.position(); result = decoderLocal.decode(bb, dst, false); producedCharsNow = dst.position() - charPos; consumedBytesNow = bb.position() - bbPos; producedChars += producedCharsNow; consumedBytes += consumedBytesNow; remaining -= producedCharsNow; } while (remaining > 0 && (producedCharsNow > 0 || consumedBytesNow > 0) && bb.hasRemaining() && result == CoderResult.UNDERFLOW); bb.position(oldBBPos); inputContentBuffer.position(inputContentBuffer.position() + consumedBytes); if (readAheadLimit == -1) { inputContentBuffer.shrink(); } return producedChars; }
@Override public void process(Buffer source, HeaderFieldTable.DecTable table, HeaderListener handler) { ObjectHolder<String> s = new ObjectHolder<>(); String name; int beginning = source.position(); byte b = source.get(); if ((b & 0b111111) == 0) { readString(source, s); name = s.getObj(); } else { source.position(beginning); int index = readInteger(source, 6); HeaderField e = table.get(index); name = e.getName(); } readString(source, s); String value = s.getObj(); HeaderField f = new HeaderField(name, value); table.put(f); handler.onDecodedHeader(name, value); }
/** * Only supported with binary data. * * @see java.io.InputStream#reset() */ public void reset() throws IOException { if (closed) { throw new IOException(); } if (readAheadLimit == -1) { throw new IOException("Mark not set"); } readCount = 0; inputContentBuffer.position(markPos); }
public Result find(PUContext puc, FilterChainContext fcc) { final Buffer buffer = fcc.getMessage(); if (buffer.remaining() >= signature.length) { final int start = buffer.position(); for (int i = 0; i < signature.length; i++) { if (buffer.get(start + i) != signature[i]) { return Result.NOT_FOUND; } } return Result.FOUND; } return Result.NEED_MORE_DATA; }
@Override public void notifyDirectUpdate() { if (type == Type.Buffer) { final int start = getStart(); final int end = getEnd(); final byte[] bytes = new byte[end - start]; final Buffer currentBuffer = getBufferChunk().getBuffer(); final int pos = currentBuffer.position(); final int lim = currentBuffer.limit(); Buffers.setPositionLimit(currentBuffer, start, end); currentBuffer.get(bytes); Buffers.setPositionLimit(currentBuffer, pos, lim); setBytes(bytes); } }
static void decodeRequest( final Buffer requestContent, final AjpHttpRequest req, final boolean tomcatAuthentication) throws IOException { // FORWARD_REQUEST handler int offset = requestContent.position(); // Translate the HTTP method code to a String. byte methodCode = requestContent.get(offset++); if (methodCode != AjpConstants.SC_M_JK_STORED) { String mName = AjpConstants.methodTransArray[(int) methodCode - 1]; req.getMethodDC().setString(mName); } offset = getBytesToDataChunk(requestContent, offset, req.getProtocolDC()); final int requestURILen = readShort(requestContent, offset); if (!isNullLength(requestURILen)) { req.getRequestURIRef().init(requestContent, offset + 2, offset + 2 + requestURILen); } // Don't forget to skip the terminating \0 (that's why "+ 1") offset += 2 + requestURILen + 1; offset = getBytesToDataChunk(requestContent, offset, req.remoteAddr()); offset = getBytesToDataChunk(requestContent, offset, req.remoteHostRaw()); offset = getBytesToDataChunk(requestContent, offset, req.localName()); req.setLocalPort(readShort(requestContent, offset)); offset += 2; final boolean isSSL = requestContent.get(offset++) != 0; req.setSecure(isSSL); req.getResponse().setSecure(isSSL); offset = decodeHeaders(requestContent, offset, req); decodeAttributes(requestContent, offset, req, tomcatAuthentication); req.setUnparsedHostHeader(req.getHeaders().getValue("host")); }
public static Buffer appendContentAndTrim( final MemoryManager memoryManager, Buffer dstBuffer, Buffer httpContentBuffer) { Buffer resultBuffer = null; do { Buffer contentRemainder = null; if (httpContentBuffer.remaining() > MAX_BODY_CHUNK_CONTENT_SIZE) { contentRemainder = httpContentBuffer.split(httpContentBuffer.position() + MAX_BODY_CHUNK_CONTENT_SIZE); } final Buffer encodedContentChunk = appendContentChunkAndTrim(memoryManager, dstBuffer, httpContentBuffer); resultBuffer = Buffers.appendBuffers(memoryManager, resultBuffer, encodedContentChunk); // dstBuffer use only once, when it comes from caller dstBuffer = null; httpContentBuffer = contentRemainder; } while (httpContentBuffer != null && httpContentBuffer.hasRemaining()); return resultBuffer; }
/** * @param size the requested size of the {@link Buffer} to be returned. * @return the {@link Buffer} of a given size, which represents a chunk of the underlying {@link * Buffer} which contains incoming request data. This method detaches the returned {@link * Buffer}, so user code becomes responsible for handling its life-cycle. */ public Buffer readBuffer(final int size) { if (LOGGER.isLoggable(LOGGER_LEVEL)) { log( "InputBuffer %s readBuffer(size), size: %s. Ready content: %s", this, size, inputContentBuffer); } final int remaining = inputContentBuffer.remaining(); if (size > remaining) { throw new IllegalStateException("Can not read more bytes than available"); } final Buffer buffer; if (size == remaining) { buffer = inputContentBuffer; inputContentBuffer = Buffers.EMPTY_BUFFER; } else { final Buffer tmpBuffer = inputContentBuffer.split(inputContentBuffer.position() + size); buffer = inputContentBuffer; inputContentBuffer = tmpBuffer; } return buffer; }
public void setReasonPhrase(final Buffer reason) { reasonPhraseC.setBuffer(reason, reason.position(), reason.limit()); }
public static Buffer encodeHeaders( final MemoryManager mm, final HttpResponsePacket httpResponsePacket) { Buffer encodedBuffer = mm.allocate(4096); int startPos = encodedBuffer.position(); // Skip 4 bytes for the Ajp header encodedBuffer.position(startPos + 4); encodedBuffer.put(AjpConstants.JK_AJP13_SEND_HEADERS); encodedBuffer.putShort((short) httpResponsePacket.getStatus()); final byte[] tempBuffer = httpResponsePacket.getTempHeaderEncodingBuffer(); if (httpResponsePacket.isCustomReasonPhraseSet()) { encodedBuffer = putBytes( mm, encodedBuffer, HttpStatus.filter(httpResponsePacket.getReasonPhraseDC()), tempBuffer); } else { encodedBuffer = putBytes(mm, encodedBuffer, httpResponsePacket.getHttpStatus().getReasonPhraseBytes()); } if (httpResponsePacket.isAcknowledgement()) { // If it's acknoledgment packet - don't encode the headers // Serialize 0 num_headers encodedBuffer = putShort(mm, encodedBuffer, 0); } else { final MimeHeaders headers = httpResponsePacket.getHeaders(); final String contentType = httpResponsePacket.getContentType(); if (contentType != null) { headers.setValue("Content-Type").setString(contentType); } final String contentLanguage = httpResponsePacket.getContentLanguage(); if (contentLanguage != null) { headers.setValue("Content-Language").setString(contentLanguage); } final long contentLength = httpResponsePacket.getContentLength(); if (contentLength >= 0) { final Buffer contentLengthBuffer = getLongAsBuffer(mm, contentLength); headers .setValue("Content-Length") .setBuffer( contentLengthBuffer, contentLengthBuffer.position(), contentLengthBuffer.limit()); } final int numHeaders = headers.size(); encodedBuffer = putShort(mm, encodedBuffer, numHeaders); for (int i = 0; i < numHeaders; i++) { final DataChunk headerName = headers.getName(i); encodedBuffer = putBytes(mm, encodedBuffer, headerName, tempBuffer); final DataChunk headerValue = headers.getValue(i); encodedBuffer = putBytes(mm, encodedBuffer, headerValue, tempBuffer); } } // Add Ajp message header encodedBuffer.put(startPos, (byte) 'A'); encodedBuffer.put(startPos + 1, (byte) 'B'); encodedBuffer.putShort(startPos + 2, (short) (encodedBuffer.position() - startPos - 4)); return encodedBuffer; }
/** * Used to convert bytes to chars. * * @param requestedLen how much content should attempt to be read * @return the number of chars actually read * @throws IOException if an I/O error occurs while reading content */ private int fillChars(final int requestedLen, final CharBuffer dst) throws IOException { int read = 0; // 1) Check pre-decoded singleCharBuf if (dst != singleCharBuf && singleCharBuf.hasRemaining()) { dst.put(singleCharBuf.get()); read = 1; } // 2) Decode available byte[] -> char[] if (inputContentBuffer.hasRemaining()) { read += fillAvailableChars(requestedLen - read, dst); } if (read >= requestedLen) { dst.flip(); return read; } // 3) If we don't expect more data - return what we've read so far if (!httpHeader.isExpectContent()) { dst.flip(); return read > 0 ? read : -1; } // 4) Try to read more data (we may block) CharsetDecoder decoderLocal = getDecoder(); boolean isNeedMoreInput = false; // true, if content in composite buffer is not enough to produce even 1 char boolean last = false; while (read < requestedLen && httpHeader.isExpectContent()) { if (isNeedMoreInput || !inputContentBuffer.hasRemaining()) { final HttpContent c = blockingRead(); updateInputContentBuffer(c.getContent()); last = c.isLast(); c.recycle(); isNeedMoreInput = false; } final ByteBuffer bytes = inputContentBuffer.toByteBuffer(); final int bytesPos = bytes.position(); final int dstPos = dst.position(); final CoderResult result = decoderLocal.decode(bytes, dst, false); final int producedChars = dst.position() - dstPos; final int consumedBytes = bytes.position() - bytesPos; read += producedChars; if (consumedBytes > 0) { bytes.position(bytesPos); inputContentBuffer.position(inputContentBuffer.position() + consumedBytes); if (readAheadLimit == -1) { inputContentBuffer.shrink(); } } else { isNeedMoreInput = true; } if (last || result == CoderResult.OVERFLOW) { break; } } dst.flip(); if (last && read == 0) { read = -1; } return read; }