1 /*
2  * Copyright (C) 2010 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 package com.android.quicksearchbox.util;
18 
19 import android.os.Build;
20 import android.util.Log;
21 
22 import java.io.BufferedReader;
23 import java.io.IOException;
24 import java.io.InputStreamReader;
25 import java.io.OutputStreamWriter;
26 import java.net.HttpURLConnection;
27 import java.net.URL;
28 import java.util.HashMap;
29 import java.util.Map;
30 
31 /**
32  * Simple HTTP client API.
33  */
34 public class JavaNetHttpHelper implements HttpHelper {
35     private static final String TAG = "QSB.JavaNetHttpHelper";
36     private static final boolean DBG = false;
37 
38     private static final int BUFFER_SIZE = 1024 * 4;
39     private static final String USER_AGENT_HEADER = "User-Agent";
40     private static final String DEFAULT_CHARSET = "UTF-8";
41 
42     private int mConnectTimeout;
43     private int mReadTimeout;
44     private final String mUserAgent;
45     private final HttpHelper.UrlRewriter mRewriter;
46 
47     /**
48      * Creates a new HTTP helper.
49      *
50      * @param rewriter URI rewriter
51      * @param userAgent User agent string, e.g. "MyApp/1.0".
52      */
JavaNetHttpHelper(UrlRewriter rewriter, String userAgent)53     public JavaNetHttpHelper(UrlRewriter rewriter, String userAgent) {
54         mUserAgent = userAgent + " (" + Build.DEVICE + " " + Build.ID + ")";
55         mRewriter = rewriter;
56     }
57 
58     /**
59      * Executes a GET request and returns the response content.
60      *
61      * @param request Request.
62      * @return The response content. This is the empty string if the response
63      *         contained no content.
64      * @throws IOException If an IO error occurs.
65      * @throws HttpException If the response has a status code other than 200.
66      */
get(GetRequest request)67     public String get(GetRequest request) throws IOException, HttpException {
68         return get(request.getUrl(), request.getHeaders());
69     }
70 
71     /**
72      * Executes a GET request and returns the response content.
73      *
74      * @param url Request URI.
75      * @param requestHeaders Request headers.
76      * @return The response content. This is the empty string if the response
77      *         contained no content.
78      * @throws IOException If an IO error occurs.
79      * @throws HttpException If the response has a status code other than 200.
80      */
get(String url, Map<String,String> requestHeaders)81     public String get(String url, Map<String,String> requestHeaders)
82             throws IOException, HttpException {
83         HttpURLConnection c = null;
84         try {
85             c = createConnection(url, requestHeaders);
86             c.setRequestMethod("GET");
87             c.connect();
88             return getResponseFrom(c);
89         } finally {
90             if (c != null) {
91                 c.disconnect();
92             }
93         }
94     }
95 
96     @Override
post(PostRequest request)97     public String post(PostRequest request) throws IOException, HttpException {
98         return post(request.getUrl(), request.getHeaders(), request.getContent());
99     }
100 
post(String url, Map<String,String> requestHeaders, String content)101     public String post(String url, Map<String,String> requestHeaders, String content)
102             throws IOException, HttpException {
103         HttpURLConnection c = null;
104         try {
105             if (requestHeaders == null) {
106                 requestHeaders = new HashMap<String, String>();
107             }
108             requestHeaders.put("Content-Length",
109                     Integer.toString(content == null ? 0 : content.length()));
110             c = createConnection(url, requestHeaders);
111             c.setDoOutput(content != null);
112             c.setRequestMethod("POST");
113             c.connect();
114             if (content != null) {
115                 OutputStreamWriter writer = new OutputStreamWriter(c.getOutputStream());
116                 writer.write(content);
117                 writer.close();
118             }
119             return getResponseFrom(c);
120         } finally {
121             if (c != null) {
122                 c.disconnect();
123             }
124         }
125     }
126 
createConnection(String url, Map<String, String> headers)127     private HttpURLConnection createConnection(String url, Map<String, String> headers)
128             throws IOException, HttpException {
129         URL u = new URL(mRewriter.rewrite(url));
130         if (DBG) Log.d(TAG, "URL=" + url + " rewritten='" + u + "'");
131         HttpURLConnection c = (HttpURLConnection) u.openConnection();
132         if (headers != null) {
133             for (Map.Entry<String,String> e : headers.entrySet()) {
134                 String name = e.getKey();
135                 String value = e.getValue();
136                 if (DBG) Log.d(TAG, "  " + name + ": " + value);
137                 c.addRequestProperty(name, value);
138             }
139         }
140         c.addRequestProperty(USER_AGENT_HEADER, mUserAgent);
141         if (mConnectTimeout != 0) {
142             c.setConnectTimeout(mConnectTimeout);
143         }
144         if (mReadTimeout != 0) {
145             c.setReadTimeout(mReadTimeout);
146         }
147         return c;
148     }
149 
getResponseFrom(HttpURLConnection c)150     private String getResponseFrom(HttpURLConnection c) throws IOException, HttpException {
151         if (c.getResponseCode() != HttpURLConnection.HTTP_OK) {
152             throw new HttpException(c.getResponseCode(), c.getResponseMessage());
153         }
154         if (DBG) {
155             Log.d(TAG, "Content-Type: " + c.getContentType() + " (assuming " +
156                     DEFAULT_CHARSET + ")");
157         }
158         BufferedReader reader = new BufferedReader(
159                 new InputStreamReader(c.getInputStream(), DEFAULT_CHARSET));
160         StringBuilder string = new StringBuilder();
161         char[] chars = new char[BUFFER_SIZE];
162         int bytes;
163         while ((bytes = reader.read(chars)) != -1) {
164             string.append(chars, 0, bytes);
165         }
166         return string.toString();
167     }
168 
setConnectTimeout(int timeoutMillis)169     public void setConnectTimeout(int timeoutMillis) {
170         mConnectTimeout = timeoutMillis;
171     }
172 
setReadTimeout(int timeoutMillis)173     public void setReadTimeout(int timeoutMillis) {
174         mReadTimeout = timeoutMillis;
175     }
176 
177     /**
178      * A Url rewriter that does nothing, i.e., returns the
179      * url that is passed to it.
180      */
181     public static class PassThroughRewriter implements UrlRewriter {
182         @Override
rewrite(String url)183         public String rewrite(String url) {
184             return url;
185         }
186     }
187 }
188