@Override public HttpData decode(HttpData obj) { if (obj instanceof ByteBufHolder) { decoder.writeInbound(((ByteBufHolder) obj).content()); } else { final ByteBuf compressed = Unpooled.wrappedBuffer(obj.array(), obj.offset(), obj.length()); decoder.writeInbound(compressed); } return HttpData.of(fetchDecoderOutput()); }
static void ensureHttpDataOfString(HttpObject httpObject, String expected) { assertThat(httpObject).isInstanceOf(HttpData.class); assertThat(((HttpData) httpObject).toStringUtf8()).isEqualTo(expected); }
/** * Converts the specified formatted string into a US-ASCII {@link HttpData}. The string is formatted by * {@link String#format(Locale, String, Object...)} with {@linkplain Locale#ENGLISH English locale}. * * @param format {@linkplain Formatter the format string} of the response content * @param args the arguments referenced by the format specifiers in the format string * * @return a new {@link HttpData}. {@link #EMPTY_DATA} if {@code format} is empty. */ static HttpData ofAscii(String format, Object... args) { return of(StandardCharsets.US_ASCII, format, args); }
/** * Returns {@code true} if the content of the response with the given {@link HttpStatus} is expected to * be always empty (1xx, 204, 205 and 304 responses.) * * @throws IllegalArgumentException if the specified {@code content} or {@code trailingHeaders} are * non-empty when the content is always empty */ public static boolean isContentAlwaysEmptyWithValidation( HttpStatus status, HttpData content, HttpHeaders trailingHeaders) { if (!isContentAlwaysEmpty(status)) { return false; } if (!content.isEmpty()) { throw new IllegalArgumentException( "A " + status + " response must have empty content: " + content.length() + " byte(s)"); } if (!trailingHeaders.isEmpty()) { throw new IllegalArgumentException( "A " + status + " response must not have trailing headers: " + trailingHeaders); } return true; }
@Test public void unframed() throws Exception { final HttpClient client = HttpClient.of(server.httpUri("/")); final AggregatedHttpMessage response = client.execute( HttpHeaders.of(HttpMethod.POST, UnitTestServiceGrpc.getStaticUnaryCallMethod().getFullMethodName()) .set(HttpHeaderNames.CONTENT_TYPE, "application/protobuf"), REQUEST_MESSAGE.toByteArray()).aggregate().get(); final SimpleResponse message = SimpleResponse.parseFrom(response.content().array()); assertThat(message).isEqualTo(RESPONSE_MESSAGE); assertThat(response.headers().getInt(HttpHeaderNames.CONTENT_LENGTH)) .isEqualTo(response.content().length()); checkRequestLog((rpcReq, rpcRes, grpcStatus) -> { assertThat(rpcReq.method()).isEqualTo("armeria.grpc.testing.UnitTestService/StaticUnaryCall"); assertThat(rpcReq.params()).containsExactly(REQUEST_MESSAGE); assertThat(rpcRes.get()).isEqualTo(RESPONSE_MESSAGE); }); }
/** * Returns whether the {@link #length()} is 0. */ default boolean isEmpty() { return length() == 0; }
private ChannelFuture doWriteSplitData(int id, HttpData data, boolean endStream) { try { int offset = data.offset(); int remaining = data.length(); ChannelFuture lastFuture; for (;;) { // Ensure an HttpContent does not exceed the maximum length of a cleartext TLS record. final int chunkSize = Math.min(MAX_TLS_DATA_LENGTH, remaining); lastFuture = write(id, new DefaultHttpContent(dataChunk(data, offset, chunkSize)), false); remaining -= chunkSize; if (remaining == 0) { break; } offset += chunkSize; } if (endStream) { lastFuture = write(id, LastHttpContent.EMPTY_LAST_CONTENT, true); } ch.flush(); return lastFuture; } finally { ReferenceCountUtil.safeRelease(data); } }
@Test public void maybe() { final HttpClient client = HttpClient.of(rule.uri("/maybe")); AggregatedHttpMessage msg; msg = client.get("/string").aggregate().join(); assertThat(msg.headers().contentType()).isEqualTo(MediaType.PLAIN_TEXT_UTF_8); assertThat(msg.content().toStringUtf8()).isEqualTo("a"); msg = client.get("/json").aggregate().join(); assertThat(msg.headers().contentType()).isEqualTo(MediaType.JSON_UTF_8); assertThatJson(msg.content().toStringUtf8()).isStringEqualTo("a"); msg = client.get("/empty").aggregate().join(); assertThat(msg.headers().status()).isEqualTo(HttpStatus.OK); assertThat(msg.content().isEmpty()).isTrue(); msg = client.get("/error").aggregate().join(); assertThat(msg.headers().status()).isEqualTo(HttpStatus.INTERNAL_SERVER_ERROR); }
@Override public void onComplete() { final Iterator<HttpObject> it = received.build().iterator(); final HttpHeaders headers = (HttpHeaders) it.next(); assertThat(headers.status()).isEqualTo(HttpStatus.OK); assertThat(headers.contentType()).isEqualTo(MediaType.JSON_SEQ); // JSON Text Sequences: *(Record Separator[0x1E] JSON-text Line Feed[0x0A]) assertThat(((HttpData) it.next()).array()) .isEqualTo(new byte[] { 0x1E, '\"', 'a', '\"', 0x0A }); assertThat(((HttpData) it.next()).array()) .isEqualTo(new byte[] { 0x1E, '\"', 'b', '\"', 0x0A }); assertThat(((HttpData) it.next()).array()) .isEqualTo(new byte[] { 0x1E, '\"', 'c', '\"', 0x0A }); assertThat(((HttpData) it.next()).isEmpty()).isTrue(); assertThat(it.hasNext()).isFalse(); isFinished.set(true); } });
/** * Sends an HTTP POST request with the specified content. */ default HttpResponse post(String path, String content) { return execute(HttpHeaders.of(HttpMethod.POST, path), HttpData.ofUtf8(content)); }
private void fail(int id, HttpResponseStatus status) { discarding = true; req = null; final HttpData data = HttpData.ofUtf8(status.toString()); final com.linecorp.armeria.common.HttpHeaders headers = com.linecorp.armeria.common.HttpHeaders.of(status.code()); headers.set(HttpHeaderNames.CONNECTION, "close"); headers.setObject(HttpHeaderNames.CONTENT_TYPE, MediaType.PLAIN_TEXT_UTF_8); headers.setInt(HttpHeaderNames.CONTENT_LENGTH, data.length()); writer.writeHeaders(id, 1, headers, false); writer.writeData(id, 1, data, true).addListener(ChannelFutureListener.CLOSE); }
private boolean isNeedToRead() { return !(read || content.isEmpty()); } }
private static ByteBuf dataChunk(HttpData data, int offset, int chunkSize) { if (data instanceof ByteBufHolder) { final ByteBuf buf = ((ByteBufHolder) data).content(); return buf.retainedSlice(offset, chunkSize); } else { return Unpooled.wrappedBuffer(data.array(), offset, chunkSize); } }
private void validateEchoResponse(AggregatedHttpMessage res) { assertThat(res.status()).isEqualTo(com.linecorp.armeria.common.HttpStatus.OK); assertThat(res.content().toStringUtf8()).isEqualTo(POST_BODY); }
/** * Converts the specified {@code text} into a UTF-8 {@link HttpData}. * * @param text the {@link String} to convert * * @return a new {@link HttpData}. {@link #EMPTY_DATA} if the length of {@code text} is 0. */ static HttpData ofUtf8(String text) { return of(StandardCharsets.UTF_8, text); }
/** * Creates a new HTTP message. * * @param informationals the informational class (1xx) HTTP headers * @param headers the HTTP headers * @param content the content of the HTTP message * @param trailingHeaders the trailing HTTP headers */ static AggregatedHttpMessage of(Iterable<HttpHeaders> informationals, HttpHeaders headers, HttpData content, HttpHeaders trailingHeaders) { requireNonNull(informationals, "informationals"); requireNonNull(headers, "headers"); requireNonNull(content, "content"); requireNonNull(trailingHeaders, "trailingHeaders"); // Set the 'content-length' header if possible. final HttpStatus status = headers.status(); final HttpHeaders newHeaders; if (status != null) { // Response newHeaders = setOrRemoveContentLength(headers, content, trailingHeaders); } else { // Request newHeaders = headers.toMutable(); if (content.isEmpty()) { newHeaders.remove(CONTENT_LENGTH); } else { newHeaders.setInt(CONTENT_LENGTH, content.length()); } } return new DefaultAggregatedHttpMessage(ImmutableList.copyOf(informationals), newHeaders, content, trailingHeaders); }
@Test public void unframed_acceptEncoding() throws Exception { final HttpClient client = HttpClient.of(server.httpUri("/")); final AggregatedHttpMessage response = client.execute( HttpHeaders.of(HttpMethod.POST, UnitTestServiceGrpc.getStaticUnaryCallMethod().getFullMethodName()) .set(HttpHeaderNames.CONTENT_TYPE, "application/protobuf") .set(GrpcHeaderNames.GRPC_ACCEPT_ENCODING, "gzip,none"), REQUEST_MESSAGE.toByteArray()).aggregate().get(); final SimpleResponse message = SimpleResponse.parseFrom(response.content().array()); assertThat(message).isEqualTo(RESPONSE_MESSAGE); assertThat(response.headers().getInt(HttpHeaderNames.CONTENT_LENGTH)) .isEqualTo(response.content().length()); checkRequestLog((rpcReq, rpcRes, grpcStatus) -> { assertThat(rpcReq.method()).isEqualTo("armeria.grpc.testing.UnitTestService/StaticUnaryCall"); assertThat(rpcReq.params()).containsExactly(REQUEST_MESSAGE); assertThat(rpcRes.get()).isEqualTo(RESPONSE_MESSAGE); }); }
@Override protected void onRemoval(HttpObject obj) { if (obj instanceof HttpData) { final int length = ((HttpData) obj).length(); inboundTrafficController.dec(length); } }