File: HostHeaderTest.java

package info (click to toggle)
openjdk-25 25~32ea-1
  • links: PTS, VCS
  • area: main
  • in suites: trixie
  • size: 825,280 kB
  • sloc: java: 5,584,902; cpp: 1,333,941; xml: 1,321,242; ansic: 487,993; asm: 404,003; objc: 21,088; sh: 15,102; javascript: 13,265; python: 8,319; makefile: 2,515; perl: 357; awk: 351; pascal: 103; exp: 83; sed: 72; jsp: 24
file content (143 lines) | stat: -rw-r--r-- 6,018 bytes parent folder | download | duplicates (3)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
/*
 * Copyright (c) 2025, Oracle and/or its affiliates. All rights reserved.
 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
 *
 * This code is free software; you can redistribute it and/or modify it
 * under the terms of the GNU General Public License version 2 only, as
 * published by the Free Software Foundation.
 *
 * This code is distributed in the hope that it will be useful, but WITHOUT
 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
 * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
 * version 2 for more details (a copy is included in the LICENSE file that
 * accompanied this code).
 *
 * You should have received a copy of the GNU General Public License version
 * 2 along with this work; if not, write to the Free Software Foundation,
 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
 *
 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
 * or visit www.oracle.com if you need additional information or have any
 * questions.
 */

import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.HttpURLConnection;
import java.net.InetAddress;
import java.net.InetSocketAddress;
import java.net.Proxy;
import java.net.URL;
import java.net.URLConnection;
import java.util.List;

import com.sun.net.httpserver.HttpExchange;
import com.sun.net.httpserver.HttpHandler;
import com.sun.net.httpserver.HttpServer;
import jdk.test.lib.net.URIBuilder;
import org.junit.jupiter.api.AfterAll;
import org.junit.jupiter.api.BeforeAll;
import org.junit.jupiter.api.Test;
import static java.nio.charset.StandardCharsets.US_ASCII;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertInstanceOf;
import static org.junit.jupiter.api.Assertions.assertNull;

/*
 * @test
 * @bug 8359709
 * @summary verify that if the Host header is allowed to be set by the application
 *          then the correct value gets set in a HTTP request issued through
 *          java.net.HttpURLConnection
 * @library /test/lib
 * @run junit HostHeaderTest
 * @run junit/othervm -Dsun.net.http.allowRestrictedHeaders=true HostHeaderTest
 * @run junit/othervm -Dsun.net.http.allowRestrictedHeaders=false HostHeaderTest
 */
class HostHeaderTest {

    private static final String SERVER_CTX_ROOT = "/8359709/";
    private static final boolean allowsHostHeader = Boolean.getBoolean("sun.net.http.allowRestrictedHeaders");

    private static HttpServer server;

    @BeforeAll
    static void beforeAll() throws Exception {
        final InetSocketAddress addr = new InetSocketAddress(InetAddress.getLoopbackAddress(), 0);
        server = HttpServer.create(addr, 0);
        server.createContext(SERVER_CTX_ROOT, new Handler());
        server.start();
        System.err.println("started server at " + server.getAddress());
    }

    @AfterAll
    static void afterAll() throws Exception {
        if (server != null) {
            System.err.println("stopping server " + server.getAddress());
            server.stop(0);
        }
    }

    @Test
    void testHostHeader() throws Exception {
        final InetSocketAddress serverAddr = server.getAddress();
        final URL reqURL = URIBuilder.newBuilder()
                .scheme("http")
                .loopback()
                .port(serverAddr.getPort())
                .path(SERVER_CTX_ROOT)
                .build().toURL();
        final URLConnection conn = reqURL.openConnection(Proxy.NO_PROXY);

        conn.setRequestProperty("Host", "foobar");
        if (!allowsHostHeader) {
            // if restricted headers aren't allowed to be set by the user, then
            // we expect the previous call to setRequestProperty to not set the Host
            // header
            assertNull(conn.getRequestProperty("Host"), "Host header unexpectedly set");
        }

        assertInstanceOf(HttpURLConnection.class, conn);
        final HttpURLConnection httpURLConn = (HttpURLConnection) conn;

        // send the HTTP request
        System.err.println("sending request " + reqURL);
        final int respCode = httpURLConn.getResponseCode();
        assertEquals(200, respCode, "unexpected response code");
        // verify that the server side handler received the expected
        // Host header value in the request
        try (final InputStream is = httpURLConn.getInputStream()) {
            final byte[] resp = is.readAllBytes();
            // if Host header wasn't explicitly set, then we expect it to be
            // derived from the request URL
            final String expected = allowsHostHeader
                    ? "foobar"
                    : reqURL.getHost() + ":" + reqURL.getPort();
            final String actual = new String(resp, US_ASCII);
            assertEquals(expected, actual, "unexpected Host header received on server side");
        }
    }

    private static final class Handler implements HttpHandler {
        private static final int NO_RESPONSE_BODY = -1;

        @Override
        public void handle(final HttpExchange exchange) throws IOException {
            final List<String> headerVals = exchange.getRequestHeaders().get("Host");
            System.err.println("Host header has value(s): " + headerVals);
            // unexpected Host header value, respond with 400 status code
            if (headerVals == null || headerVals.size() != 1) {
                System.err.println("Unexpected header value(s) for Host header: " + headerVals);
                exchange.sendResponseHeaders(400, NO_RESPONSE_BODY);
                return;
            }
            // respond back with the Host header value that we found in the request
            final byte[] response = headerVals.getFirst().getBytes(US_ASCII);
            exchange.sendResponseHeaders(200, response.length);
            try (final OutputStream os = exchange.getResponseBody()) {
                os.write(response);
            }
        }
    }
}