@Override public AsciiString create(String name) { return HttpHeaderNames.of(name); } }
private static AsciiString toHeaderName(CharSequence name) { return HttpHeaderNames.of(requireNonNull(name, "name").toString()); }
/** * Returns a {@link ClientAddressSource} which indicates the value of the specified {@code header} * in a request will be used to determine a client address. */ public static ClientAddressSource ofHeader(CharSequence header) { checkArgument(header != null && header.length() > 0, "empty header"); return new ClientAddressSource(HttpHeaderNames.of(header)); }
/** * Adds the specified HTTP header. */ public B addHttpHeader(CharSequence name, Object value) { requireNonNull(name, "name"); requireNonNull(value, "value"); httpHeaders.addObject(HttpHeaderNames.of(name), value); return self(); }
/** * Sets the specified HTTP header. */ public B setHttpHeader(CharSequence name, Object value) { requireNonNull(name, "name"); requireNonNull(value, "value"); httpHeaders.setObject(HttpHeaderNames.of(name), value); return self(); }
/** * Specifies HTTP response headers that should be added to a CORS preflight response. * * <p>An intermediary like a load balancer might require that a CORS preflight request * have certain headers set. This enables such headers to be added. * * <p>Some values must be dynamically created when the HTTP response is created, for * example the {@code "Date"} response header. This can be accomplished by using a {@link Supplier} * which will have its {@link Supplier#get()} method invoked when the HTTP response is created. * * @param name the name of the HTTP header. * @param valueSupplier a {@link Supplier} which will be invoked at HTTP response creation. * @return {@code this} to support method chaining. */ public B preflightResponseHeader(CharSequence name, Supplier<?> valueSupplier) { requireNonNull(name, "name"); requireNonNull(valueSupplier, "valueSupplier"); preflightResponseHeaders.put(HttpHeaderNames.of(name), valueSupplier); return self(); }
/** * Lower-cases and converts the specified header name into an {@link AsciiString}. If {@code name} is * a known header name, this method will return a pre-instantiated {@link AsciiString} to reduce * the allocation rate of {@link AsciiString}. */ public static AsciiString of(CharSequence name) { if (name instanceof AsciiString) { return of((AsciiString) name); } final String lowerCased = Ascii.toLowerCase(requireNonNull(name, "name")); final AsciiString cached = map.get(lowerCased); return cached != null ? cached : AsciiString.cached(lowerCased); }
private static <T extends Annotation> void setAdditionalHeader(HttpHeaders headers, AnnotatedElement element, String clsAlias, String elementAlias, String level, Class<T> annotation, Function<T, String> nameGetter, Function<T, String[]> valueGetter) { requireNonNull(headers, "headers"); requireNonNull(element, "element"); requireNonNull(level, "level"); final Set<String> addedHeaderSets = new HashSet<>(); findAll(element, annotation).forEach(header -> { final String name = nameGetter.apply(header); final String[] value = valueGetter.apply(header); if (addedHeaderSets.contains(name)) { logger.warn("The additional {} named '{}' at '{}' is set at the same {} level already;" + "ignoring.", clsAlias, name, elementAlias, level); return; } headers.set(HttpHeaderNames.of(name), value); addedHeaderSets.add(name); }); }
/** * Adds the specified HTTP header. */ public final B addHeader(CharSequence name, Object value) { requireNonNull(name, "name"); requireNonNull(value, "value"); getOrCreateHeaders().addObject(HttpHeaderNames.of(name), value); return self(); }
/** * Specifies HTTP response headers that should be added to a CORS preflight response. * * <p>An intermediary like a load balancer might require that a CORS preflight request * have certain headers set. This enables such headers to be added. * * @param name the name of the HTTP header. * @param values the values for the HTTP header. * @return {@code this} to support method chaining. */ public B preflightResponseHeader(CharSequence name, Object... values) { requireNonNull(name, "name"); requireNonNull(values, "values"); checkArgument(values.length > 0,"values should not be empty."); for (int i = 0; i < values.length; i++) { if (values[i] == null) { throw new NullPointerException("values[" + i + ']'); } } preflightResponseHeaders.put(HttpHeaderNames.of(name), new ConstantValueSupplier(ImmutableList.copyOf(values))); return self(); }
/** * Specifies HTTP response headers that should be added to a CORS preflight response. * * <p>An intermediary like a load balancer might require that a CORS preflight request * have certain headers set. This enables such headers to be added. * * @param name the name of the HTTP header. * @param values the values for the HTTP header. * @return {@code this} to support method chaining. */ public B preflightResponseHeader(CharSequence name, Iterable<?> values) { requireNonNull(name, "name"); requireNonNull(values, "values"); checkArgument(!Iterables.isEmpty(values), "values should not be empty."); final ImmutableList.Builder builder = new Builder(); int i = 0; for (Object value : values) { if (value == null) { throw new NullPointerException("value[" + i + ']'); } builder.add(value); i++; } preflightResponseHeaders.put(HttpHeaderNames.of(name), new ConstantValueSupplier(builder.build())); return self(); }
/** * Sets the specified HTTP header. */ public final B setHeader(CharSequence name, Object value) { requireNonNull(name, "name"); requireNonNull(value, "value"); getOrCreateHeaders().setObject(HttpHeaderNames.of(name), value); return self(); }
@Nullable @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 (final 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(); }
@Override protected void applyHeaders() { getHeaders().forEach((name, values) -> headers.add(HttpHeaderNames.of(name), values)); }
/** * Converts the specified Netty HTTP/2 into Armeria HTTP/2 headers. */ public static HttpHeaders toArmeria(Http2Headers headers, boolean endOfStream) { final HttpHeaders converted = new DefaultHttpHeaders(false, headers.size(), endOfStream); StringJoiner cookieJoiner = null; for (Entry<CharSequence, CharSequence> e : headers) { final AsciiString name = HttpHeaderNames.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, convertHeaderValue(name, value)); } } if (cookieJoiner != null && cookieJoiner.length() != 0) { converted.add(HttpHeaderNames.COOKIE, cookieJoiner.toString()); } return converted; }
@Override protected void applyHeaders() { // Copy the HTTP headers which were specified by a user to the Armeria request. getHeaders().forEach((name, values) -> headers.set(HttpHeaderNames.of(name), values)); setDefaultRequestHeaders(headers); }
while (iter.hasNext()) { final Entry<CharSequence, CharSequence> entry = iter.next(); final AsciiString aName = HttpHeaderNames.of(entry.getKey()).toLowerCase(); if (HTTP_TO_HTTP2_HEADER_BLACKLIST.contains(aName) || connectionBlacklist.contains(aName)) { continue;
private static AnnotatedValueResolver ofHeader(String name, AnnotatedElement annotatedElement, AnnotatedElement typeElement, Class<?> type, @Nullable String description) { return builder(annotatedElement, type) .annotationType(Header.class) .httpElementName(name) .typeElement(typeElement) .supportOptional(true) .supportDefault(true) .supportContainer(true) .description(description) .resolver(resolver( ctx -> ctx.request().headers().getAll(HttpHeaderNames.of(name)), () -> "Cannot resolve a value from HTTP header: " + name)) .build(); }
private static HttpHeaders toResponseHeaders(ArmeriaHttpTransport transport) { final MetaData.Response info = transport.info; if (info == null) { throw new IllegalStateException("response metadata unavailable"); } final HttpHeaders headers = HttpHeaders.of(HttpStatus.valueOf(info.getStatus())); info.getFields().forEach(e -> headers.add(HttpHeaderNames.of(e.getName()), e.getValue())); if (transport.method != HttpMethod.HEAD) { headers.setLong(HttpHeaderNames.CONTENT_LENGTH, transport.contentLength); } return headers; }
@Test public void getCookies() { final HttpHeaders httpHeaders = HttpHeaders.of(HttpStatus.OK) .add(HttpHeaderNames.of("blahblah"), "armeria") .add(HttpHeaderNames.SET_COOKIE, "a=1; b=2"); final HttpResponse httpResponse = HttpResponse.of(httpHeaders); final ArmeriaClientHttpResponse response = response(new ArmeriaHttpClientResponseSubscriber(httpResponse), httpHeaders); // HttpResponse would be completed after Httpheaders is completed, because there's no body. assertThat(httpResponse.completionFuture().isDone()).isTrue(); assertThat(response.getStatusCode()).isEqualTo(org.springframework.http.HttpStatus.OK); assertThat(response.getHeaders().getFirst("blahblah")).isEqualTo("armeria"); final ResponseCookie cookie = response.getCookies().getFirst("a"); assertThat(cookie).isNotNull(); assertThat(cookie.getValue()).isEqualTo("1"); }