Skip to content
This repository has been archived by the owner on Apr 5, 2022. It is now read-only.

Commit

Permalink
Add support for OkHttp3. See OkHttp3ClientHttpRequestFactory.
Browse files Browse the repository at this point in the history
Resolves #29
  • Loading branch information
royclarkson committed Mar 4, 2016
1 parent e0a274b commit 1b923c1
Show file tree
Hide file tree
Showing 12 changed files with 485 additions and 7 deletions.
4 changes: 3 additions & 1 deletion build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,8 @@ configure(allprojects) {
ext.jackson2Version = "2.5.4"
ext.gsonVersion = "2.3.1"
ext.simpleXmlVersion = "2.7.1"
ext.okHttpVersion = "2.4.0"
ext.okHttp3Version = "3.2.0"
ext.okHttpVersion = "2.7.5"
ext.httpclientVersion = "4.3.5.1"
ext.gradleScriptDir = "${rootProject.projectDir}/gradle"

Expand Down Expand Up @@ -158,6 +159,7 @@ project("spring-android-rest-template") {
provided("com.google.android:android:$androidVersion")
compile(project(":spring-android-core"))
optional("org.apache.httpcomponents:httpclient-android:$httpclientVersion")
optional("com.squareup.okhttp3:okhttp-urlconnection:$okHttp3Version")
optional("com.squareup.okhttp:okhttp-urlconnection:$okHttpVersion")
optional("com.fasterxml.jackson.core:jackson-databind:$jackson2Version")
optional("com.google.code.gson:gson:$gsonVersion")
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,124 @@
/*
* Copyright 2002-2016 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

package org.springframework.http.client;

import java.io.IOException;
import java.net.ProtocolException;
import java.net.URI;
import java.net.URL;
import java.util.List;
import java.util.Map;

import okhttp3.MediaType;
import okhttp3.OkHttpClient;
import okhttp3.Request;
import okhttp3.RequestBody;
import okhttp3.Response;

import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpMethod;
import org.springframework.http.HttpStatus;
import org.springframework.util.StringUtils;
import org.springframework.web.client.HttpClientErrorException;

/**
* {@link ClientHttpRequest} implementation that uses OkHttp 3.x to execute requests.
*
* <p>Created via the {@link OkHttp3ClientHttpRequestFactory}.
*
* @author Luciano Leggieri
* @author Arjen Poutsma
* @author Roy Clarkson
* @since 2.0
*/
class OkHttp3ClientHttpRequest extends AbstractBufferingClientHttpRequest
implements ClientHttpRequest {

private static final String PROXY_AUTH_ERROR = "Received HTTP_PROXY_AUTH (407) code while not using proxy";

private static final byte[] NO_BODY = new byte[0];

private final OkHttpClient client;

private final URI uri;

private final HttpMethod method;


public OkHttp3ClientHttpRequest(OkHttpClient client, URI uri, HttpMethod method) {
this.client = client;
this.uri = uri;
this.method = method;
}


@Override
public HttpMethod getMethod() {
return this.method;
}

@Override
public URI getURI() {
return this.uri;
}

@Override
protected ClientHttpResponse executeInternal(HttpHeaders headers, byte[] content) throws IOException {

boolean requiresBody = method == HttpMethod.POST || method == HttpMethod.PUT || method == HttpMethod.PATCH;

RequestBody body;

if (requiresBody && content.length == 0) {
body = RequestBody.create(null, NO_BODY);
} else {
MediaType contentType = getContentType(headers);
body = (content.length > 0 ? RequestBody.create(contentType, content) : null);
}

URL url = this.uri.toURL();
String methodName = this.method.name();
Request.Builder builder = new Request.Builder().url(url).method(methodName, body);

for (Map.Entry<String, List<String>> entry : headers.entrySet()) {
String headerName = entry.getKey();
for (String headerValue : entry.getValue()) {
builder.addHeader(headerName, headerValue);
}
}
Request request = builder.build();
Response response = null;
try {
response = client.newCall(request).execute();
}
catch (ProtocolException e) {
if (PROXY_AUTH_ERROR.equals(e.getMessage())) {
throw new HttpClientErrorException(HttpStatus.PROXY_AUTHENTICATION_REQUIRED,
HttpStatus.PROXY_AUTHENTICATION_REQUIRED.getReasonPhrase());
} else {
throw e;
}
}
return new OkHttp3ClientHttpResponse(response);
}

private MediaType getContentType(HttpHeaders headers) {
String rawContentType = headers.getFirst("Content-Type");
return (StringUtils.hasText(rawContentType) ? MediaType.parse(rawContentType) : null);
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,117 @@
/*
* Copyright 2002-2016 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

package org.springframework.http.client;

import java.net.URI;
import java.util.concurrent.TimeUnit;

import okhttp3.OkHttpClient;

import org.springframework.beans.factory.DisposableBean;
import org.springframework.http.HttpMethod;
import org.springframework.util.Assert;

/**
* {@link ClientHttpRequestFactory} implementation that uses
* <a href="http://square.github.io/okhttp/">OkHttp 3.x</a> to create requests.
*
* @author Stéphane Nicolas
* @author Luciano Leggieri
* @author Arjen Poutsma
* @author Roy Clarkson
* @since 2.0
*/
public class OkHttp3ClientHttpRequestFactory implements ClientHttpRequestFactory, DisposableBean {

private OkHttpClient client;

private final boolean defaultClient;


/**
* Create a factory with a default {@link OkHttpClient} instance.
*/
public OkHttp3ClientHttpRequestFactory() {
this.client = new OkHttpClient();
this.defaultClient = true;
}

/**
* Create a factory with the given {@link OkHttpClient} instance.
* @param client the client to use
*/
public OkHttp3ClientHttpRequestFactory(OkHttpClient client) {
Assert.notNull(client, "'client' must not be null");
this.client = client;
this.defaultClient = false;
}


/**
* Sets the underlying read timeout in milliseconds.
* A value of 0 specifies an infinite timeout.
* @see okhttp3.OkHttpClient.Builder#readTimeout(long, TimeUnit)
*/
public void setReadTimeout(int readTimeout) {
this.client = this.client.newBuilder()
.readTimeout(readTimeout, TimeUnit.MILLISECONDS)
.build();
}

/**
* Sets the underlying write timeout in milliseconds.
* A value of 0 specifies an infinite timeout.
* @see okhttp3.OkHttpClient.Builder#writeTimeout(long, TimeUnit)
*/
public void setWriteTimeout(int writeTimeout) {
this.client = this.client.newBuilder()
.writeTimeout(writeTimeout, TimeUnit.MILLISECONDS)
.build();
}

/**
* Sets the underlying connect timeout in milliseconds.
* A value of 0 specifies an infinite timeout.
* @see okhttp3.OkHttpClient.Builder#connectTimeout(long, TimeUnit)
*/
public void setConnectTimeout(int connectTimeout) {
this.client = this.client.newBuilder()
.connectTimeout(connectTimeout, TimeUnit.MILLISECONDS)
.build();
}


@Override
public ClientHttpRequest createRequest(URI uri, HttpMethod httpMethod) {
return createRequestInternal(uri, httpMethod);
}

private OkHttp3ClientHttpRequest createRequestInternal(URI uri, HttpMethod httpMethod) {
return new OkHttp3ClientHttpRequest(this.client, uri, httpMethod);
}

@Override
public void destroy() throws Exception {
if (this.defaultClient) {
// Clean up the client if we created it in the constructor
if (this.client.cache() != null) {
this.client.cache().close();
}
this.client.dispatcher().executorService().shutdown();
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,82 @@
/*
* Copyright 2002-2016 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

package org.springframework.http.client;

import java.io.IOException;
import java.io.InputStream;

import okhttp3.Response;

import org.springframework.http.HttpHeaders;
import org.springframework.util.Assert;

/**
* {@link ClientHttpResponse} implementation that uses
* OkHttp 3.x.
*
* @author Luciano Leggieri
* @author Arjen Poutsma
* @author Roy Clarkson
* @since 2.0
*/
class OkHttp3ClientHttpResponse extends AbstractClientHttpResponse {

private final Response response;

private HttpHeaders headers;


public OkHttp3ClientHttpResponse(Response response) {
Assert.notNull(response, "'response' must not be null");
this.response = response;
}


@Override
public int getRawStatusCode() {
return this.response.code();
}

@Override
public String getStatusText() {
return this.response.message();
}

@Override
public InputStream getBodyInternal() throws IOException {
return this.response.body().byteStream();
}

@Override
public HttpHeaders getHeaders() {
if (this.headers == null) {
HttpHeaders headers = new HttpHeaders();
for (String headerName : this.response.headers().names()) {
for (String headerValue : this.response.headers(headerName)) {
headers.add(headerName, headerValue);
}
}
this.headers = headers;
}
return this.headers;
}

@Override
public void closeInternal() {
this.response.body().close();
}
}
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2015 the original author or authors.
* Copyright 2002-2016 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
Expand Down Expand Up @@ -45,6 +45,7 @@
* @author Roy Clarkson
* @since 2.0
*/
@Deprecated
class OkHttpClientHttpRequest extends AbstractBufferingClientHttpRequest
implements ClientHttpRequest {

Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2015 the original author or authors.
* Copyright 2002-2016 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
Expand Down Expand Up @@ -27,14 +27,15 @@

/**
* {@link ClientHttpRequestFactory} implementation that uses
* <a href="http://square.github.io/okhttp/">OkHttp</a> to create requests.
* <a href="http://square.github.io/okhttp/">OkHttp 2.x</a> to create requests.
*
* @author Stéphane Nicolas
* @author Luciano Leggieri
* @author Arjen Poutsma
* @author Roy Clarkson
* @since 2.0
*/
@Deprecated
public class OkHttpClientHttpRequestFactory implements ClientHttpRequestFactory, DisposableBean {

private final OkHttpClient client;
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2015 the original author or authors.
* Copyright 2002-2016 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
Expand Down Expand Up @@ -33,6 +33,7 @@
* @author Roy Clarkson
* @since 2.0
*/
@Deprecated
class OkHttpClientHttpResponse extends AbstractClientHttpResponse {

private final Response response;
Expand Down
Loading

0 comments on commit 1b923c1

Please sign in to comment.