/** * @return the {@link BodyDecoder} capable of decoding this message's body. * <p> * If the message body is not encoded, a no-op decoder is returned. */ public BodyDecoder getBodyDecoder() { return bodyDecoder == null ? new BodyDecoder() : bodyDecoder; }
/** * @return the transfer encodings applied to the HTTP message body. * <p> * RFC-7230 explicitly mentions "chunked", "compress", "deflate" and "gzip", but others may also be applied * as long as they are included in the * <a href="https://tools.ietf.org/html/rfc7230#section-8.4">Transfer Coding Registry</a>. * <p> * RawHTTP can support custom encodings by being given custom implementations of * {@link rawhttp.core.body.encoding.HttpBodyEncodingRegistry} or, more simply, by using the * {@link rawhttp.core.body.encoding.ServiceLoaderHttpBodyEncodingRegistry} mechanism, which is the default. */ public List<String> getEncodings() { return bodyDecoder.getEncodings(); }
/** * Read the HTTP message body, simultaneously unframing and decoding it, * then writing the decoded body to the given output. * <p> * This method may not validate the full HTTP message before it starts writing it out. * To perform a full validation first, call {@link #eager()} to get an eager reader. * * @param out to write the unframed, decoded message body to * @param bufferSize size of the buffer to use for writing, if possible * @throws IOException if an error occurs while writing the message * @throws UnknownEncodingException if the body is encoded with an encoding that is unknown * by the {@link HttpBodyEncodingRegistry}. */ public void writeDecodedTo(OutputStream out, int bufferSize) throws IOException { DecodingOutputStream decodedStream = framedBody.getBodyDecoder().decoding(out); framedBody.getBodyConsumer().consumeDataInto(asRawStream(), decodedStream, bufferSize); decodedStream.finishDecoding(); }
/** * Create a {@link DecodingOutputStream} that decodes the contents written to it before passing it on * to the given {@link OutputStream}. * * @param out receiver of decoded contents * @return a stream that decodes the bytes written into it, then writes the decoded bytes into another stream * @throws IOException if an error occurs while writing to the given stream */ public DecodingOutputStream decoding(OutputStream out) throws IOException { ArrayList<HttpMessageDecoder> decoders = getDecoders(); DecodingOutputStream decoderStream = new DecodingOutputStream(out); if (decoders.isEmpty()) { return decoderStream; } if (decoders.get(decoders.size() - 1).encodingName().equalsIgnoreCase("chunked")) { // when the chunked encoding is used to frame the message, we don't need to to decode its contents decoders.remove(decoders.size() - 1); } for (HttpMessageDecoder decoder : decoders) { decoderStream = decoder.decode(decoderStream); } return decoderStream; }
/** * Read the HTTP message body, simultaneously unframing and decoding it, * then writing the decoded body to the given output. * <p> * This method may not validate the full HTTP message before it starts writing it out. * To perform a full validation first, call {@link #eager()} to get an eager reader. * * @param out to write the unframed, decoded message body to * @param bufferSize size of the buffer to use for writing, if possible * @throws IOException if an error occurs while writing the message * @throws UnknownEncodingException if the body is encoded with an encoding that is unknown * by the {@link HttpBodyEncodingRegistry}. */ public void writeDecodedTo(OutputStream out, int bufferSize) throws IOException { DecodingOutputStream decodedStream = framedBody.getBodyDecoder().decoding(out); framedBody.getBodyConsumer().consumeDataInto(asRawStream(), decodedStream, bufferSize); decodedStream.finishDecoding(); }
/** * Create a {@link DecodingOutputStream} that decodes the contents written to it before passing it on * to the given {@link OutputStream}. * * @param out receiver of decoded contents * @return a stream that decodes the bytes written into it, then writes the decoded bytes into another stream * @throws IOException if an error occurs while writing to the given stream */ public DecodingOutputStream decoding(OutputStream out) throws IOException { ArrayList<HttpMessageDecoder> decoders = getDecoders(); DecodingOutputStream decoderStream = new DecodingOutputStream(out); if (decoders.isEmpty()) { return decoderStream; } if (decoders.get(decoders.size() - 1).encodingName().equalsIgnoreCase("chunked")) { // when the chunked encoding is used to frame the message, we don't need to to decode its contents decoders.remove(decoders.size() - 1); } for (HttpMessageDecoder decoder : decoders) { decoderStream = decoder.decode(decoderStream); } return decoderStream; }
/** * Create a {@link HttpMessageBody} whose contents are the given bytes. * * @param bytes contents of the body */ public BytesBody(byte[] bytes) { this(bytes, null, new BodyDecoder()); }
/** * @return the transfer encodings applied to the HTTP message body. * <p> * RFC-7230 explicitly mentions "chunked", "compress", "deflate" and "gzip", but others may also be applied * as long as they are included in the * <a href="https://tools.ietf.org/html/rfc7230#section-8.4">Transfer Coding Registry</a>. * <p> * RawHTTP can support custom encodings by being given custom implementations of * {@link rawhttp.core.body.encoding.HttpBodyEncodingRegistry} or, more simply, by using the * {@link rawhttp.core.body.encoding.ServiceLoaderHttpBodyEncodingRegistry} mechanism, which is the default. */ public List<String> getEncodings() { return bodyDecoder.getEncodings(); }
/** * Create a new instance of the {@link ContentLength} framed body. * * @param bodyLength the length of the HTTP message body */ public ContentLength(long bodyLength) { this(new BodyDecoder(), bodyLength); }
/** * Create a new instance of the {@link Chunked} body type. * * @param bodyDecoder the body encoding * @param metadataParser parser for the body trailer part */ public Chunked(BodyDecoder bodyDecoder, HttpMetadataParser metadataParser) { super(bodyDecoder); assert "chunked".equalsIgnoreCase(bodyDecoder.getEncodings().get(bodyDecoder.getEncodings().size() - 1)); this.bodyParser = new ChunkedBodyParser(metadataParser); }
/** * @return the {@link BodyDecoder} capable of decoding this message's body. * <p> * If the message body is not encoded, a no-op decoder is returned. */ public BodyDecoder getBodyDecoder() { return bodyDecoder == null ? new BodyDecoder() : bodyDecoder; }
/** * Create a new instance of the {@link Chunked} body type. * * @param bodyDecoder the body encoding * @param metadataParser parser for the body trailer part */ public Chunked(BodyDecoder bodyDecoder, HttpMetadataParser metadataParser) { super(bodyDecoder); assert "chunked".equalsIgnoreCase(bodyDecoder.getEncodings().get(bodyDecoder.getEncodings().size() - 1)); this.bodyParser = new ChunkedBodyParser(metadataParser); }
/** * Create a new instance of the {@link ContentLength} framed body. * * @param bodyLength the length of the HTTP message body */ public ContentLength(long bodyLength) { this(new BodyDecoder(), bodyLength); }
/** * Create a new {@link ChunkedBody} to encode the contents of the given stream. * <p> * The stream is read lazily, so it shouldn't be closed until this body is consumed. * * @param stream content to encode * @param contentType Content-Type of the stream contents * @param chunkLength the length of each chunk * @param bodyDecoder decoder capable of decoding the body. The last encoding must be "chunked". * @param metadataParser metadata parser (chunked body may contain metadata) * @throws IllegalArgumentException if the bodyDecoder's last encoding is not "chunked" */ public ChunkedBody(InputStream stream, @Nullable String contentType, int chunkLength, BodyDecoder bodyDecoder, HttpMetadataParser metadataParser) { super(contentType, bodyDecoder); this.stream = stream; this.chunkLength = chunkLength; this.metadataParser = metadataParser; validateEncodings(bodyDecoder.getEncodings()); }
/** * Create a {@link HttpMessageBody} whose contents are the given bytes. * * @param bytes contents of the body */ public BytesBody(byte[] bytes) { this(bytes, null, new BodyDecoder()); }
/** * Create a new {@link ChunkedBody} to encode the contents of the given stream. * <p> * The stream is read lazily, so it shouldn't be closed until this body is consumed. * * @param stream content to encode * @param contentType Content-Type of the stream contents * @param chunkLength the length of each chunk * @param bodyDecoder decoder capable of decoding the body. The last encoding must be "chunked". * @param metadataParser metadata parser (chunked body may contain metadata) * @throws IllegalArgumentException if the bodyDecoder's last encoding is not "chunked" */ public ChunkedBody(InputStream stream, @Nullable String contentType, int chunkLength, BodyDecoder bodyDecoder, HttpMetadataParser metadataParser) { super(contentType, bodyDecoder); this.stream = stream; this.chunkLength = chunkLength; this.metadataParser = metadataParser; validateEncodings(bodyDecoder.getEncodings()); }
/** * Create a {@link HttpMessageBody} whose contents are the given bytes. * * @param bytes contents of the body * @param contentType Content-Type of the body */ public BytesBody(byte[] bytes, @Nullable String contentType) { this(bytes, contentType, new BodyDecoder()); }
/** * @param headers headers object to adapt to include this HTTP message body. * @return adjusted headers for this HTTP message body. * The Content-Type and Content-Length headers may be modified to fit a HTTP message * containing this body. If the body is encoded, the Transfer-Encoding header will be set. */ public RawHttpHeaders headersFrom(RawHttpHeaders headers) { RawHttpHeaders.Builder builder = RawHttpHeaders.newBuilder(headers); getContentType().ifPresent(contentType -> builder.overwrite("Content-Type", contentType)); getContentLength().ifPresent(length -> builder.overwrite("Content-Length", Long.toString(length))); Optional.ofNullable(bodyDecoder).ifPresent(decoder -> { if (!decoder.getEncodings().isEmpty()) { builder.overwrite("Transfer-Encoding", String.join(",", decoder.getEncodings())); } }); return builder.build(); }
/** * Create a {@link HttpMessageBody} whose contents are the given bytes. * * @param bytes contents of the body * @param contentType Content-Type of the body */ public BytesBody(byte[] bytes, @Nullable String contentType) { this(bytes, contentType, new BodyDecoder()); }
/** * @param headers headers object to adapt to include this HTTP message body. * @return adjusted headers for this HTTP message body. * The Content-Type and Content-Length headers may be modified to fit a HTTP message * containing this body. If the body is encoded, the Transfer-Encoding header will be set. */ public RawHttpHeaders headersFrom(RawHttpHeaders headers) { RawHttpHeaders.Builder builder = RawHttpHeaders.newBuilder(headers); getContentType().ifPresent(contentType -> builder.overwrite("Content-Type", contentType)); getContentLength().ifPresent(length -> builder.overwrite("Content-Length", Long.toString(length))); Optional.ofNullable(bodyDecoder).ifPresent(decoder -> { if (!decoder.getEncodings().isEmpty()) { builder.overwrite("Transfer-Encoding", String.join(",", decoder.getEncodings())); } }); return builder.build(); }