ArmeriaHttpUtil { public static String concatPaths(@Nullable String path1, @Nullable String path2) { path2 = path2 == null ? "" : path2; if (path1 == null || path1.isEmpty() || EMPTY_REQUEST_PATH.equals(path1)) { if (path2.isEmpty()) { return EMPTY_REQUEST_PATH; } if (path2.charAt(0) == '/') { return path2; } return '/' + path2; } if (path2.isEmpty()) { return path1; } if (path1.charAt(path1.length() - 1) == '/') { if (path2.charAt(0) == '/') { return new StringBuilder(path1.length() + path2.length() - 1) .append(path1).append(path2, 1, path2.length()).toString(); } return path1 + path2; } if (path2.charAt(0) == '/') { return path1 + path2; } return path1 + '/' + path2; } 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 testConcatPaths() throws Exception { assertThat(concatPaths(null, "a")).isEqualTo("/a"); assertThat(concatPaths(null, "/a")).isEqualTo("/a"); assertThat(concatPaths("", "a")).isEqualTo("/a"); assertThat(concatPaths("", "/a")).isEqualTo("/a"); assertThat(concatPaths("/", "a")).isEqualTo("/a"); assertThat(concatPaths("/", "/a")).isEqualTo("/a"); assertThat(concatPaths("/", "/")).isEqualTo("/"); assertThat(concatPaths("/a", "b")).isEqualTo("/a/b"); assertThat(concatPaths("/a", "/b")).isEqualTo("/a/b"); assertThat(concatPaths("/a/", "/b")).isEqualTo("/a/b"); }