Skip to content

Commit

Permalink
Support common http verbs including zero length POST, DELETE.
Browse files Browse the repository at this point in the history
  • Loading branch information
Adrian Cole committed Apr 26, 2014
1 parent 04aee71 commit 520d9fc
Show file tree
Hide file tree
Showing 8 changed files with 207 additions and 56 deletions.
180 changes: 142 additions & 38 deletions okhttp-tests/src/test/java/com/squareup/okhttp/CallTest.java
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,148 @@ public final class CallTest {
cache.delete();
}

@Test public void get() throws Exception {
server.enqueue(new MockResponse().setBody("abc").addHeader("Content-Type: text/plain"));
server.play();

Request request = new Request.Builder()
.url(server.getUrl("/"))
.header("User-Agent", "SyncApiTest")
.build();

executeSynchronously(request)
.assertCode(200)
.assertContainsHeaders("Content-Type: text/plain")
.assertBody("abc");

RecordedRequest recordedRequest = server.takeRequest();
assertEquals("GET", recordedRequest.getMethod());
assertEquals("SyncApiTest", recordedRequest.getHeader("User-Agent"));
assertEquals(0, recordedRequest.getBody().length);
assertNull(recordedRequest.getHeader("Content-Length"));
}

@Test public void head() throws Exception {
server.enqueue(new MockResponse().addHeader("Content-Type: text/plain"));
server.play();

Request request = new Request.Builder()
.url(server.getUrl("/"))
.head()
.header("User-Agent", "SyncApiTest")
.build();

executeSynchronously(request)
.assertCode(200)
.assertContainsHeaders("Content-Type: text/plain");

RecordedRequest recordedRequest = server.takeRequest();
assertEquals("HEAD", recordedRequest.getMethod());
assertEquals("SyncApiTest", recordedRequest.getHeader("User-Agent"));
assertEquals(0, recordedRequest.getBody().length);
assertNull(recordedRequest.getHeader("Content-Length"));
}

@Test public void post() throws Exception {
server.enqueue(new MockResponse().setBody("abc"));
server.play();

Request request = new Request.Builder()
.url(server.getUrl("/"))
.post(Request.Body.create(MediaType.parse("text/plain"), "def"))
.build();

executeSynchronously(request)
.assertCode(200)
.assertBody("abc");

RecordedRequest recordedRequest = server.takeRequest();
assertEquals("POST", recordedRequest.getMethod());
assertEquals("def", recordedRequest.getUtf8Body());
assertEquals("3", recordedRequest.getHeader("Content-Length"));
assertEquals("text/plain; charset=utf-8", recordedRequest.getHeader("Content-Type"));
}

@Test public void postZeroLength() throws Exception {
server.enqueue(new MockResponse().setBody("abc"));
server.play();

Request request = new Request.Builder()
.url(server.getUrl("/"))
.method("POST", null)
.build();

executeSynchronously(request)
.assertCode(200)
.assertBody("abc");

RecordedRequest recordedRequest = server.takeRequest();
assertEquals("POST", recordedRequest.getMethod());
assertEquals(0, recordedRequest.getBody().length);
assertEquals("0", recordedRequest.getHeader("Content-Length"));
assertEquals(null, recordedRequest.getHeader("Content-Type"));
}

@Test public void delete() throws Exception {
server.enqueue(new MockResponse().setBody("abc"));
server.play();

Request request = new Request.Builder()
.url(server.getUrl("/"))
.delete()
.build();

executeSynchronously(request)
.assertCode(200)
.assertBody("abc");

RecordedRequest recordedRequest = server.takeRequest();
assertEquals("DELETE", recordedRequest.getMethod());
assertEquals(0, recordedRequest.getBody().length);
assertEquals("0", recordedRequest.getHeader("Content-Length"));
assertEquals(null, recordedRequest.getHeader("Content-Type"));
}

@Test public void put() throws Exception {
server.enqueue(new MockResponse().setBody("abc"));
server.play();

Request request = new Request.Builder()
.url(server.getUrl("/"))
.put(Request.Body.create(MediaType.parse("text/plain"), "def"))
.build();

executeSynchronously(request)
.assertCode(200)
.assertBody("abc");

RecordedRequest recordedRequest = server.takeRequest();
assertEquals("PUT", recordedRequest.getMethod());
assertEquals("def", recordedRequest.getUtf8Body());
assertEquals("3", recordedRequest.getHeader("Content-Length"));
assertEquals("text/plain; charset=utf-8", recordedRequest.getHeader("Content-Type"));
}

@Test public void patch() throws Exception {
server.enqueue(new MockResponse().setBody("abc"));
server.play();

Request request = new Request.Builder()
.url(server.getUrl("/"))
.patch(Request.Body.create(MediaType.parse("text/plain"), "def"))
.build();

executeSynchronously(request)
.assertCode(200)
.assertBody("abc");

RecordedRequest recordedRequest = server.takeRequest();
assertEquals("PATCH", recordedRequest.getMethod());
assertEquals("def", recordedRequest.getUtf8Body());
assertEquals("3", recordedRequest.getHeader("Content-Length"));
assertEquals("text/plain; charset=utf-8", recordedRequest.getHeader("Content-Type"));
}

