1/*
2 * Copyright (C) 2013 Square, Inc.
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 *      http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16package com.squareup.okhttp;
17
18import com.squareup.okhttp.internal.Util;
19import java.io.File;
20import java.io.FileWriter;
21import java.io.IOException;
22import java.net.URI;
23import java.net.URL;
24import java.util.Arrays;
25import java.util.Collections;
26import okio.Buffer;
27import org.junit.Test;
28
29import static org.junit.Assert.assertEquals;
30import static org.junit.Assert.assertNull;
31import static org.junit.Assert.fail;
32
33public final class RequestTest {
34  @Test public void string() throws Exception {
35    MediaType contentType = MediaType.parse("text/plain; charset=utf-8");
36    RequestBody body = RequestBody.create(contentType, "abc".getBytes(Util.UTF_8));
37    assertEquals(contentType, body.contentType());
38    assertEquals(3, body.contentLength());
39    assertEquals("616263", bodyToHex(body));
40    assertEquals("Retransmit body", "616263", bodyToHex(body));
41  }
42
43  @Test public void stringWithDefaultCharsetAdded() throws Exception {
44    MediaType contentType = MediaType.parse("text/plain");
45    RequestBody body = RequestBody.create(contentType, "\u0800");
46    assertEquals(MediaType.parse("text/plain; charset=utf-8"), body.contentType());
47    assertEquals(3, body.contentLength());
48    assertEquals("e0a080", bodyToHex(body));
49  }
50
51  @Test public void stringWithNonDefaultCharsetSpecified() throws Exception {
52    MediaType contentType = MediaType.parse("text/plain; charset=utf-16be");
53    RequestBody body = RequestBody.create(contentType, "\u0800");
54    assertEquals(contentType, body.contentType());
55    assertEquals(2, body.contentLength());
56    assertEquals("0800", bodyToHex(body));
57  }
58
59  @Test public void byteArray() throws Exception {
60    MediaType contentType = MediaType.parse("text/plain");
61    RequestBody body = RequestBody.create(contentType, "abc".getBytes(Util.UTF_8));
62    assertEquals(contentType, body.contentType());
63    assertEquals(3, body.contentLength());
64    assertEquals("616263", bodyToHex(body));
65    assertEquals("Retransmit body", "616263", bodyToHex(body));
66  }
67
68  @Test public void byteArrayRange() throws Exception {
69    MediaType contentType = MediaType.parse("text/plain");
70    RequestBody body = RequestBody.create(contentType, ".abcd".getBytes(Util.UTF_8), 1, 3);
71    assertEquals(contentType, body.contentType());
72    assertEquals(3, body.contentLength());
73    assertEquals("616263", bodyToHex(body));
74    assertEquals("Retransmit body", "616263", bodyToHex(body));
75  }
76
77  @Test public void file() throws Exception {
78    File file = File.createTempFile("RequestTest", "tmp");
79    FileWriter writer = new FileWriter(file);
80    writer.write("abc");
81    writer.close();
82
83    MediaType contentType = MediaType.parse("text/plain");
84    RequestBody body = RequestBody.create(contentType, file);
85    assertEquals(contentType, body.contentType());
86    assertEquals(3, body.contentLength());
87    assertEquals("616263", bodyToHex(body));
88    assertEquals("Retransmit body", "616263", bodyToHex(body));
89  }
90
91  /** Common verbs used for apis such as GitHub, AWS, and Google Cloud. */
92  @Test public void crudVerbs() throws IOException {
93    MediaType contentType = MediaType.parse("application/json");
94    RequestBody body = RequestBody.create(contentType, "{}");
95
96    Request get = new Request.Builder().url("http://localhost/api").get().build();
97    assertEquals("GET", get.method());
98    assertNull(get.body());
99
100    Request head = new Request.Builder().url("http://localhost/api").head().build();
101    assertEquals("HEAD", head.method());
102    assertNull(head.body());
103
104    Request delete = new Request.Builder().url("http://localhost/api").delete().build();
105    assertEquals("DELETE", delete.method());
106    assertEquals(0L, delete.body().contentLength());
107
108    Request post = new Request.Builder().url("http://localhost/api").post(body).build();
109    assertEquals("POST", post.method());
110    assertEquals(body, post.body());
111
112    Request put = new Request.Builder().url("http://localhost/api").put(body).build();
113    assertEquals("PUT", put.method());
114    assertEquals(body, put.body());
115
116    Request patch = new Request.Builder().url("http://localhost/api").patch(body).build();
117    assertEquals("PATCH", patch.method());
118    assertEquals(body, patch.body());
119  }
120
121  @Test public void uninitializedURI() throws Exception {
122    Request request = new Request.Builder().url("http://localhost/api").build();
123    assertEquals(new URI("http://localhost/api"), request.uri());
124    assertEquals(new URL("http://localhost/api"), request.url());
125  }
126
127  @Test public void newBuilderUrlResetsUrl() throws Exception {
128    Request requestWithoutCache = new Request.Builder().url("http://localhost/api").build();
129    Request builtRequestWithoutCache = requestWithoutCache.newBuilder().url("http://localhost/api/foo").build();
130    assertEquals(new URL("http://localhost/api/foo"), builtRequestWithoutCache.url());
131
132    Request requestWithCache = new Request.Builder().url("http://localhost/api").build();
133    // cache url object
134    requestWithCache.url();
135    Request builtRequestWithCache = requestWithCache.newBuilder().url(
136        "http://localhost/api/foo").build();
137    assertEquals(new URL("http://localhost/api/foo"), builtRequestWithCache.url());
138  }
139
140  @Test public void cacheControl() throws Exception {
141    Request request = new Request.Builder()
142        .cacheControl(new CacheControl.Builder().noCache().build())
143        .url("https://square.com")
144        .build();
145    assertEquals(Arrays.asList("no-cache"), request.headers("Cache-Control"));
146  }
147
148  @Test public void emptyCacheControlClearsAllCacheControlHeaders() throws Exception {
149    Request request = new Request.Builder()
150        .header("Cache-Control", "foo")
151        .cacheControl(new CacheControl.Builder().build())
152        .url("https://square.com")
153        .build();
154    assertEquals(Collections.<String>emptyList(), request.headers("Cache-Control"));
155  }
156
157  @Test public void headerAcceptsPermittedCharacters() throws Exception {
158    Request.Builder builder = new Request.Builder();
159    builder.header("AZab09 ~", "AZab09 ~");
160    builder.addHeader("AZab09 ~", "AZab09 ~");
161  }
162
163  @Test public void emptyNameForbidden() throws Exception {
164    Request.Builder builder = new Request.Builder();
165    try {
166      builder.header("", "Value");
167      fail();
168    } catch (IllegalArgumentException expected) {
169    }
170    try {
171      builder.addHeader("", "Value");
172      fail();
173    } catch (IllegalArgumentException expected) {
174    }
175  }
176
177  @Test public void headerForbidsControlCharacters() throws Exception {
178    assertForbiddenHeader(null);
179    assertForbiddenHeader("\u0000");
180    // Workaround for http://b/26422335 , http://b/26889631
181    // assertForbiddenHeader("\n");
182    assertForbiddenHeader("a\nb");
183    assertForbiddenHeader("\nb");
184    // assertForbiddenHeader("\r");
185    assertForbiddenHeader("a\rb");
186    assertForbiddenHeader("\rb");
187    // End of Android modification.
188    assertForbiddenHeader("\t");
189    assertForbiddenHeader("\u001f");
190    assertForbiddenHeader("\u007f");
191
192    // ANDROID-BEGIN Workaround for http://b/28867041
193    // assertForbiddenHeader("\u0080");
194    // assertForbiddenHeader("\ud83c\udf69");
195    // ANDROID-END
196  }
197
198  private void assertForbiddenHeader(String s) {
199    Request.Builder builder = new Request.Builder();
200    try {
201      builder.header(s, "Value");
202      fail();
203    } catch (IllegalArgumentException expected) {
204    }
205    try {
206      builder.addHeader(s, "Value");
207      fail();
208    } catch (IllegalArgumentException expected) {
209    }
210    try {
211      builder.header("Name", s);
212      fail();
213    } catch (IllegalArgumentException expected) {
214    }
215    try {
216      builder.addHeader("Name", s);
217      fail();
218    } catch (IllegalArgumentException expected) {
219    }
220  }
221
222  private String bodyToHex(RequestBody body) throws IOException {
223    Buffer buffer = new Buffer();
224    body.writeTo(buffer);
225    return buffer.readByteString().hex();
226  }
227}
228