1b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien/* 2b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien * Copyright 2008 Netflix, Inc. 3b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien * 4b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien * Licensed under the Apache License, Version 2.0 (the "License"); 5b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien * you may not use this file except in compliance with the License. 6b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien * You may obtain a copy of the License at 7b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien * 8b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien * http://www.apache.org/licenses/LICENSE-2.0 9b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien * 10b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien * Unless required by applicable law or agreed to in writing, software 11b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien * distributed under the License is distributed on an "AS IS" BASIS, 12b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien * See the License for the specific language governing permissions and 14b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien * limitations under the License. 15b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien */ 16b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien 17b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembienpackage net.oauth.client; 18b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien 19b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembienimport java.io.IOException; 20b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembienimport java.io.InputStream; 21b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembienimport java.io.OutputStream; 22b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembienimport java.net.HttpURLConnection; 23b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembienimport java.net.URL; 24b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembienimport java.net.URLConnection; 25b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembienimport java.util.Collection; 26b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembienimport java.util.List; 27b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembienimport java.util.Map; 28b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembienimport net.oauth.http.HttpClient; 29b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembienimport net.oauth.http.HttpMessage; 30b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembienimport net.oauth.http.HttpResponseMessage; 31b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien 32b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien/** 33b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien * An HttpClient based on HttpURLConnection. 34b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien * <p> 35b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien * HttpClient3 or HttpClient4 perform better than this class, as a rule; since 36b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien * they do things like connection pooling. They also support reading the body 37b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien * of an HTTP response whose status code isn't 200 (OK), which can enable your 38b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien * application to handle problems better. 39b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien * 40b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien * @author John Kristian 41b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien * @hide 42b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien */ 43b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembienpublic class URLConnectionClient implements HttpClient { 44b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien 45b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien /** Send a message to the service provider and get the response. */ 46b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien public HttpResponseMessage execute(HttpMessage request) throws IOException { 47b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien final String httpMethod = request.method; 48b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien final Collection<Map.Entry<String, String>> addHeaders = request.headers; 49b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien final URL url = request.url; 50b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien final URLConnection connection = url.openConnection(); 51b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien connection.setDoInput(true); 52b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien if (connection instanceof HttpURLConnection) { 53b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien HttpURLConnection http = (HttpURLConnection) connection; 54b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien http.setRequestMethod(httpMethod); 55b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien http.setInstanceFollowRedirects(false); 56b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien } 57b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien StringBuilder headers = new StringBuilder(httpMethod); 58b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien { 59b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien headers.append(" ").append(url.getPath()); 60b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien String query = url.getQuery(); 61b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien if (query != null && query.length() > 0) { 62b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien headers.append("?").append(query); 63b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien } 64b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien headers.append(EOL); 65b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien for (Map.Entry<String, List<String>> header : connection 66b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien .getRequestProperties().entrySet()) { 67b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien String key = header.getKey(); 68b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien for (String value : header.getValue()) { 69b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien headers.append(key).append(": ").append(value).append(EOL); 70b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien } 71b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien } 72b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien } 73b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien String contentLength = null; 74b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien for (Map.Entry<String, String> header : addHeaders) { 75b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien String key = header.getKey(); 76b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien if (HttpMessage.CONTENT_LENGTH.equalsIgnoreCase(key) 77b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien && connection instanceof HttpURLConnection) { 78b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien contentLength = header.getValue(); 79b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien } else { 80b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien connection.setRequestProperty(key, header.getValue()); 81b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien } 82b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien headers.append(key).append(": ").append(header.getValue()).append(EOL); 83b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien } 84b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien byte[] excerpt = null; 85b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien final InputStream body = request.getBody(); 86b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien if (body != null) { 87b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien try { 88b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien if (contentLength != null) { 89b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien ((HttpURLConnection) connection) 90b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien .setFixedLengthStreamingMode(Integer.parseInt(contentLength)); 91b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien } 92b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien connection.setDoOutput(true); 93b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien OutputStream output = connection.getOutputStream(); 94b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien try { 95b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien final ExcerptInputStream ex = new ExcerptInputStream(body); 96b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien byte[] b = new byte[1024]; 97b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien for (int n; 0 < (n = ex.read(b));) { 98b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien output.write(b, 0, n); 99b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien } 100b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien excerpt = ex.getExcerpt(); 101b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien } finally { 102b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien output.close(); 103b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien } 104b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien } finally { 105b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien body.close(); 106b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien } 107b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien } 108b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien return new URLConnectionResponse(request, headers.toString(), excerpt, connection); 109b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien } 110b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien 111b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien private static final String EOL = HttpResponseMessage.EOL; 112b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien 113b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien} 114