/** * Converts the specified {@code request} to {@link Optional} which contains {@link WatchRequest} when * the request has {@link HttpHeaderNames#IF_NONE_MATCH}. {@link Optional#EMPTY} otherwise. */ @Override public Object convertRequest(ServiceRequestContext ctx, AggregatedHttpMessage request, Class<?> expectedResultType) throws Exception { final String ifNoneMatch = request.headers().get(AsciiString.of("if-none-match")); if (!isNullOrEmpty(ifNoneMatch)) { final Revision lastKnownRevision = new Revision(ifNoneMatch); final String prefer = request.headers().get(AsciiString.of("prefer")); final long timeoutMillis; if (!isNullOrEmpty(prefer)) { timeoutMillis = getTimeoutMillis(prefer); } else { timeoutMillis = DEFAULT_TIMEOUT_MILLIS; } return Optional.of(new WatchRequest(lastKnownRevision, timeoutMillis)); } return Optional.empty(); }
@Test public void turnOff() throws Exception { service.serverHealth.setHealthy(true); AggregatedHttpMessage res = service.serve(context, HC_TURN_OFF_REQ).aggregate().get(); assertThat(res.status(), is(HttpStatus.OK)); assertThat(res.headers().get(AsciiString.of(HttpHeaders.CONTENT_TYPE)), is(MediaType.PLAIN_TEXT_UTF_8.toString())); assertThat(res.content().toStringUtf8(), is("Set unhealthy.")); res = service.serve(context, HC_REQ).aggregate().get(); assertThat(res.status(), is(HttpStatus.SERVICE_UNAVAILABLE)); assertThat(res.headers().get(AsciiString.of(HttpHeaders.CONTENT_TYPE)), is(MediaType.PLAIN_TEXT_UTF_8.toString())); }
private HttpData serializeTrailersAsMessage(HttpHeaders trailers) { ByteBuf serialized = ctx.alloc().buffer(); boolean success = false; try { serialized.writeByte(TRAILERS_FRAME_HEADER); // Skip, we'll set this after serializing the headers. serialized.writeInt(0); for (Map.Entry<AsciiString, String> trailer : trailers) { encodeHeader(trailer.getKey(), trailer.getValue(), serialized); } int messageSize = serialized.readableBytes() - 5; serialized.setInt(1, messageSize); success = true; } finally { if (!success) { serialized.release(); } } return new ByteBufHttpData(serialized, true); }
@Test public void missingMethod() throws Exception { when(ctx.mappedPath()).thenReturn("/grpc.testing.TestService/FooCall"); HttpResponse response = grpcService.doPost( ctx, HttpRequest.of(HttpHeaders.of(HttpMethod.POST, "/grpc.testing.TestService/FooCall") .set(HttpHeaderNames.CONTENT_TYPE, "application/grpc+proto"))); assertThat(response.aggregate().get()).isEqualTo(AggregatedHttpMessage.of( HttpHeaders.of(HttpStatus.OK) .set(HttpHeaderNames.CONTENT_TYPE, "application/grpc+proto") .set(AsciiString.of("grpc-status"), "12") .set(AsciiString.of("grpc-message"), "Method not found: grpc.testing.TestService/FooCall") .set(HttpHeaderNames.CONTENT_LENGTH, "0"), HttpData.of(new byte[] {}))); }
@Test(timeout = 10000) public void testDerivedClient() throws Exception { final String AUTHORIZATION = "authorization"; final String NO_TOKEN = ""; final String TOKEN_A = "token 1234"; final String TOKEN_B = "token 5678"; final HeaderService.Iface client = Clients.newClient(clientFactory(), getURI(Handlers.HEADER), Handlers.HEADER.iface(), clientOptions); assertThat(client.header(AUTHORIZATION)).isEqualTo(NO_TOKEN); final HeaderService.Iface clientA = Clients.newDerivedClient(client, newHttpHeaderOption(AsciiString.of(AUTHORIZATION), TOKEN_A)); final HeaderService.Iface clientB = Clients.newDerivedClient(client, newHttpHeaderOption(AsciiString.of(AUTHORIZATION), TOKEN_B)); assertThat(clientA.header(AUTHORIZATION)).isEqualTo(TOKEN_A); assertThat(clientB.header(AUTHORIZATION)).isEqualTo(TOKEN_B); // Ensure that the parent client's HTTP_HEADERS option did not change: assertThat(client.header(AUTHORIZATION)).isEqualTo(NO_TOKEN); }
private void configureHttp1WithUpgrade(ChannelHandlerContext ctx) { final ChannelPipeline p = ctx.pipeline(); final HttpServerCodec http1codec = new HttpServerCodec( config.defaultMaxHttp1InitialLineLength(), config.defaultMaxHttp1HeaderSize(), config.defaultMaxHttp1ChunkSize()); String baseName = name; baseName = addAfter(p, baseName, http1codec); baseName = addAfter(p, baseName, new HttpServerUpgradeHandler( http1codec, protocol -> { if (!AsciiString.contentEquals(Http2CodecUtil.HTTP_UPGRADE_PROTOCOL_NAME, protocol)) { return null; } return new Http2ServerUpgradeCodec( newHttp2ConnectionHandler(p)); }, UPGRADE_REQUEST_MAX_LENGTH)); addAfter(p, baseName, new Http1RequestDecoder(config, ctx.channel(), SCHEME_HTTP)); }
/** * Returns HTTP response headers that should be added to a CORS preflight response. * * @return {@link HttpHeaders} the HTTP response headers to be added. * * @throws IllegalStateException if CORS support is not enabled */ public HttpHeaders preflightResponseHeaders() { ensureEnabled(); if (preflightResponseHeaders.isEmpty()) { return HttpHeaders.EMPTY_HEADERS; } final HttpHeaders preflightHeaders = new DefaultHttpHeaders(false); for (Entry<AsciiString, Supplier<?>> entry : preflightResponseHeaders.entrySet()) { final Object value = getValue(entry.getValue()); if (value instanceof Iterable) { preflightHeaders.addObject(entry.getKey(), (Iterable<?>) value); } else { preflightHeaders.addObject(entry.getKey(), value); } } return preflightHeaders; }
/** * Converts the specified Netty HTTP/2 into Armeria HTTP/2 headers. */ public static HttpHeaders toArmeria(Http2Headers headers) { final HttpHeaders converted = new DefaultHttpHeaders(false, headers.size()); StringJoiner cookieJoiner = null; for (Entry<CharSequence, CharSequence> e : headers) { final AsciiString name = AsciiString.of(e.getKey()); final CharSequence value = e.getValue(); // Cookies must be concatenated into a single octet string. // https://tools.ietf.org/html/rfc7540#section-8.1.2.5 if (name.equals(HttpHeaderNames.COOKIE)) { if (cookieJoiner == null) { cookieJoiner = new StringJoiner(COOKIE_SEPARATOR); } COOKIE_SPLITTER.split(value).forEach(cookieJoiner::add); } else { converted.add(name, value.toString()); } } if (cookieJoiner != null && cookieJoiner.length() != 0) { converted.add(HttpHeaderNames.COOKIE, cookieJoiner.toString()); } return converted; }
/** * Filter the {@link HttpHeaderNames#TE} header according to the * <a href="https://tools.ietf.org/html/rfc7540#section-8.1.2.2">special rules in the HTTP/2 RFC</a>. * @param entry An entry whose name is {@link HttpHeaderNames#TE}. * @param out the resulting HTTP/2 headers. */ private static void toHttp2HeadersFilterTE(Entry<CharSequence, CharSequence> entry, HttpHeaders out) { if (AsciiString.indexOf(entry.getValue(), ',', 0) == -1) { if (AsciiString.contentEqualsIgnoreCase(AsciiString.trim(entry.getValue()), HttpHeaderValues.TRAILERS)) { out.add(HttpHeaderNames.TE, HttpHeaderValues.TRAILERS.toString()); } } else { List<CharSequence> teValues = StringUtil.unescapeCsvFields(entry.getValue()); for (CharSequence teValue : teValues) { if (AsciiString.contentEqualsIgnoreCase(AsciiString.trim(teValue), HttpHeaderValues.TRAILERS)) { out.add(HttpHeaderNames.TE, HttpHeaderValues.TRAILERS.toString()); break; } } } }
@Test public void notSupported() throws Exception { HttpRequestWriter noopRequest = HttpRequest.streaming(HttpMethod.PUT, "/"); noopRequest.write(() -> HttpData.ofAscii("noop")); noopRequest.close(); AggregatedHttpMessage res = service.serve(context, noopRequest).aggregate().get(); assertThat(res.status(), is(HttpStatus.BAD_REQUEST)); assertThat(res.headers().get(AsciiString.of(HttpHeaders.CONTENT_TYPE)), is(MediaType.PLAIN_TEXT_UTF_8.toString())); assertThat(res.content().toStringUtf8(), is("Not supported.")); service.serverHealth.setHealthy(true); noopRequest = HttpRequest.streaming(HttpMethod.PUT, "/"); noopRequest.write(() -> HttpData.ofAscii("noop")); noopRequest.close(); res = service.serve(context, noopRequest).aggregate().get(); assertThat(res.status(), is(HttpStatus.BAD_REQUEST)); assertThat(res.headers().get(AsciiString.of(HttpHeaders.CONTENT_TYPE)), is(MediaType.PLAIN_TEXT_UTF_8.toString())); assertThat(res.content().toStringUtf8(), is("Not supported.")); }
@Test public void test400(final TestContext testContext) throws Exception { final HttpServerRequest serverRequest = mock(HttpServerRequest.class); when(serverRequest.absoluteURI()).thenReturn("http://test.trajano.net/api/hello/400"); when(serverRequest.path()).thenReturn("/api/hello/400"); when(serverRequest.uri()).thenReturn("/api/hello/400"); when(serverRequest.isEnded()).thenReturn(true); when(serverRequest.method()).thenReturn(HttpMethod.GET); final HttpServerResponse response = mock(HttpServerResponse.class); when(response.putHeader(anyString(), anyString())).thenReturn(response); when(response.putHeader(any(AsciiString.class), anyString())).thenReturn(response); when(response.headers()).thenReturn(new VertxHttpHeaders()); final Async async = testContext.async(); when(response.setStatusCode(Matchers.any(Integer.class))).then(invocation -> { try { return response; } finally { async.complete(); } }); when(serverRequest.response()).thenReturn(response); router.accept(serverRequest); async.awaitSuccess(); verify(response, times(1)).setStatusCode(400); }
@Test public void test404(final TestContext testContext) throws Exception { final Router router = Router.router(rule.vertx()); final JaxRsRouter jaxRsRouter = new JaxRsRouter(); final SpringJaxRsHandler handler = new SpringJaxRsHandler(MyApp.class); jaxRsRouter.register(MyApp.class, router, handler, handler); final HttpServerRequest serverRequest = mock(HttpServerRequest.class); when(serverRequest.absoluteURI()).thenReturn("http://test.trajano.net/api/nothello"); when(serverRequest.path()).thenReturn("/api/nothello"); when(serverRequest.uri()).thenReturn("/api/nothello"); when(serverRequest.isEnded()).thenReturn(true); when(serverRequest.method()).thenReturn(HttpMethod.GET); final HttpServerResponse response = mock(HttpServerResponse.class); when(response.putHeader(anyString(), anyString())).thenReturn(response); when(response.putHeader(any(AsciiString.class), anyString())).thenReturn(response); when(response.headers()).thenReturn(new VertxHttpHeaders()); final Async async = testContext.async(); Mockito.doAnswer(invocation -> { async.complete(); return null; }).when(response).end(anyString()); when(serverRequest.response()).thenReturn(response); router.accept(serverRequest); async.await(); verify(response, times(1)).setStatusCode(404); verify(response, times(1)).end(anyString()); }
@Test public void test404Internal(final TestContext testContext) throws Exception { final Router router = Router.router(rule.vertx()); final JaxRsRouter jaxRsRouter = new JaxRsRouter(); final SpringJaxRsHandler handler = new SpringJaxRsHandler(MyApp.class); jaxRsRouter.register(MyApp.class, router, handler, handler); final HttpServerRequest serverRequest = mock(HttpServerRequest.class); when(serverRequest.absoluteURI()).thenReturn("http://test.trajano.net/api/hello/404"); when(serverRequest.path()).thenReturn("/api/hello/404"); when(serverRequest.uri()).thenReturn("/api/hello/404"); when(serverRequest.isEnded()).thenReturn(true); when(serverRequest.method()).thenReturn(HttpMethod.GET); final HttpServerResponse response = mock(HttpServerResponse.class); when(response.putHeader(anyString(), anyString())).thenReturn(response); when(response.putHeader(any(AsciiString.class), anyString())).thenReturn(response); when(response.headers()).thenReturn(new VertxHttpHeaders()); final Async async = testContext.async(); when(response.setStatusCode(Matchers.any(Integer.class))).then(invocation -> { try { return response; } finally { async.complete(); } }); when(serverRequest.response()).thenReturn(response); router.accept(serverRequest); async.await(); verify(response, times(1)).setStatusCode(404); }
@Test public void test500(final TestContext testContext) throws Exception { final Router router = Router.router(rule.vertx()); final JaxRsRouter jaxRsRouter = new JaxRsRouter(); final SpringJaxRsHandler handler = new SpringJaxRsHandler(MyApp.class); jaxRsRouter.register(MyApp.class, router, handler, handler); final HttpServerRequest serverRequest = mock(HttpServerRequest.class); when(serverRequest.absoluteURI()).thenReturn("http://test.trajano.net/api/hello/cough"); when(serverRequest.path()).thenReturn("/api/hello/cough"); when(serverRequest.uri()).thenReturn("/api/hello/cough"); when(serverRequest.isEnded()).thenReturn(true); when(serverRequest.method()).thenReturn(HttpMethod.GET); final HttpServerResponse response = mock(HttpServerResponse.class); when(response.putHeader(anyString(), anyString())).thenReturn(response); when(response.putHeader(any(AsciiString.class), anyString())).thenReturn(response); when(response.headers()).thenReturn(new VertxHttpHeaders()); final Async async = testContext.async(); when(response.write(Matchers.any(Buffer.class))).thenReturn(response); doAnswer(i -> { async.complete(); return null; }).when(response).end(); when(serverRequest.response()).thenReturn(response); router.accept(serverRequest); async.awaitSuccess(); final ArgumentCaptor<Buffer> captor = ArgumentCaptor.forClass(Buffer.class); verify(response, times(1)).setStatusCode(500); verify(response, atLeastOnce()).write(captor.capture()); final String errorMessage = String.join("", captor.getAllValues().stream().map(Buffer::toString).collect(Collectors.toList())); assertTrue(errorMessage.contains("server_error")); }
@Test public void testFailure(final TestContext testContext) throws Exception { final HttpServerRequest serverRequest = mock(HttpServerRequest.class); when(serverRequest.absoluteURI()).thenThrow(new RuntimeException("boom")); when(serverRequest.path()).thenReturn("/api/hello/400"); when(serverRequest.uri()).thenReturn("/api/hello/400"); when(serverRequest.isEnded()).thenReturn(true); when(serverRequest.method()).thenReturn(HttpMethod.GET); final HttpServerResponse response = mock(HttpServerResponse.class); when(response.putHeader(anyString(), anyString())).thenReturn(response); when(response.putHeader(any(AsciiString.class), anyString())).thenReturn(response); when(response.headers()).thenReturn(new VertxHttpHeaders()); final Async async = testContext.async(); when(response.setStatusCode(Matchers.any(Integer.class))).then(invocation -> { try { return response; } finally { async.complete(); } }); when(serverRequest.response()).thenReturn(response); router.accept(serverRequest); async.await(); verify(response, times(1)).setStatusCode(500); }
@Test public void testHandler(final TestContext testContext) throws Exception { final Router router = Router.router(rule.vertx()); final JaxRsRouter jaxRsRouter = new JaxRsRouter(); final SpringJaxRsHandler handler = new SpringJaxRsHandler(MyApp.class); jaxRsRouter.register(MyApp.class, router, handler, handler); final HttpServerRequest serverRequest = mock(HttpServerRequest.class); when(serverRequest.absoluteURI()).thenReturn("http://test.trajano.net/api/hello"); when(serverRequest.path()).thenReturn("/api/hello"); when(serverRequest.uri()).thenReturn("/api/hello"); when(serverRequest.isEnded()).thenReturn(true); when(serverRequest.method()).thenReturn(HttpMethod.GET); final HttpServerResponse response = mock(HttpServerResponse.class); when(response.putHeader(anyString(), anyString())).thenReturn(response); when(response.putHeader(any(AsciiString.class), anyString())).thenReturn(response); when(response.headers()).thenReturn(new VertxHttpHeaders()); final Async async = testContext.async(); when(response.write(Matchers.any(Buffer.class))).then(invocation -> { try { return response; } finally { async.complete(); } }); when(serverRequest.response()).thenReturn(response); router.accept(serverRequest); async.await(); final ArgumentCaptor<Buffer> captor = ArgumentCaptor.forClass(Buffer.class); verify(response, times(1)).setStatusCode(200); verify(response, times(1)).setChunked(true); verify(response, times(1)).write(captor.capture()); assertTrue(captor.getValue().toString().startsWith("Hello")); }
public static AsciiString readLELengthAsciiString(ByteBuf buffer) { Preconditions.checkNotNull(buffer, "buffer"); int length = buffer.readIntLE(); byte[] bytes = new byte[length]; buffer.readBytes(bytes); return new AsciiString(bytes); }
@Test public void leLengthString() throws Exception { ByteBuf dest = Unpooled.buffer(); AsciiString string = AsciiString.of("test"); McpeUtil.writeLELengthAsciiString(dest, string); assertEquals(string, McpeUtil.readLELengthAsciiString(dest)); dest.release(); }
@Override public UpgradeCodec newUpgradeCodec(CharSequence protocol) { if (AsciiString.contentEquals(Http2CodecUtil.HTTP_UPGRADE_PROTOCOL_NAME, protocol)) { return new Http2ServerUpgradeCodec(new Http2MultiplexCodec(true, new HelloWorldHttp2Handler())); } else { return null; } }
/** * Handles the cleartext HTTP upgrade event. If an upgrade occurred, sends a simple response via HTTP/2 * on stream 1 (the stream specifically reserved for cleartext HTTP upgrade). */ @Override public void userEventTriggered(ChannelHandlerContext ctx, Object evt) throws Exception { if (evt instanceof HttpServerUpgradeHandler.UpgradeEvent) { // Write an HTTP/2 response to the upgrade request Http2Headers headers = new DefaultHttp2Headers().status(OK.codeAsText()) .set(new AsciiString(UPGRADE_RESPONSE_HEADER), new AsciiString("true")); encoder().writeHeaders(ctx, 1, headers, 0, true, ctx.newPromise()); } super.userEventTriggered(ctx, evt); }
@Override public UpgradeCodec newUpgradeCodec(CharSequence protocol) { if (AsciiString.contentEquals(Http2CodecUtil.HTTP_UPGRADE_PROTOCOL_NAME, protocol)) { return new Http2ServerUpgradeCodec(new HelloWorldHttp2HandlerBuilder().build()); } else { return null; } }
@SuppressWarnings("unchecked") RequestContextExporter(Set<BuiltInProperty> builtIns, Set<ExportEntry<AttributeKey<?>>> attrs, Set<ExportEntry<AsciiString>> httpReqHeaders, Set<ExportEntry<AsciiString>> httpResHeaders) { this.builtIns = new BuiltInProperties(); builtIns.forEach(this.builtIns::add); if (!attrs.isEmpty()) { this.attrs = attrs.toArray(new ExportEntry[attrs.size()]); } else { this.attrs = null; } if (!httpReqHeaders.isEmpty()) { this.httpReqHeaders = httpReqHeaders.toArray(new ExportEntry[httpReqHeaders.size()]); } else { this.httpReqHeaders = null; } if (!httpResHeaders.isEmpty()) { this.httpResHeaders = httpResHeaders.toArray(new ExportEntry[httpResHeaders.size()]); } else { this.httpResHeaders = null; } }
private static void exportHttpHeaders(Map<String, String> out, HttpHeaders headers, ExportEntry<AsciiString>[] requiredHeaderNames) { for (ExportEntry<AsciiString> e : requiredHeaderNames) { final String value = headers.get(e.key); final String mdcKey = e.mdcKey; if (value != null) { out.put(mdcKey, e.stringify(value)); } } }
private static void writeAscii(ByteBuf buf, int offset, CharSequence value, int valueLen) { if (value instanceof AsciiString) { ByteBufUtil.copy((AsciiString) value, 0, buf, offset, valueLen); } else { writeCharSequence(buf, offset, value, valueLen); } }
/** * Adds the specified HTTP header. */ public B addHttpHeader(AsciiString name, Object value) { requireNonNull(name, "name"); requireNonNull(value, "value"); httpHeaders.addObject(name, value); return self(); }
/** * Sets the specified HTTP header. */ public B setHttpHeader(AsciiString name, Object value) { requireNonNull(name, "name"); requireNonNull(value, "value"); httpHeaders.setObject(name, value); return self(); }
private static HttpHeaders filterHttpHeaders(HttpHeaders headers) { requireNonNull(headers, "headers"); for (AsciiString name : BLACKLISTED_HEADER_NAMES) { if (headers.contains(name)) { throw new IllegalArgumentException("unallowed header name: " + name); } } return new DefaultHttpHeaders().add(headers).asImmutable(); }
@Test public void stripConnectionNomineesWithCsv() { final io.netty.handler.codec.http.HttpHeaders in = new io.netty.handler.codec.http.DefaultHttpHeaders(); in.add(HttpHeaderNames.CONNECTION, "foo, bar"); in.add("foo", "baz"); in.add("bar", "qux"); in.add("hello", "world"); final HttpHeaders out = new DefaultHttpHeaders(); toArmeria(in, out); assertThat(out).hasSize(1); assertThat(out.get(AsciiString.of("hello"))).isEqualTo("world"); }
CorsConfig(final CorsServiceBuilder builder) { enabled = true; origins = builder.origins; anyOriginSupported = builder.anyOriginSupported; nullOriginAllowed = builder.nullOriginAllowed; credentialsAllowed = builder.credentialsAllowed; shortCircuit = builder.shortCircuit; maxAge = builder.maxAge; exposedHeaders = builder.exposedHeaders.isEmpty() ? Collections.emptySet() : ImmutableSet.copyOf(builder.exposedHeaders); allowedRequestMethods = EnumSet.copyOf(builder.allowedRequestMethods); allowedRequestHeaders = builder.allowedRequestHeaders.isEmpty() ? Collections.emptySet() : ImmutableSet.copyOf(builder.allowedRequestHeaders); final Map<AsciiString, Supplier<?>> preflightResponseHeaders; if (builder.preflightResponseHeadersDisabled) { preflightResponseHeaders = Collections.emptyMap(); } else if (builder.preflightResponseHeaders.isEmpty()) { preflightResponseHeaders = ImmutableMap.of(HttpHeaderNames.DATE, DateValueSupplier.INSTANCE, HttpHeaderNames.CONTENT_LENGTH, ConstantValueSupplier.ZERO); } else { preflightResponseHeaders = ImmutableMap.copyOf(builder.preflightResponseHeaders); } this.preflightResponseHeaders = preflightResponseHeaders; }
@Test public void testCorsPreflight() throws Exception { HttpClient client = HttpClient.of(clientFactory, server.uri("/")); AggregatedHttpMessage response = client.execute( HttpHeaders.of(HttpMethod.OPTIONS, "/cors") .set(HttpHeaderNames.ACCEPT, "utf-8") .set(HttpHeaderNames.ORIGIN, "http://example.com") .set(HttpHeaderNames.ACCESS_CONTROL_REQUEST_METHOD, "POST") ).aggregate().get(); assertEquals(HttpStatus.OK, response.status()); assertEquals("http://example.com", response.headers().get(HttpHeaderNames.ACCESS_CONTROL_ALLOW_ORIGIN)); assertEquals("Hello CORS", response.headers().get(AsciiString.of("x-preflight-cors"))); }
private void setCorsAllowHeaders(final HttpHeaders headers) { final Set<AsciiString> allowedHeaders = config.allowedRequestHeaders(); if (allowedHeaders.isEmpty()) { return; } for (AsciiString header : allowedHeaders) { headers.add(HttpHeaderNames.ACCESS_CONTROL_ALLOW_HEADERS, header.toString()); } }
/** * Converts the specified Netty HTTP/1 headers into Armeria HTTP/2 headers. */ public static void toArmeria(io.netty.handler.codec.http.HttpHeaders inHeaders, HttpHeaders out) { final Iterator<Entry<CharSequence, CharSequence>> iter = inHeaders.iteratorCharSequence(); // Choose 8 as a default size because it is unlikely we will see more than 4 Connection headers values, // but still allowing for "enough" space in the map to reduce the chance of hash code collision. final CharSequenceMap connectionBlacklist = toLowercaseMap(inHeaders.valueCharSequenceIterator(HttpHeaderNames.CONNECTION), 8); StringJoiner cookieJoiner = null; while (iter.hasNext()) { final Entry<CharSequence, CharSequence> entry = iter.next(); final AsciiString aName = AsciiString.of(entry.getKey()).toLowerCase(); if (HTTP_TO_HTTP2_HEADER_BLACKLIST.contains(aName) || connectionBlacklist.contains(aName)) { continue; } // https://tools.ietf.org/html/rfc7540#section-8.1.2.2 makes a special exception for TE if (aName.equals(HttpHeaderNames.TE)) { toHttp2HeadersFilterTE(entry, out); continue; } // Cookies must be concatenated into a single octet string. // https://tools.ietf.org/html/rfc7540#section-8.1.2.5 final CharSequence value = entry.getValue(); if (aName.equals(HttpHeaderNames.COOKIE)) { if (cookieJoiner == null) { cookieJoiner = new StringJoiner(COOKIE_SEPARATOR); } COOKIE_SPLITTER.split(value).forEach(cookieJoiner::add); } else { out.add(aName, value.toString()); } } if (cookieJoiner != null && cookieJoiner.length() != 0) { out.add(HttpHeaderNames.COOKIE, cookieJoiner.toString()); } }
/** * Returns new HTTP headers with four entries. */ static HttpHeaders of(AsciiString name1, String value1, AsciiString name2, String value2, AsciiString name3, String value3, AsciiString name4, String value4) { return new DefaultHttpHeaders().add(name1, value1).add(name2, value2) .add(name3, value3).add(name4, value4); }
@Override public HttpHeaders deserialize(JsonParser p, DeserializationContext ctx) throws IOException { final JsonNode tree = p.getCodec().readTree(p); if (!tree.isObject()) { ctx.reportInputMismatch(HttpHeaders.class, "HTTP headers must be an object."); return null; } final ObjectNode obj = (ObjectNode) tree; final HttpHeaders headers = HttpHeaders.of(); for (Iterator<Entry<String, JsonNode>> i = obj.fields(); i.hasNext();) { final Entry<String, JsonNode> e = i.next(); final AsciiString name = HttpHeaderNames.of(e.getKey()); final JsonNode values = e.getValue(); if (!values.isArray()) { // Values is a single item, so add it directly. addHeader(ctx, headers, name, values); } else { final int numValues = values.size(); for (int j = 0; j < numValues; j++) { final JsonNode v = values.get(j); addHeader(ctx, headers, name, v); } } } return headers.asImmutable(); }
private static void addHeader(DeserializationContext ctx, HttpHeaders headers, AsciiString name, JsonNode valueNode) throws JsonMappingException { if (!valueNode.isTextual()) { ctx.reportInputMismatch(HttpHeaders.class, "HTTP header '%s' contains %s (%s); only strings are allowed.", name, valueNode.getNodeType(), valueNode); } headers.add(name, valueNode.asText()); }
@Test(timeout = 10000) public void testTrailers() throws Exception { final HttpHeaders req = HttpHeaders.of(HttpMethod.GET, "/trailers"); final CompletableFuture<AggregatedHttpMessage> f = client().execute(req).aggregate(); final AggregatedHttpMessage res = f.get(); assertThat(res.trailingHeaders().get(AsciiString.of("foo")), is("bar")); }
@Test public void testInvalidHeaderName() throws Exception { assertThatThrownBy(() -> HttpHeaders.of((AsciiString) null, "value1")) .isInstanceOf(IllegalArgumentException.class); assertThatThrownBy(() -> HttpHeaders.of(AsciiString.of(""), "value1")) .isInstanceOf(IllegalArgumentException.class); }
/** Returns the name of this method. */ public AsciiString asciiName() { return name; }
NettyEmbeddedContext(String contextPath, ClassLoader classLoader, String serverInfo) { this.contextPath = contextPath; this.classLoader = classLoader; this.serverInfo = new AsciiString(serverInfo); }
AsciiString getServerInfoAscii() { return serverInfo; }