• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright 2015 The Chromium Authors
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4 
5 package org.chromium.net.urlconnection;
6 
7 import static org.junit.Assert.assertEquals;
8 import static org.junit.Assert.assertTrue;
9 import static org.junit.Assert.fail;
10 
11 import static org.chromium.net.CronetTestRule.getContext;
12 
13 import androidx.test.ext.junit.runners.AndroidJUnit4;
14 import androidx.test.filters.SmallTest;
15 
16 import org.junit.After;
17 import org.junit.Before;
18 import org.junit.Rule;
19 import org.junit.Test;
20 import org.junit.runner.RunWith;
21 
22 import android.net.http.HttpEngine;
23 import org.chromium.net.CronetTestRule;
24 import org.chromium.net.CronetTestRule.CompareDefaultWithCronet;
25 import org.chromium.net.CronetTestRule.OnlyRunCronetHttpURLConnection;
26 import org.chromium.net.NativeTestServer;
27 import android.net.http.NetworkException;
28 
29 import java.io.IOException;
30 import java.io.OutputStream;
31 import java.net.HttpURLConnection;
32 import java.net.ProtocolException;
33 import java.net.URL;
34 
35 /**
36  * Tests {@code getOutputStream} when {@code setChunkedStreamingMode} is enabled.
37  * Tests annotated with {@code CompareDefaultWithCronet} will run once with the
38  * default HttpURLConnection implementation and then with Cronet's
39  * HttpURLConnection implementation. Tests annotated with
40  * {@code OnlyRunCronetHttpURLConnection} only run Cronet's implementation.
41  * See {@link CronetTestBase#runTest()} for details.
42  */
43 @RunWith(AndroidJUnit4.class)
44 public class CronetChunkedOutputStreamTest {
45     @Rule
46     public final CronetTestRule mTestRule = new CronetTestRule();
47 
48     private static final String UPLOAD_DATA_STRING = "Nifty upload data!";
49     private static final byte[] UPLOAD_DATA = UPLOAD_DATA_STRING.getBytes();
50     private static final int REPEAT_COUNT = 100000;
51 
52     @Before
setUp()53     public void setUp() throws Exception {
54         mTestRule.setStreamHandlerFactory(new HttpEngine.Builder(getContext()).build());
55         assertTrue(NativeTestServer.startNativeTestServer(getContext()));
56     }
57 
58     @After
tearDown()59     public void tearDown() throws Exception {
60         NativeTestServer.shutdownNativeTestServer();
61     }
62 
63     @Test
64     @SmallTest
65     @CompareDefaultWithCronet
testGetOutputStreamAfterConnectionMade()66     public void testGetOutputStreamAfterConnectionMade() throws Exception {
67         URL url = new URL(NativeTestServer.getEchoBodyURL());
68         HttpURLConnection connection = (HttpURLConnection) url.openConnection();
69         connection.setDoOutput(true);
70         connection.setRequestMethod("POST");
71         connection.setChunkedStreamingMode(0);
72         assertEquals(200, connection.getResponseCode());
73         try {
74             connection.getOutputStream();
75             fail();
76         } catch (ProtocolException e) {
77             // Expected.
78         }
79     }
80 
81     @Test
82     @SmallTest
83     @CompareDefaultWithCronet
testWriteAfterReadingResponse()84     public void testWriteAfterReadingResponse() throws Exception {
85         URL url = new URL(NativeTestServer.getEchoBodyURL());
86         HttpURLConnection connection = (HttpURLConnection) url.openConnection();
87         connection.setDoOutput(true);
88         connection.setRequestMethod("POST");
89         connection.setChunkedStreamingMode(0);
90         OutputStream out = connection.getOutputStream();
91         assertEquals(200, connection.getResponseCode());
92         try {
93             out.write(UPLOAD_DATA);
94             fail();
95         } catch (IOException e) {
96             // Expected.
97         }
98     }
99 
100     @Test
101     @SmallTest
102     @CompareDefaultWithCronet
testWriteAfterRequestFailed()103     public void testWriteAfterRequestFailed() throws Exception {
104         URL url = new URL(NativeTestServer.getEchoBodyURL());
105         HttpURLConnection connection = (HttpURLConnection) url.openConnection();
106         connection.setDoOutput(true);
107         connection.setRequestMethod("POST");
108         connection.setChunkedStreamingMode(0);
109         OutputStream out = connection.getOutputStream();
110         out.write(UPLOAD_DATA);
111         NativeTestServer.shutdownNativeTestServer();
112         try {
113             out.write(TestUtil.getLargeData());
114             connection.getResponseCode();
115             fail();
116         } catch (IOException e) {
117             if (!mTestRule.testingSystemHttpURLConnection()) {
118                 NetworkException requestException = (NetworkException) e;
119                 assertEquals(
120                         NetworkException.ERROR_CONNECTION_REFUSED, requestException.getErrorCode());
121             }
122         }
123         connection.disconnect();
124         // Restarting server to run the test for a second time.
125         assertTrue(NativeTestServer.startNativeTestServer(getContext()));
126     }
127 
128     @Test
129     @SmallTest
130     @CompareDefaultWithCronet
testGetResponseAfterWriteFailed()131     public void testGetResponseAfterWriteFailed() throws Exception {
132         URL url = new URL(NativeTestServer.getEchoBodyURL());
133         NativeTestServer.shutdownNativeTestServer();
134         HttpURLConnection connection = (HttpURLConnection) url.openConnection();
135         connection.setDoOutput(true);
136         connection.setRequestMethod("POST");
137         // Set 1 byte as chunk size so internally Cronet will try upload when
138         // 1 byte is filled.
139         connection.setChunkedStreamingMode(1);
140         try {
141             OutputStream out = connection.getOutputStream();
142             out.write(1);
143             out.write(1);
144             // Forces OutputStream implementation to flush. crbug.com/653072
145             out.flush();
146             // System's implementation is flaky see crbug.com/653072.
147             if (!mTestRule.testingSystemHttpURLConnection()) {
148                 fail();
149             }
150         } catch (IOException e) {
151             if (!mTestRule.testingSystemHttpURLConnection()) {
152                 NetworkException requestException = (NetworkException) e;
153                 assertEquals(
154                         NetworkException.ERROR_CONNECTION_REFUSED, requestException.getErrorCode());
155             }
156         }
157         // Make sure IOException is reported again when trying to read response
158         // from the connection.
159         try {
160             connection.getResponseCode();
161             fail();
162         } catch (IOException e) {
163             // Expected.
164             if (!mTestRule.testingSystemHttpURLConnection()) {
165                 NetworkException requestException = (NetworkException) e;
166                 assertEquals(
167                         NetworkException.ERROR_CONNECTION_REFUSED, requestException.getErrorCode());
168             }
169         }
170         // Restarting server to run the test for a second time.
171         assertTrue(NativeTestServer.startNativeTestServer(getContext()));
172     }
173 
174     @Test
175     @SmallTest
176     @CompareDefaultWithCronet
testPost()177     public void testPost() throws Exception {
178         URL url = new URL(NativeTestServer.getEchoBodyURL());
179         HttpURLConnection connection = (HttpURLConnection) url.openConnection();
180         connection.setDoOutput(true);
181         connection.setRequestMethod("POST");
182         connection.setChunkedStreamingMode(0);
183         OutputStream out = connection.getOutputStream();
184         out.write(UPLOAD_DATA);
185         assertEquals(200, connection.getResponseCode());
186         assertEquals("OK", connection.getResponseMessage());
187         assertEquals(UPLOAD_DATA_STRING, TestUtil.getResponseAsString(connection));
188         connection.disconnect();
189     }
190 
191     @Test
192     @SmallTest
193     @CompareDefaultWithCronet
testTransferEncodingHeaderSet()194     public void testTransferEncodingHeaderSet() throws Exception {
195         URL url = new URL(NativeTestServer.getEchoHeaderURL("Transfer-Encoding"));
196         HttpURLConnection connection = (HttpURLConnection) url.openConnection();
197         connection.setDoOutput(true);
198         connection.setRequestMethod("POST");
199         connection.setChunkedStreamingMode(0);
200         OutputStream out = connection.getOutputStream();
201         out.write(UPLOAD_DATA);
202         assertEquals(200, connection.getResponseCode());
203         assertEquals("OK", connection.getResponseMessage());
204         assertEquals("chunked", TestUtil.getResponseAsString(connection));
205         connection.disconnect();
206     }
207 
208     @Test
209     @SmallTest
210     @CompareDefaultWithCronet
testPostOneMassiveWrite()211     public void testPostOneMassiveWrite() throws Exception {
212         URL url = new URL(NativeTestServer.getEchoBodyURL());
213         HttpURLConnection connection = (HttpURLConnection) url.openConnection();
214         connection.setDoOutput(true);
215         connection.setRequestMethod("POST");
216         connection.setChunkedStreamingMode(0);
217         OutputStream out = connection.getOutputStream();
218         byte[] largeData = TestUtil.getLargeData();
219         out.write(largeData);
220         assertEquals(200, connection.getResponseCode());
221         assertEquals("OK", connection.getResponseMessage());
222         TestUtil.checkLargeData(TestUtil.getResponseAsString(connection));
223         connection.disconnect();
224     }
225 
226     @Test
227     @SmallTest
228     @CompareDefaultWithCronet
testPostWriteOneByte()229     public void testPostWriteOneByte() throws Exception {
230         URL url = new URL(NativeTestServer.getEchoBodyURL());
231         HttpURLConnection connection = (HttpURLConnection) url.openConnection();
232         connection.setDoOutput(true);
233         connection.setRequestMethod("POST");
234         connection.setChunkedStreamingMode(0);
235         OutputStream out = connection.getOutputStream();
236         for (int i = 0; i < UPLOAD_DATA.length; i++) {
237             out.write(UPLOAD_DATA[i]);
238         }
239         assertEquals(200, connection.getResponseCode());
240         assertEquals("OK", connection.getResponseMessage());
241         assertEquals(UPLOAD_DATA_STRING, TestUtil.getResponseAsString(connection));
242         connection.disconnect();
243     }
244 
245     @Test
246     @SmallTest
247     @CompareDefaultWithCronet
testPostOneMassiveWriteWriteOneByte()248     public void testPostOneMassiveWriteWriteOneByte() throws Exception {
249         URL url = new URL(NativeTestServer.getEchoBodyURL());
250         HttpURLConnection connection = (HttpURLConnection) url.openConnection();
251         connection.setDoOutput(true);
252         connection.setRequestMethod("POST");
253         connection.setChunkedStreamingMode(0);
254         OutputStream out = connection.getOutputStream();
255         byte[] largeData = TestUtil.getLargeData();
256         for (int i = 0; i < largeData.length; i++) {
257             out.write(largeData[i]);
258         }
259         assertEquals(200, connection.getResponseCode());
260         assertEquals("OK", connection.getResponseMessage());
261         TestUtil.checkLargeData(TestUtil.getResponseAsString(connection));
262         connection.disconnect();
263     }
264 
265     @Test
266     @SmallTest
267     @CompareDefaultWithCronet
testPostWholeNumberOfChunks()268     public void testPostWholeNumberOfChunks() throws Exception {
269         URL url = new URL(NativeTestServer.getEchoBodyURL());
270         HttpURLConnection connection = (HttpURLConnection) url.openConnection();
271         connection.setDoOutput(true);
272         connection.setRequestMethod("POST");
273         int totalSize = UPLOAD_DATA.length * REPEAT_COUNT;
274         int chunkSize = 18000;
275         // Ensure total data size is a multiple of chunk size, so no partial
276         // chunks will be used.
277         assertEquals(0, totalSize % chunkSize);
278         connection.setChunkedStreamingMode(chunkSize);
279         OutputStream out = connection.getOutputStream();
280         byte[] largeData = TestUtil.getLargeData();
281         out.write(largeData);
282         assertEquals(200, connection.getResponseCode());
283         assertEquals("OK", connection.getResponseMessage());
284         TestUtil.checkLargeData(TestUtil.getResponseAsString(connection));
285         connection.disconnect();
286     }
287 
288     @Test
289     @SmallTest
290     @OnlyRunCronetHttpURLConnection
291     // Regression testing for crbug.com/618872.
testOneMassiveWriteLargerThanInternalBuffer()292     public void testOneMassiveWriteLargerThanInternalBuffer() throws Exception {
293         URL url = new URL(NativeTestServer.getEchoBodyURL());
294         HttpURLConnection connection = (HttpURLConnection) url.openConnection();
295         connection.setDoOutput(true);
296         connection.setRequestMethod("POST");
297         // Use a super big chunk size so that it exceeds the UploadDataProvider
298         // read buffer size.
299         byte[] largeData = TestUtil.getLargeData();
300         connection.setChunkedStreamingMode(largeData.length);
301         OutputStream out = connection.getOutputStream();
302         out.write(largeData);
303         assertEquals(200, connection.getResponseCode());
304         TestUtil.checkLargeData(TestUtil.getResponseAsString(connection));
305         connection.disconnect();
306     }
307 }
308