File: HTTPTest.java

package info (click to toggle)
openjdk-11 11.0.4%2B11-1
  • links: PTS, VCS
  • area: main
  • in suites: sid
  • size: 757,028 kB
  • sloc: java: 5,016,041; xml: 1,191,974; cpp: 934,731; ansic: 555,697; sh: 24,299; objc: 12,703; python: 3,602; asm: 3,415; makefile: 2,772; awk: 351; sed: 172; perl: 114; jsp: 24; csh: 3
file content (284 lines) | stat: -rw-r--r-- 11,115 bytes parent folder | download | duplicates (2)
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
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
/*
 * Copyright (c) 2016, 2017, 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.  Oracle designates this
 * particular file as subject to the "Classpath" exception as provided
 * by Oracle in the LICENSE file that accompanied this code.
 *
 * 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.UncheckedIOException;
import java.net.Authenticator;
import java.net.HttpURLConnection;
import java.net.InetSocketAddress;
import java.net.MalformedURLException;
import java.net.PasswordAuthentication;
import java.net.Proxy;
import java.net.URL;
import java.util.Locale;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.logging.Level;
import java.util.logging.Logger;
import java.util.stream.Stream;
import javax.net.ssl.HostnameVerifier;
import javax.net.ssl.HttpsURLConnection;
import javax.net.ssl.SSLContext;
import javax.net.ssl.SSLSession;
import jdk.testlibrary.SimpleSSLContext;

/*
 * @test
 * @bug 8169415
 * @library /lib/testlibrary/
 * @modules java.logging
 *          java.base/sun.net.www
 *          jdk.httpserver/sun.net.httpserver
 * @build jdk.testlibrary.SimpleSSLContext HTTPTest HTTPTestServer HTTPTestClient
 * @summary A simple HTTP test that starts an echo server supporting Digest
 *          authentication, then starts a regular HTTP client to invoke it.
 *          The client first does a GET request on "/", then follows on
 *          with a POST request that sends "Hello World!" to the server.
 *          The client expects to receive "Hello World!" in return.
 *          The test supports several execution modes:
 *            SERVER: The server performs Digest Server authentication;
 *            PROXY:  The server pretends to be a proxy and performs
 *                    Digest Proxy authentication;
 *            SERVER307: The server redirects the client (307) to another
 *                    server that perform Digest authentication;
 *            PROXY305: The server attempts to redirect
 *                    the client to a proxy using 305 code;
 * @run main/othervm HTTPTest SERVER
 * @run main/othervm HTTPTest PROXY
 * @run main/othervm HTTPTest SERVER307
 * @run main/othervm HTTPTest PROXY305
 *
 * @author danielfuchs
 */
public class HTTPTest {

    public static final boolean DEBUG =
         Boolean.parseBoolean(System.getProperty("test.debug", "false"));
    public static enum HttpAuthType { SERVER, PROXY, SERVER307, PROXY305 };
    public static enum HttpProtocolType { HTTP, HTTPS };
    public static enum HttpSchemeType { NONE, BASICSERVER, BASIC, DIGEST };
    public static final HttpAuthType DEFAULT_HTTP_AUTH_TYPE = HttpAuthType.SERVER;
    public static final HttpProtocolType DEFAULT_PROTOCOL_TYPE = HttpProtocolType.HTTP;
    public static final HttpSchemeType DEFAULT_SCHEME_TYPE = HttpSchemeType.DIGEST;

    public static class HttpTestAuthenticator extends Authenticator {
        private final String realm;
        private final String username;
        // Used to prevent incrementation of 'count' when calling the
        // authenticator from the server side.
        private final ThreadLocal<Boolean> skipCount = new ThreadLocal<>();
        // count will be incremented every time getPasswordAuthentication()
        // is called from the client side.
        final AtomicInteger count = new AtomicInteger();

        public HttpTestAuthenticator(String realm, String username) {
            this.realm = realm;
            this.username = username;
        }

        @Override
        protected PasswordAuthentication getPasswordAuthentication() {
            if (skipCount.get() == null || skipCount.get().booleanValue() == false) {
                System.out.println("Authenticator called: " + count.incrementAndGet());
            }
            return new PasswordAuthentication(getUserName(),
                    new char[] {'b','a','r'});
        }

        // Called by the server side to get the password of the user
        // being authentified.
        public final char[] getPassword(String user) {
            if (user.equals(username)) {
                skipCount.set(Boolean.TRUE);
                try {
                    return getPasswordAuthentication().getPassword();
                } finally {
                    skipCount.set(Boolean.FALSE);
                }
            }
            throw new SecurityException("User unknown: " + user);
        }

        public final String getUserName() {
            return username;
        }
        public final String getRealm() {
            return realm;
        }

    }
    public static final HttpTestAuthenticator AUTHENTICATOR;
    static {
        AUTHENTICATOR = new HttpTestAuthenticator("dublin", "foox");
        Authenticator.setDefault(AUTHENTICATOR);
    }