@Test public void illegalToExecuteTwice() throws Exception {
server.enqueue(new MockResponse()
.setBody("abc")
Expand Down Expand Up @@ -127,25 +269,6 @@ public final class CallTest {
assertTrue(server.takeRequest().getHeaders().contains("User-Agent: SyncApiTest"));
}

@Test public void get() throws Exception {
server.enqueue(new MockResponse()
.setBody("abc")
.addHeader("Content-Type: text/plain"));
server.play();

Request request = new Request.Builder()
.url(server.getUrl("/"))
.header("User-Agent", "SyncApiTest")
.build();

executeSynchronously(request)
.assertCode(200)
.assertContainsHeaders("Content-Type: text/plain")
.assertBody("abc");

assertTrue(server.takeRequest().getHeaders().contains("User-Agent: SyncApiTest"));
}

@Test public void get_Async() throws Exception {
server.enqueue(new MockResponse()
.setBody("abc")
Expand Down Expand Up @@ -340,25 +463,6 @@ public final class CallTest {
assertEquals(301, response.code());
}

@Test public void post() throws Exception {
server.enqueue(new MockResponse().setBody("abc"));
server.play();

Request request = new Request.Builder()
.url(server.getUrl("/"))
.post(Request.Body.create(MediaType.parse("text/plain"), "def"))
.build();

executeSynchronously(request)
.assertCode(200)
.assertBody("abc");

RecordedRequest recordedRequest = server.takeRequest();
assertEquals("def", recordedRequest.getUtf8Body());
assertEquals("3", recordedRequest.getHeader("Content-Length"));
assertEquals("text/plain; charset=utf-8", recordedRequest.getHeader("Content-Type"));
}

@Test public void post_Async() throws Exception {
server.enqueue(new MockResponse().setBody("abc"));
server.play();
Expand Down
31 changes: 31 additions & 0 deletions okhttp-tests/src/test/java/com/squareup/okhttp/RequestTest.java
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@
import org.junit.Test;

import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNull;

public final class RequestTest {
@Test public void string() throws Exception {
Expand Down Expand Up @@ -73,6 +74,36 @@ public final class RequestTest {
assertEquals("Retransmit body", "616263", bodyToHex(body));
}

/** Common verbs used for apis such as GitHub, AWS, and Google Cloud. */
@Test public void crudVerbs() {
MediaType contentType = MediaType.parse("application/json");
Request.Body body = Request.Body.create(contentType, "{}");

Request get = new Request.Builder().url("http://localhost/api").get().build();
assertEquals("GET", get.method());
assertNull(get.body());

Request head = new Request.Builder().url("http://localhost/api").head().build();
assertEquals("HEAD", head.method());
assertNull(head.body());

Request delete = new Request.Builder().url("http://localhost/api").delete().build();
assertEquals("DELETE", delete.method());
assertNull(delete.body());

Request post = new Request.Builder().url("http://localhost/api").post(body).build();
assertEquals("POST", post.method());
assertEquals(body, post.body());

Request put = new Request.Builder().url("http://localhost/api").put(body).build();
assertEquals("PUT", put.method());
assertEquals(body, put.body());

Request patch = new Request.Builder().url("http://localhost/api").patch(body).build();
assertEquals("PATCH", patch.method());
assertEquals(body, patch.body());
}

private String bodyToHex(Request.Body body) throws IOException {
Buffer buffer = new Buffer();
body.writeTo(buffer);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -209,7 +209,7 @@ private void testCreateOkResponseInternal(HttpURLConnectionFactory httpUrlConnec
@Test public void createOkResponse_fromCacheResponse() throws Exception {
final String statusLine = "HTTP/1.1 200 Fantastic";
URI uri = new URI("http://foo/bar");
Request request = new Request.Builder().url(uri.toURL()).method("GET", null).build();
Request request = new Request.Builder().url(uri.toURL()).build();
CacheResponse cacheResponse = new CacheResponse() {
@Override
public Map<String, List<String>> getHeaders() throws IOException {
Expand Down Expand Up @@ -244,7 +244,7 @@ public InputStream getBody() throws IOException {
final Principal serverPrincipal = SERVER_CERT.getSubjectX500Principal();
final List<Certificate> serverCertificates = Arrays.<Certificate>asList(SERVER_CERT);
URI uri = new URI("https://foo/bar");
Request request = new Request.Builder().url(uri.toURL()).method("GET", null).build();
Request request = new Request.Builder().url(uri.toURL()).build();
SecureCacheResponse cacheResponse = new SecureCacheResponse() {
@Override
public Map<String, List<String>> getHeaders() throws IOException {
Expand Down Expand Up @@ -517,7 +517,7 @@ private void assertHeadersContainsMapping(Map<String, List<String>> headers, Str

@Test public void createJavaUrlConnection_accessibleRequestInfo_GET() throws Exception {
Request okRequest = createArbitraryOkRequest().newBuilder()
.method("GET", null)
.get()
.build();
Response okResponse = createArbitraryOkResponse(okRequest);
HttpURLConnection httpUrlConnection = JavaApiConverter.createJavaUrlConnection(okResponse);
Expand All @@ -529,7 +529,7 @@ private void assertHeadersContainsMapping(Map<String, List<String>> headers, Str

@Test public void createJavaUrlConnection_accessibleRequestInfo_POST() throws Exception {
Request okRequest = createArbitraryOkRequest().newBuilder()
.method("POST", createRequestBody("PostBody"))
.post(createRequestBody("PostBody"))
.build();
Response okResponse = createArbitraryOkResponse(okRequest);
HttpURLConnection httpUrlConnection = JavaApiConverter.createJavaUrlConnection(okResponse);
Expand All @@ -541,7 +541,7 @@ private void assertHeadersContainsMapping(Map<String, List<String>> headers, Str

@Test public void createJavaUrlConnection_https_extraHttpsMethods() throws Exception {
Request okRequest = createArbitraryOkRequest().newBuilder()
.method("GET", null)
.get()
.url("https://secure/request")
.build();
Handshake handshake = Handshake.get("SecureCipher", Arrays.<Certificate>asList(SERVER_CERT),
Expand Down Expand Up @@ -584,7 +584,7 @@ private void assertHeadersContainsMapping(Map<String, List<String>> headers, Str
Request okRequest =
createArbitraryOkRequest().newBuilder()
.url("http://insecure/request")
.method("GET", null)
.get()
.build();
Response okResponse = createArbitraryOkResponse(okRequest).newBuilder()
.protocol(Protocol.HTTP_1_1)
Expand All @@ -607,7 +607,7 @@ private void assertHeadersContainsMapping(Map<String, List<String>> headers, Str
Request okRequest =
createArbitraryOkRequest().newBuilder()
.url("http://insecure/request")
.method("POST", createRequestBody("RequestBody"))
.post(createRequestBody("RequestBody"))
.build();
Response.Body responseBody = createResponseBody("ResponseBody");
Response okResponse = createArbitraryOkResponse(okRequest).newBuilder()
Expand All @@ -631,7 +631,7 @@ private void assertHeadersContainsMapping(Map<String, List<String>> headers, Str
Request okRequest =
createArbitraryOkRequest().newBuilder()
.url("https://secure/request")
.method("POST", createRequestBody("RequestBody") )
.post(createRequestBody("RequestBody") )
.build();
Response.Body responseBody = createResponseBody("ResponseBody");
Handshake handshake = Handshake.get("SecureCipher", Arrays.<Certificate>asList(SERVER_CERT),
Expand Down Expand Up @@ -754,10 +754,7 @@ private static <T> Set<T> newSet(List<T> elements) {
}

private static Request createArbitraryOkRequest() {
return new Request.Builder()
.url("http://arbitrary/url")
.method("GET", null)
.build();
return new Request.Builder().url("http://arbitrary/url").build();
}

private static Response createArbitraryOkResponse(Request request) {
Expand Down
8 changes: 7 additions & 1 deletion okhttp/src/main/java/com/squareup/okhttp/Call.java
Original file line number Diff line number Diff line change
Expand Up @@ -16,8 +16,11 @@
package com.squareup.okhttp;

import com.squareup.okhttp.internal.NamedRunnable;
import com.squareup.okhttp.internal.Util;
import com.squareup.okhttp.internal.http.HttpEngine;
import com.squareup.okhttp.internal.http.HttpMethod;
import com.squareup.okhttp.internal.http.OkHeaders;
import com.squareup.okhttp.internal.http.RetryableSink;
import java.io.IOException;
import java.net.ProtocolException;
import okio.BufferedSink;
Expand Down Expand Up @@ -170,6 +173,7 @@ private Response getResponse() throws IOException {

// Copy body metadata to the appropriate request headers.
Request.Body body = request.body();
RetryableSink requestBodyOut = null;
if (body != null) {
MediaType contentType = body.contentType();
if (contentType == null) throw new IllegalStateException("contentType == null");
Expand All @@ -187,10 +191,12 @@ private Response getResponse() throws IOException {
}

request = requestBuilder.build();
} else if (HttpMethod.hasRequestBody(request.method())) {
requestBodyOut = Util.emptySink();
}

// Create the initial HTTP engine. Retries and redirects need new engine for each attempt.
engine = new HttpEngine(client, request, false, null, null, null);
engine = new HttpEngine(client, request, false, null, null, requestBodyOut);

while (true) {
if (canceled) return null;
Expand Down
8 changes: 8 additions & 0 deletions okhttp/src/main/java/com/squareup/okhttp/Request.java
Original file line number Diff line number Diff line change
Expand Up @@ -276,10 +276,18 @@ public Builder post(Body body) {
return method("POST", body);
}

public Builder delete() {
return method("DELETE", null);
}

public Builder put(Body body) {
return method("PUT", body);
}

public Builder patch(Body body) {
return method("PATCH", body);
}

public Builder method(String method, Body body) {
if (method == null || method.length() == 0) {
throw new IllegalArgumentException("method == null || method.length() == 0");
Expand Down
Loading

0 comments on commit 520d9fc

Please sign in to comment.