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 */ 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 */ 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 */ 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 97 public String post(PostRequest request) throws IOException, HttpException { 98 return post(request.getUrl(), request.getHeaders(), request.getContent()); 99 } 100 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 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 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 169 public void setConnectTimeout(int timeoutMillis) { 170 mConnectTimeout = timeoutMillis; 171 } 172 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 183 public String rewrite(String url) { 184 return url; 185 } 186 } 187 } 188