001package io.freefair.spring.okhttp.client; 002 003import okhttp3.*; 004import okio.Buffer; 005import okio.ByteString; 006import org.springframework.http.HttpHeaders; 007import org.springframework.http.HttpMethod; 008import org.springframework.http.StreamingHttpOutputMessage; 009import org.springframework.http.client.AbstractClientHttpRequest; 010import org.springframework.http.client.ClientHttpRequest; 011import org.springframework.http.client.ClientHttpResponse; 012import org.springframework.lang.Nullable; 013import org.springframework.util.Assert; 014import org.springframework.util.StringUtils; 015import java.io.IOException; 016import java.io.OutputStream; 017import java.net.MalformedURLException; 018import java.net.URI; 019 020/** 021 * OkHttp based {@link ClientHttpRequest} implementation. 022 * 023 * @author Lars Grefer 024 * @see OkHttpClientRequestFactory 025 */ 026public class OkHttpClientRequest extends AbstractClientHttpRequest implements StreamingHttpOutputMessage { 027 private final OkHttpClient okHttpClient; 028 private final URI uri; 029 private final HttpMethod method; 030 @Nullable 031 private Body streamingBody; 032 @Nullable 033 private Buffer bufferBody; 034 035 @Override 036 public HttpMethod getMethod() { 037 return method; 038 } 039 040 @Override 041 public URI getURI() { 042 return uri; 043 } 044 045 @Override 046 public void setBody(Body body) { 047 Assert.notNull(body, "body must not be null"); 048 assertNotExecuted(); 049 Assert.state(bufferBody == null, "getBody has already been used."); 050 this.streamingBody = body; 051 } 052 053 @Override 054 protected OutputStream getBodyInternal(HttpHeaders headers) { 055 Assert.state(this.streamingBody == null, "setBody has already been used."); 056 if (bufferBody == null) { 057 bufferBody = new Buffer(); 058 } 059 return bufferBody.outputStream(); 060 } 061 062 @Override 063 protected ClientHttpResponse executeInternal(HttpHeaders headers) throws IOException { 064 Request okHttpRequest = buildRequest(headers); 065 Response okHttpResponse = this.okHttpClient.newCall(okHttpRequest).execute(); 066 return new OkHttpClientResponse(okHttpResponse); 067 } 068 069 private Request buildRequest(HttpHeaders headers) throws MalformedURLException { 070 Request.Builder builder = new Request.Builder(); 071 builder.url(uri.toURL()); 072 MediaType contentType = null; 073 String contentTypeHeader = headers.getFirst(HttpHeaders.CONTENT_TYPE); 074 if (StringUtils.hasText(contentTypeHeader)) { 075 contentType = MediaType.parse(contentTypeHeader); 076 } 077 RequestBody body = null; 078 if (bufferBody != null) { 079 ByteString bodyData = bufferBody.readByteString(); 080 if (headers.getContentLength() < 0) { 081 headers.setContentLength(bodyData.size()); 082 } 083 body = RequestBody.create(bodyData, contentType); 084 } else if (streamingBody != null) { 085 body = new StreamingBodyRequestBody(streamingBody, contentType, headers.getContentLength()); 086 } else if (okhttp3.internal.http.HttpMethod.requiresRequestBody(method.name())) { 087 body = RequestBody.create(new byte[0], contentType); 088 } 089 builder.method(getMethod().name(), body); 090 headers.forEach((name, values) -> { 091 for (String value : values) { 092 builder.addHeader(name, value); 093 } 094 }); 095 return builder.build(); 096 } 097 098 public OkHttpClientRequest(final OkHttpClient okHttpClient, final URI uri, final HttpMethod method) { 099 this.okHttpClient = okHttpClient; 100 this.uri = uri; 101 this.method = method; 102 } 103}