HttpURLConnectionTest.java revision 6a6b612286976cc185c898803fe51e4e062bd9eb
1/*
2 *  Licensed to the Apache Software Foundation (ASF) under one or more
3 *  contributor license agreements.  See the NOTICE file distributed with
4 *  this work for additional information regarding copyright ownership.
5 *  The ASF licenses this file to You under the Apache License, Version 2.0
6 *  (the "License"); you may not use this file except in compliance with
7 *  the License.  You may obtain a copy of the License at
8 *
9 *     http://www.apache.org/licenses/LICENSE-2.0
10 *
11 *  Unless required by applicable law or agreed to in writing, software
12 *  distributed under the License is distributed on an "AS IS" BASIS,
13 *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 *  See the License for the specific language governing permissions and
15 *  limitations under the License.
16 */
17
18package org.apache.harmony.luni.tests.internal.net.www.protocol.http;
19
20import java.io.IOException;
21import java.net.Authenticator;
22import java.net.HttpURLConnection;
23import java.net.InetSocketAddress;
24import java.net.PasswordAuthentication;
25import java.net.Proxy;
26import java.net.ProxySelector;
27import java.net.ServerSocket;
28import java.net.Socket;
29import java.net.SocketAddress;
30import java.net.SocketTimeoutException;
31import java.net.URI;
32import java.net.URL;
33import java.util.ArrayList;
34
35import junit.framework.TestCase;
36
37
38/**
39 * Tests for <code>HTTPURLConnection</code> class constructors and methods.
40 *
41 */
42public class HttpURLConnectionTest extends TestCase {
43
44    private final static Object bound = new Object();
45
46    static class MockServer extends Thread {
47        ServerSocket serverSocket;
48        boolean accepted = false;
49        boolean started = false;
50
51        public MockServer(String name) throws IOException {
52            super(name);
53            serverSocket = new ServerSocket(0);
54            serverSocket.setSoTimeout(1000);
55        }
56
57        public int port() {
58            return serverSocket.getLocalPort();
59        }
60
61        @Override
62        public void run() {
63            try {
64                synchronized (bound) {
65                    started = true;
66                    bound.notify();
67                }
68                try {
69                    serverSocket.accept().close();
70                    accepted = true;
71                } catch (SocketTimeoutException ignore) {
72                }
73                serverSocket.close();
74            } catch (IOException e) {
75                throw new RuntimeException(e);
76            }
77        }
78    }
79
80    static class MockProxyServer extends MockServer {
81
82        boolean acceptedAuthorizedRequest;
83
84        public MockProxyServer(String name) throws Exception {
85            super(name);
86        }
87
88        @Override
89        public void run() {
90            try {
91                Socket socket = serverSocket.accept();
92                socket.setSoTimeout(1000);
93                byte[] buff = new byte[1024];
94                int num = socket.getInputStream().read(buff);
95                socket.getOutputStream().write((
96                    "HTTP/1.0 407 Proxy authentication required\n"
97                  + "Proxy-authenticate: Basic realm=\"remotehost\"\n\n")
98                        .getBytes());
99                num = socket.getInputStream().read(buff);
100                if (num == -1) {
101                    // this connection was closed, create new one:
102                    socket = serverSocket.accept();
103                    socket.setSoTimeout(1000);
104                    num = socket.getInputStream().read(buff);
105                }
106                String request = new String(buff, 0, num);
107                acceptedAuthorizedRequest =
108                    request.toLowerCase().indexOf("proxy-authorization:") > 0;
109                if (acceptedAuthorizedRequest) {
110                    socket.getOutputStream().write((
111                            "HTTP/1.1 200 OK\n\n").getBytes());
112                }
113            } catch (IOException e) {
114            }
115        }
116    }
117
118    /**
119     * ProxySelector implementation used in the test.
120     */
121    static class TestProxySelector extends ProxySelector {
122        // proxy port
123        private int proxy_port;
124        // server port
125        private int server_port;
126
127        /**
128         * Creates proxy selector instance.
129         * Selector will return the proxy, only if the connection
130         * is made to localhost:server_port. Otherwise it will
131         * return NO_PROXY.
132         * Address of the returned proxy will be localhost:proxy_port.
133         */
134        public TestProxySelector(int server_port, int proxy_port) {
135            this.server_port = server_port;
136            this.proxy_port = proxy_port;
137        }
138
139        @Override
140        public java.util.List<Proxy> select(URI uri) {
141            Proxy proxy = Proxy.NO_PROXY;
142            if (("localhost".equals(uri.getHost()))
143                    && (server_port == uri.getPort())) {
144                proxy = new Proxy(Proxy.Type.HTTP,
145                            new InetSocketAddress("localhost", proxy_port));
146            }
147            ArrayList<Proxy> result = new ArrayList<Proxy>();
148            result.add(proxy);
149            return result;
150        }
151
152        @Override
153        public void connectFailed(URI uri, SocketAddress sa, IOException ioe) {
154            // do nothing
155        }
156    }
157
158    /**
159     * org.apache.harmony.luni.internal.net.www.http.getOutputStream()
160     */
161    public void testGetOutputStream() throws Exception {
162        // Regression for HARMONY-482
163        MockServer httpServer =
164            new MockServer("ServerSocket for HttpURLConnectionTest");
165        httpServer.start();
166        synchronized(bound) {
167            if (!httpServer.started) {
168                bound.wait(5000);
169            }
170        }
171        HttpURLConnection c = (HttpURLConnection)
172            new URL("http://localhost:" + httpServer.port()).openConnection();
173        c.setDoOutput(true);
174        //use new String("POST") instead of simple "POST" to obtain other
175        //object instances then those that are in HttpURLConnection classes
176        c.setRequestMethod(new String("POST"));
177        c.getOutputStream();
178        httpServer.join();
179    }
180
181
182    /**
183     * Test checks if the proxy specified in openConnection
184     * method will be used for connection to the server
185     */
186    public void testUsingProxy() throws Exception {
187        // Regression for HARMONY-570
188        MockServer server = new MockServer("server");
189        MockServer proxy = new MockServer("proxy");
190
191        URL url = new URL("http://localhost:" + server.port());
192
193        HttpURLConnection connection = (HttpURLConnection) url
194                .openConnection(new Proxy(Proxy.Type.HTTP,
195                        new InetSocketAddress("localhost",
196                            proxy.port())));
197        connection.setConnectTimeout(2000);
198        connection.setReadTimeout(2000);
199
200        server.start();
201        synchronized(bound) {
202            if (!server.started) bound.wait(5000);
203        }
204        proxy.start();
205        synchronized(bound) {
206            if (!proxy.started) bound.wait(5000);
207        }
208
209        connection.connect();
210
211        // wait while server and proxy run
212        server.join();
213        proxy.join();
214
215        assertTrue("Connection does not use proxy", connection.usingProxy());
216        assertTrue("Proxy server was not used", proxy.accepted);
217
218        HttpURLConnection huc = (HttpURLConnection)url.openConnection(Proxy.NO_PROXY);
219        assertFalse(huc.usingProxy());
220    }
221
222    /**
223     * Test checks if the proxy provided by proxy selector
224     * will be used for connection to the server
225     */
226    public void testUsingProxySelector() throws Exception {
227        // Regression for HARMONY-570
228        MockServer server = new MockServer("server");
229        MockServer proxy = new MockServer("proxy");
230
231        URL url = new URL("http://localhost:" + server.port());
232
233        // keep default proxy selector
234        ProxySelector defPS = ProxySelector.getDefault();
235        // replace selector
236        ProxySelector.setDefault(
237                new TestProxySelector(server.port(), proxy.port()));
238
239        try {
240            HttpURLConnection connection =
241                (HttpURLConnection) url.openConnection();
242            connection.setConnectTimeout(2000);
243            connection.setReadTimeout(2000);
244
245            server.start();
246            synchronized(bound) {
247                if (!server.started) bound.wait(5000);
248            }
249            proxy.start();
250            synchronized(bound) {
251                if (!proxy.started) bound.wait(5000);
252            }
253            connection.connect();
254
255            // wait while server and proxy run
256            server.join();
257            proxy.join();
258
259            assertTrue("Connection does not use proxy",
260                                            connection.usingProxy());
261            assertTrue("Proxy server was not used", proxy.accepted);
262
263            connection.disconnect();
264            assertTrue("usingProxy broken after disconnect",
265                   connection.usingProxy());
266        } finally {
267            // restore default proxy selector
268            ProxySelector.setDefault(defPS);
269        }
270    }
271    // SideEffect: Suffers from side effect of other, currently unknown test
272    public void testProxyAuthorization() throws Exception {
273        // Set up test Authenticator
274        Authenticator.setDefault(new Authenticator() {
275            @Override
276            protected PasswordAuthentication getPasswordAuthentication() {
277                return new PasswordAuthentication(
278                    "user", "password".toCharArray());
279            }
280        });
281
282        try {
283            MockProxyServer proxy = new MockProxyServer("ProxyServer");
284
285            URL url = new URL("http://remotehost:55555/requested.data");
286            HttpURLConnection connection =
287                (HttpURLConnection) url.openConnection(
288                        new Proxy(Proxy.Type.HTTP,
289                            new InetSocketAddress("localhost", proxy.port())));
290            connection.setConnectTimeout(1000);
291            connection.setReadTimeout(1000);
292
293            proxy.start();
294
295            connection.connect();
296            assertEquals("unexpected response code",
297                    200, connection.getResponseCode());
298            proxy.join();
299            assertTrue("Connection did not send proxy authorization request",
300                    proxy.acceptedAuthorizedRequest);
301        } finally {
302            // remove previously set authenticator
303            Authenticator.setDefault(null);
304        }
305    }
306
307}
308