HttpURLConnectionTest.java revision cc05ad238516f1303687aba4a978e24e57c0c07a
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 dalvik.annotation.TestTargetClass;
21import dalvik.annotation.TestTargets;
22import dalvik.annotation.TestLevel;
23import dalvik.annotation.TestTargetNew;
24
25import java.io.IOException;
26import java.net.Authenticator;
27import java.net.HttpURLConnection;
28import java.net.InetSocketAddress;
29import java.net.PasswordAuthentication;
30import java.net.Proxy;
31import java.net.ProxySelector;
32import java.net.ServerSocket;
33import java.net.Socket;
34import java.net.SocketAddress;
35import java.net.SocketTimeoutException;
36import java.net.URI;
37import java.net.URL;
38import java.util.ArrayList;
39
40import junit.framework.TestCase;
41
42
43/**
44 * Tests for <code>HTTPURLConnection</code> class constructors and methods.
45 *
46 */
47@TestTargetClass(HttpURLConnection.class)
48public class HttpURLConnectionTest extends TestCase {
49
50    private final static Object bound = new Object();
51
52    static class MockServer extends Thread {
53        ServerSocket serverSocket;
54        boolean accepted = false;
55        boolean started = false;
56
57        public MockServer(String name) throws IOException {
58            super(name);
59            serverSocket = new ServerSocket(0);
60            serverSocket.setSoTimeout(1000);
61        }
62
63        public int port() {
64            return serverSocket.getLocalPort();
65        }
66
67        @Override
68        public void run() {
69            try {
70                synchronized (bound) {
71                    started = true;
72                    bound.notify();
73                }
74                try {
75                    serverSocket.accept().close();
76                    accepted = true;
77                } catch (SocketTimeoutException ignore) {
78                }
79                serverSocket.close();
80            } catch (IOException e) {
81                throw new RuntimeException(e);
82            }
83        }
84    }
85
86    static class MockProxyServer extends MockServer {
87
88        boolean acceptedAuthorizedRequest;
89
90        public MockProxyServer(String name) throws Exception {
91            super(name);
92        }
93
94        @Override
95        public void run() {
96            try {
97                Socket socket = serverSocket.accept();
98                socket.setSoTimeout(1000);
99                byte[] buff = new byte[1024];
100                int num = socket.getInputStream().read(buff);
101                socket.getOutputStream().write((
102                    "HTTP/1.0 407 Proxy authentication required\n"
103                  + "Proxy-authenticate: Basic realm=\"remotehost\"\n\n")
104                        .getBytes());
105                num = socket.getInputStream().read(buff);
106                if (num == -1) {
107                    // this connection was closed, create new one:
108                    socket = serverSocket.accept();
109                    socket.setSoTimeout(1000);
110                    num = socket.getInputStream().read(buff);
111                }
112                String request = new String(buff, 0, num);
113                acceptedAuthorizedRequest =
114                    request.toLowerCase().indexOf("proxy-authorization:") > 0;
115                if (acceptedAuthorizedRequest) {
116                    socket.getOutputStream().write((
117                            "HTTP/1.1 200 OK\n\n").getBytes());
118                }
119            } catch (IOException e) {
120            }
121        }
122    }
123
124    /**
125     * ProxySelector implementation used in the test.
126     */
127    static class TestProxySelector extends ProxySelector {
128        // proxy port
129        private int proxy_port;
130        // server port
131        private int server_port;
132
133        /**
134         * Creates proxy selector instance.
135         * Selector will return the proxy, only if the connection
136         * is made to localhost:server_port. Otherwise it will
137         * return NO_PROXY.
138         * Address of the returned proxy will be localhost:proxy_port.
139         */
140        public TestProxySelector(int server_port, int proxy_port) {
141            this.server_port = server_port;
142            this.proxy_port = proxy_port;
143        }
144
145        @Override
146        public java.util.List<Proxy> select(URI uri) {
147            Proxy proxy = Proxy.NO_PROXY;
148            if (("localhost".equals(uri.getHost()))
149                    && (server_port == uri.getPort())) {
150                proxy = new Proxy(Proxy.Type.HTTP,
151                            new InetSocketAddress("localhost", proxy_port));
152            }
153            ArrayList<Proxy> result = new ArrayList<Proxy>();
154            result.add(proxy);
155            return result;
156        }
157
158        @Override
159        public void connectFailed(URI uri, SocketAddress sa, IOException ioe) {
160            // do nothing
161        }
162    }
163
164    /**
165     * @tests org.apache.harmony.luni.internal.net.www.http.getOutputStream()
166     */
167    @TestTargetNew(
168        level = TestLevel.PARTIAL,
169        notes = "Regression test.",
170        method = "getOutputStream",
171        args = {}
172    )
173    public void testGetOutputStream() throws Exception {
174        // Regression for HARMONY-482
175        MockServer httpServer =
176            new MockServer("ServerSocket for HttpURLConnectionTest");
177        httpServer.start();
178        synchronized(bound) {
179            if (!httpServer.started) {
180                bound.wait(5000);
181            }
182        }
183        HttpURLConnection c = (HttpURLConnection)
184            new URL("http://127.0.0.1:" + httpServer.port()).openConnection();
185        c.setDoOutput(true);
186        //use new String("POST") instead of simple "POST" to obtain other
187        //object instances then those that are in HttpURLConnection classes
188        c.setRequestMethod(new String("POST"));
189        c.getOutputStream();
190        httpServer.join();
191    }
192
193
194    /**
195     * Test checks if the proxy specified in openConnection
196     * method will be used for connection to the server
197     */
198    @TestTargetNew(
199        level = TestLevel.PARTIAL,
200        notes = "Verifies if the proxy specified in openConnection method will be used for connection to the server.",
201        method = "usingProxy",
202        args = {}
203    )
204    public void testUsingProxy() throws Exception {
205        // Regression for HARMONY-570
206        MockServer server = new MockServer("server");
207        MockServer proxy = new MockServer("proxy");
208
209        URL url = new URL("http://localhost:" + server.port());
210
211        HttpURLConnection connection = (HttpURLConnection) url
212                .openConnection(new Proxy(Proxy.Type.HTTP,
213                        new InetSocketAddress("localhost",
214                            proxy.port())));
215        connection.setConnectTimeout(2000);
216        connection.setReadTimeout(2000);
217
218        server.start();
219        synchronized(bound) {
220            if (!server.started) bound.wait(5000);
221        }
222        proxy.start();
223        synchronized(bound) {
224            if (!proxy.started) bound.wait(5000);
225        }
226
227        connection.connect();
228
229        // wait while server and proxy run
230        server.join();
231        proxy.join();
232
233        assertTrue("Connection does not use proxy", connection.usingProxy());
234        assertTrue("Proxy server was not used", proxy.accepted);
235
236        HttpURLConnection huc = (HttpURLConnection)url.openConnection(Proxy.NO_PROXY);
237        assertFalse(huc.usingProxy());
238    }
239
240    /**
241     * Test checks if the proxy provided by proxy selector
242     * will be used for connection to the server
243     */
244    @TestTargetNew(
245        level = TestLevel.PARTIAL,
246        notes = "Verifies if the proxy provided by proxy selector will be used for connection to the server.",
247        method = "usingProxy",
248        args = {}
249    )
250    public void testUsingProxySelector() throws Exception {
251        // Regression for HARMONY-570
252        MockServer server = new MockServer("server");
253        MockServer proxy = new MockServer("proxy");
254
255        URL url = new URL("http://localhost:" + server.port());
256
257        // keep default proxy selector
258        ProxySelector defPS = ProxySelector.getDefault();
259        // replace selector
260        ProxySelector.setDefault(
261                new TestProxySelector(server.port(), proxy.port()));
262
263        try {
264            HttpURLConnection connection =
265                (HttpURLConnection) url.openConnection();
266            connection.setConnectTimeout(2000);
267            connection.setReadTimeout(2000);
268
269            server.start();
270            synchronized(bound) {
271                if (!server.started) bound.wait(5000);
272            }
273            proxy.start();
274            synchronized(bound) {
275                if (!proxy.started) bound.wait(5000);
276            }
277            connection.connect();
278
279            // wait while server and proxy run
280            server.join();
281            proxy.join();
282
283            assertTrue("Connection does not use proxy",
284                                            connection.usingProxy());
285            assertTrue("Proxy server was not used", proxy.accepted);
286        } finally {
287            // restore default proxy selector
288            ProxySelector.setDefault(defPS);
289        }
290    }
291    @TestTargets({
292        @TestTargetNew(
293            level = TestLevel.PARTIAL,
294            notes = "Regression test.",
295            method = "getResponseCode",
296            args = {}
297        ),
298        @TestTargetNew(
299            level = TestLevel.PARTIAL,
300            notes = "Regression test.",
301            method = "connect",
302            args = {}
303        )
304    })
305    public void testProxyAuthorization() throws Exception {
306        // Set up test Authenticator
307        Authenticator.setDefault(new Authenticator() {
308            @Override
309            protected PasswordAuthentication getPasswordAuthentication() {
310                return new PasswordAuthentication(
311                    "user", "password".toCharArray());
312            }
313        });
314
315        try {
316            MockProxyServer proxy = new MockProxyServer("ProxyServer");
317
318            URL url = new URL("http://remotehost:55555/requested.data");
319            HttpURLConnection connection =
320                (HttpURLConnection) url.openConnection(
321                        new Proxy(Proxy.Type.HTTP,
322                            new InetSocketAddress("localhost", proxy.port())));
323            connection.setConnectTimeout(1000);
324            connection.setReadTimeout(1000);
325
326            proxy.start();
327
328            connection.connect();
329            assertEquals("unexpected response code",
330                    200, connection.getResponseCode());
331            proxy.join();
332            assertTrue("Connection did not send proxy authorization request",
333                    proxy.acceptedAuthorizedRequest);
334        } finally {
335            // remove previously set authenticator
336            Authenticator.setDefault(null);
337        }
338    }
339
340}
341