ArmeriaHttpUtil { public static void parseDirectives(String directives, BiConsumer<String, String> callback) { final int len = directives.length(); for (int i = 0; i < len;) { final int nameStart = i; final String name; final String value; for (; i < len; i++) { final char ch = directives.charAt(i); if (ch == ',' || ch == '=') { break; } } name = directives.substring(nameStart, i).trim(); if (i == len || directives.charAt(i) == ',') { i++; value = null; } else { i++; for (; i < len; i++) { final char ch = directives.charAt(i); if (ch != ' ' && ch != '\t') { break; } } if (i < len && directives.charAt(i) == '\"') { i++; final int valueStart = i; for (; i < len; i++) { if (directives.charAt(i) == '\"') { break; } } value = directives.substring(valueStart, i); i++; for (; i < len; i++) { if (directives.charAt(i) == ',') { i++; break; } } } else { final int valueStart = i; for (; i < len; i++) { if (directives.charAt(i) == ',') { break; } } value = directives.substring(valueStart, i).trim(); i++; } } if (!name.isEmpty()) { callback.accept(Ascii.toLowerCase(name), Strings.emptyToNull(value)); } } } private  ArmeriaHttpUtil(); static String concatPaths(@Nullable String path1, @Nullable String path2); static String decodePath(String path); static boolean isAbsoluteUri(@Nullable String maybeUri); static boolean isInformational(@Nullable String statusText); static boolean isContentAlwaysEmptyWithValidation(HttpStatus status, HttpData content); static boolean isCorsPreflightRequest(com.linecorp.armeria.common.HttpRequest request); static void parseDirectives(String directives, BiConsumer<String, String> callback); static long parseDirectiveValueAsSeconds(@Nullable String value); static RequestHeaders toArmeriaRequestHeaders(ChannelHandlerContext ctx, Http2Headers headers,
                                                         boolean endOfStream, String scheme,
                                                         ServerConfig cfg); static HttpHeaders toArmeria(Http2Headers headers, boolean request, boolean endOfStream); static RequestHeaders toArmeria(ChannelHandlerContext ctx, HttpRequest in,
                                           ServerConfig cfg); static ResponseHeaders toArmeria(HttpResponse in); static HttpHeaders toArmeria(io.netty.handler.codec.http.HttpHeaders inHeaders); static void toArmeria(io.netty.handler.codec.http.HttpHeaders inHeaders, HttpHeadersBuilder out); static Http2Headers toNettyHttp2ServerHeaders(HttpHeaders inputHeaders); static Http2Headers toNettyHttp2ServerTrailer(HttpHeaders inputHeaders); static Http2Headers toNettyHttp2ClientHeader(HttpHeaders inputHeaders); static Http2Headers toNettyHttp2ClientTrailer(HttpHeaders inputHeaders); static void toNettyHttp1ServerHeader(
            HttpHeaders inputHeaders, io.netty.handler.codec.http.HttpHeaders outputHeaders); static void toNettyHttp1ServerTrailer(
            HttpHeaders inputHeaders, io.netty.handler.codec.http.HttpHeaders outputHeaders); static void toNettyHttp1ClientHeader(
            HttpHeaders inputHeaders, io.netty.handler.codec.http.HttpHeaders outputHeaders); static void toNettyHttp1ClientTrailer(
            HttpHeaders inputHeaders, io.netty.handler.codec.http.HttpHeaders outputHeaders); static ResponseHeaders setOrRemoveContentLength(ResponseHeaders headers, HttpData content,
                                                           HttpHeaders trailers); static boolean isTrailerBlacklisted(AsciiString name); static String authorityHeader(String host, int port, int defaultPort); static final Charset HTTP_DEFAULT_CONTENT_CHARSET; static final AsciiString HEADER_NAME_KEEP_ALIVE; static final AsciiString HEADER_NAME_PROXY_CONNECTION; static final String SERVER_HEADER; }
@Test void testParseDirectives() { final Map<String, String> values = new LinkedHashMap<>(); final BiConsumer<String, String> cb = (name, value) -> assertThat(values.put(name, value)).isNull(); parseDirectives("", cb); assertThat(values).isEmpty(); parseDirectives(" \t ", cb); assertThat(values).isEmpty(); parseDirectives(" ,,=, =,= ,", cb); assertThat(values).isEmpty(); parseDirectives("no-cache", cb); assertThat(values).hasSize(1).containsEntry("no-cache", null); values.clear(); parseDirectives(" no-cache ", cb); assertThat(values).hasSize(1).containsEntry("no-cache", null); values.clear(); parseDirectives("no-cache ,", cb); assertThat(values).hasSize(1).containsEntry("no-cache", null); values.clear(); parseDirectives("max-age=86400", cb); assertThat(values).hasSize(1).containsEntry("max-age", "86400"); values.clear(); parseDirectives(" max-age = 86400 ", cb); assertThat(values).hasSize(1).containsEntry("max-age", "86400"); values.clear(); parseDirectives(" max-age = 86400 ,", cb); assertThat(values).hasSize(1).containsEntry("max-age", "86400"); values.clear(); parseDirectives("max-age=\"86400\"", cb); assertThat(values).hasSize(1).containsEntry("max-age", "86400"); values.clear(); parseDirectives(" max-age = \"86400\" ", cb); assertThat(values).hasSize(1).containsEntry("max-age", "86400"); values.clear(); parseDirectives(" max-age = \"86400\" ,", cb); assertThat(values).hasSize(1).containsEntry("max-age", "86400"); values.clear(); parseDirectives("a,b=c,d,e=\"f\",g", cb); assertThat(values).hasSize(5) .containsEntry("a", null) .containsEntry("b", "c") .containsEntry("d", null) .containsEntry("e", "f") .containsEntry("g", null); }