    static {
        try {
            HttpsURLConnection.setDefaultHostnameVerifier(new HostnameVerifier() {
                public boolean verify(String hostname, SSLSession session) {
                    return true;
                }
            });
            SSLContext.setDefault(new SimpleSSLContext().get());
        } catch (IOException ex) {
            throw new ExceptionInInitializerError(ex);
        }
    }

    static final Logger logger = Logger.getLogger ("com.sun.net.httpserver");
    static {
        if (DEBUG) logger.setLevel(Level.ALL);
        Stream.of(Logger.getLogger("").getHandlers())
              .forEach(h -> h.setLevel(Level.ALL));
    }

    static final int EXPECTED_AUTH_CALLS_PER_TEST = 1;

    public static void main(String[] args) throws Exception {
        // new HTTPTest().execute(HttpAuthType.SERVER.name());
        new HTTPTest().execute(args);
    }

    public void execute(String... args) throws Exception {
        Stream<HttpAuthType> modes;
        if (args == null || args.length == 0) {
            modes = Stream.of(HttpAuthType.values());
        } else {
            modes = Stream.of(args).map(HttpAuthType::valueOf);
        }
        modes.forEach(this::test);
        System.out.println("Test PASSED - Authenticator called: "
                 + expected(AUTHENTICATOR.count.get()));
    }

    public void test(HttpAuthType mode) {
        for (HttpProtocolType type: HttpProtocolType.values()) {
            test(type, mode);
        }
    }

    public HttpSchemeType getHttpSchemeType() {
        return DEFAULT_SCHEME_TYPE;
    }

    public void test(HttpProtocolType protocol, HttpAuthType mode) {
        if (mode == HttpAuthType.PROXY305 && protocol == HttpProtocolType.HTTPS ) {
            // silently skip unsupported test combination
            return;
        }
        System.out.println("\n**** Testing " + protocol + " "
                           + mode + " mode ****\n");
        int authCount = AUTHENTICATOR.count.get();
        int expectedIncrement = 0;
        try {
            // Creates an HTTP server that echoes back whatever is in the
            // request body.
            HTTPTestServer server =
                    HTTPTestServer.create(protocol,
                                          mode,
                                          AUTHENTICATOR,
                                          getHttpSchemeType());
            try {
                expectedIncrement += run(server, protocol, mode);
            } finally {
                server.stop();
            }
        }  catch (IOException ex) {
            ex.printStackTrace(System.err);
            throw new UncheckedIOException(ex);
        }
        int count = AUTHENTICATOR.count.get();
        if (count != authCount + expectedIncrement) {
            throw new AssertionError("Authenticator called " + count(count)
                        + " expected it to be called "
                        + expected(authCount + expectedIncrement));
        }
    }

    /**
     * Runs the test with the given parameters.
     * @param server    The server
     * @param protocol  The protocol (HTTP/HTTPS)
     * @param mode      The mode (PROXY, SERVER, SERVER307...)
     * @return The number of times the default authenticator should have been
     *         called.
     * @throws IOException in case of connection or protocol issues
     */
    public int run(HTTPTestServer server,
                   HttpProtocolType protocol,
                   HttpAuthType mode)
            throws IOException
    {
        // Connect to the server with a GET request, then with a
        // POST that contains "Hello World!"
        HTTPTestClient.connect(protocol, server, mode, null);
        // return the number of times the default authenticator is supposed
        // to have been called.
        return EXPECTED_AUTH_CALLS_PER_TEST;
    }

    public static String count(int count) {
        switch(count) {
            case 0: return "not even once";
            case 1: return "once";
            case 2: return "twice";
            default: return String.valueOf(count) + " times";
        }
    }

    public static String expected(int count) {
        switch(count) {
            default: return count(count);
        }
    }
    public static String protocol(HttpProtocolType type) {
        return type.name().toLowerCase(Locale.US);
    }

    public static URL url(HttpProtocolType protocol, InetSocketAddress address,
                          String path) throws MalformedURLException {
        return new URL(protocol(protocol),
                       address.getHostString(),
                       address.getPort(), path);
    }

    public static Proxy proxy(HTTPTestServer server, HttpAuthType authType) {
        return (authType == HttpAuthType.PROXY)
               ? new Proxy(Proxy.Type.HTTP, server.getAddress())
               : null;
    }

    public static HttpURLConnection openConnection(URL url,
                                                   HttpAuthType authType,
                                                   Proxy proxy)
                                    throws IOException {

        HttpURLConnection conn = (HttpURLConnection)
                (authType == HttpAuthType.PROXY
                    ? url.openConnection(proxy)
                    : url.openConnection());
        return conn;
    }
}