• 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 com.google.common.truth.Truth.assertThat;
8 
9 import static org.junit.Assert.assertThrows;
10 
11 import androidx.test.ext.junit.runners.AndroidJUnit4;
12 import androidx.test.filters.SmallTest;
13 
14 import org.junit.After;
15 import org.junit.Before;
16 import org.junit.Rule;
17 import org.junit.Test;
18 import org.junit.runner.RunWith;
19 
20 import org.chromium.base.test.util.Batch;
21 import org.chromium.net.CronetEngine;
22 import org.chromium.net.CronetTestRule;
23 import org.chromium.net.CronetTestRule.CronetImplementation;
24 import org.chromium.net.CronetTestRule.IgnoreFor;
25 import org.chromium.net.NativeTestServer;
26 import org.chromium.net.NetworkException;
27 
28 import java.io.IOException;
29 import java.io.OutputStream;
30 import java.net.HttpURLConnection;
31 import java.net.ProtocolException;
32 import java.net.URL;
33 
34 /** Tests {@code getOutputStream} when {@code setChunkedStreamingMode} is enabled. */
35 @Batch(Batch.UNIT_TESTS)
36 @IgnoreFor(
37         implementations = {CronetImplementation.FALLBACK},
38         reason = "See crrev.com/c/4590329")
39 @RunWith(AndroidJUnit4.class)
40 public class CronetChunkedOutputStreamTest {
41     @Rule public final CronetTestRule mTestRule = CronetTestRule.withAutomaticEngineStartup();
42 
43     private static final String UPLOAD_DATA_STRING = "Nifty upload data!";
44     private static final byte[] UPLOAD_DATA = UPLOAD_DATA_STRING.getBytes();
45     private static final int REPEAT_COUNT = 100000;
46 
47     private HttpURLConnection mConnection;
48 
49     private CronetEngine mCronetEngine;
50 
51     @Before
setUp()52     public void setUp() throws Exception {
53         mCronetEngine = mTestRule.getTestFramework().getEngine();
54         assertThat(
55                         NativeTestServer.startNativeTestServer(
56                                 mTestRule.getTestFramework().getContext()))
57                 .isTrue();
58     }
59 
60     @After
tearDown()61     public void tearDown() throws Exception {
62         if (mConnection != null) {
63             mConnection.disconnect();
64         }
65         NativeTestServer.shutdownNativeTestServer();
66     }
67 
68     @Test
69     @SmallTest
testGetOutputStreamAfterConnectionMade()70     public void testGetOutputStreamAfterConnectionMade() throws Exception {
71         URL url = new URL(NativeTestServer.getEchoBodyURL());
72         mConnection = (HttpURLConnection) mCronetEngine.openConnection(url);
73         mConnection.setDoOutput(true);
74         mConnection.setRequestMethod("POST");
75         mConnection.setChunkedStreamingMode(0);
76         assertThat(mConnection.getResponseCode()).isEqualTo(200);
77         assertThrows(ProtocolException.class, mConnection::getOutputStream);
78     }
79 
80     @Test
81     @SmallTest
testWriteAfterReadingResponse()82     public void testWriteAfterReadingResponse() throws Exception {
83         URL url = new URL(NativeTestServer.getEchoBodyURL());
84         mConnection = (HttpURLConnection) mCronetEngine.openConnection(url);
85         mConnection.setDoOutput(true);
86         mConnection.setRequestMethod("POST");
87         mConnection.setChunkedStreamingMode(0);
88         OutputStream out = mConnection.getOutputStream();
89         assertThat(mConnection.getResponseCode()).isEqualTo(200);
90         assertThrows(IOException.class, () -> out.write(UPLOAD_DATA));
91     }
92 
93     @Test
94     @SmallTest
testWriteAfterRequestFailed()95     public void testWriteAfterRequestFailed() throws Exception {
96         URL url = new URL(NativeTestServer.getEchoBodyURL());
97         mConnection = (HttpURLConnection) mCronetEngine.openConnection(url);
98         mConnection.setDoOutput(true);
99         mConnection.setRequestMethod("POST");
100         mConnection.setChunkedStreamingMode(0);
101         OutputStream out = mConnection.getOutputStream();
102         out.write(UPLOAD_DATA);
103         NativeTestServer.shutdownNativeTestServer();
104         IOException e = assertThrows(IOException.class, () -> out.write(TestUtil.getLargeData()));
105         // TODO(crbug.com/1495774): Consider whether we should be checking this in the first place.
106         if (mTestRule.implementationUnderTest().equals(CronetImplementation.STATICALLY_LINKED)) {
107             assertThat(e).isInstanceOf(NetworkException.class);
108             NetworkException networkException = (NetworkException) e;
109             assertThat(networkException.getErrorCode())
110                     .isEqualTo(NetworkException.ERROR_CONNECTION_REFUSED);
111         }
112     }
113 
114     @Test
115     @SmallTest
testGetResponseAfterWriteFailed()116     public void testGetResponseAfterWriteFailed() throws Exception {
117         URL url = new URL(NativeTestServer.getEchoBodyURL());
118         NativeTestServer.shutdownNativeTestServer();
119         mConnection = (HttpURLConnection) mCronetEngine.openConnection(url);
120         mConnection.setDoOutput(true);
121         mConnection.setRequestMethod("POST");
122         // Set 1 byte as chunk size so internally Cronet will try upload when
123         // 1 byte is filled.
124         mConnection.setChunkedStreamingMode(1);
125         OutputStream out = mConnection.getOutputStream();
126         out.write(1);
127         IOException e = assertThrows(IOException.class, () -> out.write(1));
128         // TODO(crbug.com/1495774): Consider whether we should be checking this in the first place.
129         if (mTestRule.implementationUnderTest().equals(CronetImplementation.STATICALLY_LINKED)) {
130             assertThat(e).isInstanceOf(NetworkException.class);
131             NetworkException networkException = (NetworkException) e;
132             assertThat(networkException.getErrorCode())
133                     .isEqualTo(NetworkException.ERROR_CONNECTION_REFUSED);
134         }
135 
136         // Make sure IOException is reported again when trying to read response
137         // from the mConnection.
138         e = assertThrows(IOException.class, mConnection::getResponseCode);
139         // TODO(crbug.com/1495774): Consider whether we should be checking this in the first place.
140         if (mTestRule.implementationUnderTest().equals(CronetImplementation.STATICALLY_LINKED)) {
141             assertThat(e).isInstanceOf(NetworkException.class);
142             NetworkException networkException = (NetworkException) e;
143             assertThat(networkException.getErrorCode())
144                     .isEqualTo(NetworkException.ERROR_CONNECTION_REFUSED);
145         }
146     }
147 
148     @Test
149     @SmallTest
testPost()150     public void testPost() throws Exception {
151         URL url = new URL(NativeTestServer.getEchoBodyURL());
152         mConnection = (HttpURLConnection) mCronetEngine.openConnection(url);
153         mConnection.setDoOutput(true);
154         mConnection.setRequestMethod("POST");
155         mConnection.setChunkedStreamingMode(0);
156         OutputStream out = mConnection.getOutputStream();
157         out.write(UPLOAD_DATA);
158         assertThat(mConnection.getResponseCode()).isEqualTo(200);
159         assertThat(mConnection.getResponseMessage()).isEqualTo("OK");
160         assertThat(TestUtil.getResponseAsString(mConnection)).isEqualTo(UPLOAD_DATA_STRING);
161     }
162 
163     @Test
164     @SmallTest
testTransferEncodingHeaderSet()165     public void testTransferEncodingHeaderSet() throws Exception {
166         URL url = new URL(NativeTestServer.getEchoHeaderURL("Transfer-Encoding"));
167         mConnection = (HttpURLConnection) mCronetEngine.openConnection(url);
168         mConnection.setDoOutput(true);
169         mConnection.setRequestMethod("POST");
170         mConnection.setChunkedStreamingMode(0);
171         OutputStream out = mConnection.getOutputStream();
172         out.write(UPLOAD_DATA);
173         assertThat(mConnection.getResponseCode()).isEqualTo(200);
174         assertThat(mConnection.getResponseMessage()).isEqualTo("OK");
175         assertThat(TestUtil.getResponseAsString(mConnection)).isEqualTo("chunked");
176     }
177 
178     @Test
179     @SmallTest
testPostOneMassiveWrite()180     public void testPostOneMassiveWrite() throws Exception {
181         URL url = new URL(NativeTestServer.getEchoBodyURL());
182         mConnection = (HttpURLConnection) mCronetEngine.openConnection(url);
183         mConnection.setDoOutput(true);
184         mConnection.setRequestMethod("POST");
185         mConnection.setChunkedStreamingMode(0);
186         OutputStream out = mConnection.getOutputStream();
187         byte[] largeData = TestUtil.getLargeData();
188         out.write(largeData);
189         assertThat(mConnection.getResponseCode()).isEqualTo(200);
190         assertThat(mConnection.getResponseMessage()).isEqualTo("OK");
191         TestUtil.checkLargeData(TestUtil.getResponseAsString(mConnection));
192     }
193 
194     @Test
195     @SmallTest
testPostWriteOneByte()196     public void testPostWriteOneByte() throws Exception {
197         URL url = new URL(NativeTestServer.getEchoBodyURL());
198         mConnection = (HttpURLConnection) mCronetEngine.openConnection(url);
199         mConnection.setDoOutput(true);
200         mConnection.setRequestMethod("POST");
201         mConnection.setChunkedStreamingMode(0);
202         OutputStream out = mConnection.getOutputStream();
203         for (int i = 0; i < UPLOAD_DATA.length; i++) {
204             out.write(UPLOAD_DATA[i]);
205         }
206         assertThat(mConnection.getResponseCode()).isEqualTo(200);
207         assertThat(mConnection.getResponseMessage()).isEqualTo("OK");
208         assertThat(TestUtil.getResponseAsString(mConnection)).isEqualTo(UPLOAD_DATA_STRING);
209     }
210 
211     @Test
212     @SmallTest
testPostOneMassiveWriteWriteOneByte()213     public void testPostOneMassiveWriteWriteOneByte() throws Exception {
214         URL url = new URL(NativeTestServer.getEchoBodyURL());
215         mConnection = (HttpURLConnection) mCronetEngine.openConnection(url);
216         mConnection.setDoOutput(true);
217         mConnection.setRequestMethod("POST");
218         mConnection.setChunkedStreamingMode(0);
219         OutputStream out = mConnection.getOutputStream();
220         byte[] largeData = TestUtil.getLargeData();
221         for (int i = 0; i < largeData.length; i++) {
222             out.write(largeData[i]);
223         }
224         assertThat(mConnection.getResponseCode()).isEqualTo(200);
225         assertThat(mConnection.getResponseMessage()).isEqualTo("OK");
226         TestUtil.checkLargeData(TestUtil.getResponseAsString(mConnection));
227     }
228 
229     @Test
230     @SmallTest
testPostWholeNumberOfChunks()231     public void testPostWholeNumberOfChunks() throws Exception {
232         URL url = new URL(NativeTestServer.getEchoBodyURL());
233         mConnection = (HttpURLConnection) mCronetEngine.openConnection(url);
234         mConnection.setDoOutput(true);
235         mConnection.setRequestMethod("POST");
236         int totalSize = UPLOAD_DATA.length * REPEAT_COUNT;
237         int chunkSize = 18000;
238         // Ensure total data size is a multiple of chunk size, so no partial
239         // chunks will be used.
240         assertThat(totalSize % chunkSize).isEqualTo(0);
241         mConnection.setChunkedStreamingMode(chunkSize);
242         OutputStream out = mConnection.getOutputStream();
243         byte[] largeData = TestUtil.getLargeData();
244         out.write(largeData);
245         assertThat(mConnection.getResponseCode()).isEqualTo(200);
246         assertThat(mConnection.getResponseMessage()).isEqualTo("OK");
247         TestUtil.checkLargeData(TestUtil.getResponseAsString(mConnection));
248     }
249 
250     @Test
251     @SmallTest
252     // Regression testing for crbug.com/618872.
testOneMassiveWriteLargerThanInternalBuffer()253     public void testOneMassiveWriteLargerThanInternalBuffer() throws Exception {
254         URL url = new URL(NativeTestServer.getEchoBodyURL());
255         mConnection = (HttpURLConnection) mCronetEngine.openConnection(url);
256         mConnection.setDoOutput(true);
257         mConnection.setRequestMethod("POST");
258         // Use a super big chunk size so that it exceeds the UploadDataProvider
259         // read buffer size.
260         byte[] largeData = TestUtil.getLargeData();
261         mConnection.setChunkedStreamingMode(largeData.length);
262         OutputStream out = mConnection.getOutputStream();
263         out.write(largeData);
264         assertThat(mConnection.getResponseCode()).isEqualTo(200);
265         TestUtil.checkLargeData(TestUtil.getResponseAsString(mConnection));
266     }
267 }
268