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

Commit

Permalink
Update OkHttpClientHttpRequestFactory to support interceptors
Browse files Browse the repository at this point in the history
Resolves #24
  • Loading branch information
royclarkson committed Jun 24, 2015
1 parent 959b72a commit 51721c7
Show file tree
Hide file tree
Showing 5 changed files with 287 additions and 22 deletions.
2 changes: 1 addition & 1 deletion build.gradle
Expand Up @@ -19,7 +19,7 @@ configure(allprojects) {
ext.jackson2Version = "2.3.4"
ext.gsonVersion = "2.3.1"
ext.simpleXmlVersion = "2.7.1"
ext.okHttpVersion = "2.1.0"
ext.okHttpVersion = "2.4.0"
ext.httpclientVersion = "4.3.5"
ext.gradleScriptDir = "${rootProject.projectDir}/gradle"

Expand Down
@@ -0,0 +1,114 @@
/*
* Copyright 2002-2015 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 com.squareup.okhttp.MediaType;
import com.squareup.okhttp.OkHttpClient;
import com.squareup.okhttp.Request;
import com.squareup.okhttp.RequestBody;
import com.squareup.okhttp.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 to execute requests.
*
* <p>Created via the {@link OkHttpClientHttpRequestFactory}.
*
* @author Luciano Leggieri
* @author Arjen Poutsma
* @author Roy Clarkson
* @since 2.0
*/
class OkHttpClientHttpRequest extends AbstractBufferingClientHttpRequest
implements ClientHttpRequest {

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

private final OkHttpClient client;

private final URI uri;

private final HttpMethod method;


public OkHttpClientHttpRequest(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 {

MediaType contentType = getContentType(headers);
RequestBody 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 OkHttpClientHttpResponse(response);
}

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

}
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2014 the original author or authors.
* Copyright 2002-2015 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 All @@ -16,38 +16,96 @@

package org.springframework.http.client;

import java.io.IOException;
import java.net.HttpURLConnection;
import java.net.Proxy;
import java.net.URL;
import java.net.URLConnection;
import java.net.URI;
import java.util.concurrent.TimeUnit;

import com.squareup.okhttp.OkHttpClient;
import com.squareup.okhttp.OkUrlFactory;

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

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

private final OkHttpClient client;

private final boolean defaultClient;


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

/**
* Create a factory with the given {@link OkHttpClient} instance.
* @param client the client to use
*/
public OkHttpClientHttpRequestFactory(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 OkHttpClient#setReadTimeout(long, TimeUnit)
*/
public void setReadTimeout(int readTimeout) {
this.client.setReadTimeout(readTimeout, TimeUnit.MILLISECONDS);
}

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

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

private OkHttpClient okHttpClient = new OkHttpClient();

@Override
protected HttpURLConnection openConnection(URL url, Proxy proxy) throws IOException {
if (proxy != null) {
this.okHttpClient.setProxy(proxy);
}
OkUrlFactory okUrlFactory = new OkUrlFactory(this.okHttpClient);
URLConnection urlConnection = okUrlFactory.open(url);
Assert.isInstanceOf(HttpURLConnection.class, urlConnection);
return (HttpURLConnection) urlConnection;
public ClientHttpRequest createRequest(URI uri, HttpMethod httpMethod) {
return createRequestInternal(uri, httpMethod);
}

private OkHttpClientHttpRequest createRequestInternal(URI uri, HttpMethod httpMethod) {
return new OkHttpClientHttpRequest(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.getCache() != null) {
this.client.getCache().close();
}
this.client.getDispatcher().getExecutorService().shutdown();
}
}
}
@@ -0,0 +1,87 @@
/*
* Copyright 2002-2015 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 com.squareup.okhttp.Response;

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

/**
* {@link org.springframework.http.client.ClientHttpResponse} implementation that uses
* OkHttp.
*
* @author Luciano Leggieri
* @author Arjen Poutsma
* @author Roy Clarkson
* @since 2.0
*/
class OkHttpClientHttpResponse extends AbstractClientHttpResponse {

private final Response response;

private HttpHeaders headers;


public OkHttpClientHttpResponse(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() {
try {
this.response.body().close();
}
catch (IOException ex) {
// Ignore
}
}
}
Expand Up @@ -63,6 +63,12 @@ protected void runTest() throws Throwable {
}
}

@Override
public void testHttpMethods() throws Exception {
super.testHttpMethods();
assertHttpMethod("patch", HttpMethod.PATCH);
}

@MediumTest
@Override
public void testGetAcceptEncodingNone() throws Exception {
Expand Down

0 comments on commit 51721c7

Please sign in to comment.