public static RequestHeaders mergeRequestHeaders(RequestHeaders headers,
                                                     HttpHeaders defaultHeaders,
                                                     HttpHeaders additionalHeaders,
                                                     HttpHeaders internalHeaders) {
        if (defaultHeaders.isEmpty() && additionalHeaders.isEmpty() && internalHeaders.isEmpty() &&
            headers.contains(HttpHeaderNames.USER_AGENT)) {
            return headers;
        }
        if (defaultHeaders.isEmpty() && additionalHeaders.isEmpty()) {
            boolean containAllInternalHeaders = true;
            for (AsciiString name : internalHeaders.names()) {
                if (!headers.contains(name)) {
                    containAllInternalHeaders = false;
                    break;
                }
            }

            if (containAllInternalHeaders) {
                return headers;
            }
        }

        final RequestHeadersBuilder builder = headers.toBuilder();

        // Additional headers
        String authority = additionalHeaders.get(HttpHeaderNames.AUTHORITY);
        if (authority == null) {
            authority = additionalHeaders.get(HttpHeaderNames.HOST);
        }
        if (authority != null) {
            builder.authority(authority);
        }

        for (AsciiString name : additionalHeaders.names()) {
            if (name.equals(HttpHeaderNames.AUTHORITY) || name.equals(HttpHeaderNames.HOST)) {
                continue; // Manually handled above.
            } else if (!ADDITIONAL_REQUEST_HEADER_DISALLOWED_LIST.contains(name)) {
                builder.remove(name);
                additionalHeaders.forEachValue(name, value -> builder.add(name, value));
            }
        }

        // Default headers
        if (builder.authority() == null) {
            String authority0 = defaultHeaders.get(HttpHeaderNames.AUTHORITY);
            if (authority0 == null) {
                authority0 = defaultHeaders.get(HttpHeaderNames.HOST);
            }
            if (authority0 != null) {
                builder.authority(authority0);
            }
        }

        for (AsciiString name : defaultHeaders.names()) {
            if (name.equals(HttpHeaderNames.AUTHORITY) || name.equals(HttpHeaderNames.HOST)) {
                continue; // Manually handled above.
            } else if (!ADDITIONAL_REQUEST_HEADER_DISALLOWED_LIST.contains(name) && !builder.contains(name)) {
                defaultHeaders.forEachValue(name, value -> builder.add(name, value));
            }
        }

        // Internal headers
        if (builder.authority() == null) {
            String authority0 = internalHeaders.get(HttpHeaderNames.AUTHORITY);
            if (authority0 == null) {
                authority0 = internalHeaders.get(HttpHeaderNames.HOST);
            }
            if (authority0 != null) {
                builder.authority(authority0);
            }
        }

        for (AsciiString name : internalHeaders.names()) {
            if (name.equals(HttpHeaderNames.AUTHORITY) || name.equals(HttpHeaderNames.HOST)) {
                continue; // Manually handled above.
            } else if (!ADDITIONAL_REQUEST_HEADER_DISALLOWED_LIST.contains(name) && !builder.contains(name)) {
                internalHeaders.forEachValue(name, value -> builder.add(name, value));
            }
        }

        return builder.build();
    }
Merges the given {@link RequestHeaders}. The headers have priority in the following order.
<pre>{@code
additional headers (highest priority) > headers > default headers > framework headers (lowest priority)
}</pre>
core/src/main/java/com/linecorp/armeria/internal/common/HttpHeadersUtil.java