HttpUtils.java revision 4d33cdcbb402a87ffeeaddb58237c70c4608c6f5
1/* 2 * Copyright (C) 2008 Esmertec AG. 3 * Copyright (C) 2008 The Android Open Source Project 4 * 5 * Licensed under the Apache License, Version 2.0 (the "License"); 6 * you may not use this file except in compliance with the License. 7 * You may obtain a copy of the License at 8 * 9 * http://www.apache.org/licenses/LICENSE-2.0 10 * 11 * Unless required by applicable law or agreed to in writing, software 12 * distributed under the License is distributed on an "AS IS" BASIS, 13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 * See the License for the specific language governing permissions and 15 * limitations under the License. 16 */ 17 18package com.android.mms.transaction; 19 20import org.apache.http.HttpEntity; 21import org.apache.http.HttpHost; 22import org.apache.http.HttpRequest; 23import org.apache.http.HttpResponse; 24import org.apache.http.StatusLine; 25import org.apache.http.client.methods.HttpGet; 26import org.apache.http.client.methods.HttpPost; 27import org.apache.http.conn.params.ConnRouteParams; 28import org.apache.http.params.HttpParams; 29import org.apache.http.params.HttpProtocolParams; 30import org.apache.http.params.HttpConnectionParams; 31 32import com.android.mms.MmsConfig; 33import com.android.mms.LogTag; 34 35import android.content.Context; 36import android.net.http.AndroidHttpClient; 37import android.telephony.TelephonyManager; 38import android.text.TextUtils; 39import android.util.Config; 40import android.util.Log; 41 42import java.io.DataInputStream; 43import java.io.IOException; 44import java.net.SocketException; 45import java.net.URI; 46import java.net.URISyntaxException; 47import java.util.Locale; 48 49public class HttpUtils { 50 private static final String TAG = LogTag.TRANSACTION; 51 52 private static final boolean DEBUG = false; 53 private static final boolean LOCAL_LOGV = DEBUG ? Config.LOGD : Config.LOGV; 54 55 public static final int HTTP_POST_METHOD = 1; 56 public static final int HTTP_GET_METHOD = 2; 57 58 // This is the value to use for the "Accept-Language" header. 59 // Once it becomes possible for the user to change the locale 60 // setting, this should no longer be static. We should call 61 // getHttpAcceptLanguage instead. 62 private static final String HDR_VALUE_ACCEPT_LANGUAGE; 63 64 static { 65 HDR_VALUE_ACCEPT_LANGUAGE = getHttpAcceptLanguage(); 66 } 67 68 // Definition for necessary HTTP headers. 69 private static final String HDR_KEY_ACCEPT = "Accept"; 70 private static final String HDR_KEY_ACCEPT_LANGUAGE = "Accept-Language"; 71 72 private static final String HDR_VALUE_ACCEPT = 73 "*/*, application/vnd.wap.mms-message, application/vnd.wap.sic"; 74 75 private HttpUtils() { 76 // To forbidden instantiate this class. 77 } 78 79 /** 80 * A helper method to send or retrieve data through HTTP protocol. 81 * 82 * @param token The token to identify the sending progress. 83 * @param url The URL used in a GET request. Null when the method is 84 * HTTP_POST_METHOD. 85 * @param pdu The data to be POST. Null when the method is HTTP_GET_METHOD. 86 * @param method HTTP_POST_METHOD or HTTP_GET_METHOD. 87 * @return A byte array which contains the response data. 88 * If an HTTP error code is returned, an IOException will be thrown. 89 * @throws IOException if any error occurred on network interface or 90 * an HTTP error code(>=400) returned from the server. 91 */ 92 protected static byte[] httpConnection(Context context, long token, 93 String url, byte[] pdu, int method, boolean isProxySet, 94 String proxyHost, int proxyPort) throws IOException { 95 if (url == null) { 96 throw new IllegalArgumentException("URL must not be null."); 97 } 98 99 if (LOCAL_LOGV) { 100 Log.v(TAG, "httpConnection: params list"); 101 Log.v(TAG, "\ttoken\t\t= " + token); 102 Log.v(TAG, "\turl\t\t= " + url); 103 Log.v(TAG, "\tmethod\t\t= " 104 + ((method == HTTP_POST_METHOD) ? "POST" 105 : ((method == HTTP_GET_METHOD) ? "GET" : "UNKNOWN"))); 106 Log.v(TAG, "\tisProxySet\t= " + isProxySet); 107 Log.v(TAG, "\tproxyHost\t= " + proxyHost); 108 Log.v(TAG, "\tproxyPort\t= " + proxyPort); 109 // TODO Print out binary data more readable. 110 //Log.v(TAG, "\tpdu\t\t= " + Arrays.toString(pdu)); 111 } 112 113 AndroidHttpClient client = null; 114 115 try { 116 // Make sure to use a proxy which supports CONNECT. 117 URI hostUrl = new URI(url); 118 HttpHost target = new HttpHost( 119 hostUrl.getHost(), hostUrl.getPort(), 120 HttpHost.DEFAULT_SCHEME_NAME); 121 122 client = createHttpClient(context); 123 HttpRequest req = null; 124 switch(method) { 125 case HTTP_POST_METHOD: 126 ProgressCallbackEntity entity = new ProgressCallbackEntity( 127 context, token, pdu); 128 // Set request content type. 129 entity.setContentType("application/vnd.wap.mms-message"); 130 131 HttpPost post = new HttpPost(url); 132 post.setEntity(entity); 133 req = post; 134 break; 135 case HTTP_GET_METHOD: 136 req = new HttpGet(url); 137 break; 138 default: 139 Log.e(TAG, "Unknown HTTP method: " + method 140 + ". Must be one of POST[" + HTTP_POST_METHOD 141 + "] or GET[" + HTTP_GET_METHOD + "]."); 142 return null; 143 } 144 145 // Set route parameters for the request. 146 HttpParams params = client.getParams(); 147 if (isProxySet) { 148 ConnRouteParams.setDefaultProxy( 149 params, new HttpHost(proxyHost, proxyPort)); 150 } 151 req.setParams(params); 152 153 // Set necessary HTTP headers for MMS transmission. 154 req.addHeader(HDR_KEY_ACCEPT, HDR_VALUE_ACCEPT); 155 { 156 String xWapProfileTagName = MmsConfig.getUaProfTagName(); 157 String xWapProfileUrl = MmsConfig.getUaProfUrl(); 158 159 if (xWapProfileUrl != null) { 160 if (Log.isLoggable(LogTag.TRANSACTION, Log.VERBOSE)) { 161 Log.d(LogTag.TRANSACTION, 162 "[HttpUtils] httpConn: xWapProfUrl=" + xWapProfileUrl); 163 } 164 req.addHeader(xWapProfileTagName, xWapProfileUrl); 165 } 166 } 167 168 // Extra http parameters. Split by '|' to get a list of value pairs. 169 // Separate each pair by the first occurrence of ':' to obtain a name and 170 // value. Replace the occurrence of the string returned by 171 // MmsConfig.getHttpParamsLine1Key() with the users telephone number inside 172 // the value. 173 String extraHttpParams = MmsConfig.getHttpParams(); 174 175 if (extraHttpParams != null) { 176 String line1Number = ((TelephonyManager)context 177 .getSystemService(Context.TELEPHONY_SERVICE)) 178 .getLine1Number(); 179 String line1Key = MmsConfig.getHttpParamsLine1Key(); 180 String paramList[] = extraHttpParams.split("\\|"); 181 182 for (String paramPair : paramList) { 183 String splitPair[] = paramPair.split(":", 2); 184 185 if (splitPair.length == 2) { 186 String name = splitPair[0].trim(); 187 String value = splitPair[1].trim(); 188 189 if (line1Key != null) { 190 value = value.replace(line1Key, line1Number); 191 } 192 if (!TextUtils.isEmpty(name) && !TextUtils.isEmpty(value)) { 193 req.addHeader(name, value); 194 } 195 } 196 } 197 } 198 req.addHeader(HDR_KEY_ACCEPT_LANGUAGE, HDR_VALUE_ACCEPT_LANGUAGE); 199 200 HttpResponse response = client.execute(target, req); 201 StatusLine status = response.getStatusLine(); 202 if (status.getStatusCode() != 200) { // HTTP 200 is success. 203 throw new IOException("HTTP error: " + status.getReasonPhrase()); 204 } 205 206 HttpEntity entity = response.getEntity(); 207 byte[] body = null; 208 if (entity != null) { 209 try { 210 if (entity.getContentLength() > 0) { 211 body = new byte[(int) entity.getContentLength()]; 212 DataInputStream dis = new DataInputStream(entity.getContent()); 213 try { 214 dis.readFully(body); 215 } finally { 216 try { 217 dis.close(); 218 } catch (IOException e) { 219 Log.e(TAG, "Error closing input stream: " + e.getMessage()); 220 } 221 } 222 } 223 } finally { 224 if (entity != null) { 225 entity.consumeContent(); 226 } 227 } 228 } 229 return body; 230 } catch (URISyntaxException e) { 231 handleHttpConnectionException(e, url); 232 } catch (IllegalStateException e) { 233 handleHttpConnectionException(e, url); 234 } catch (IllegalArgumentException e) { 235 handleHttpConnectionException(e, url); 236 } catch (SocketException e) { 237 handleHttpConnectionException(e, url); 238 } catch (Exception e) { 239 handleHttpConnectionException(e, url); 240 } 241 finally { 242 if (client != null) { 243 client.close(); 244 } 245 } 246 return null; 247 } 248 249 private static void handleHttpConnectionException(Exception exception, String url) 250 throws IOException { 251 // Inner exception should be logged to make life easier. 252 Log.e(TAG, "Url: " + url + "\n" + exception.getMessage()); 253 IOException e = new IOException(exception.getMessage()); 254 e.initCause(exception); 255 throw e; 256 } 257 258 private static AndroidHttpClient createHttpClient(Context context) { 259 String userAgent = MmsConfig.getUserAgent(); 260 AndroidHttpClient client = AndroidHttpClient.newInstance(userAgent, context); 261 HttpParams params = client.getParams(); 262 HttpProtocolParams.setContentCharset(params, "UTF-8"); 263 264 // set the socket timeout 265 int soTimeout = MmsConfig.getHttpSocketTimeout(); 266 267 if (Log.isLoggable(LogTag.TRANSACTION, Log.DEBUG)) { 268 Log.d(TAG, "[HttpUtils] createHttpClient w/ socket timeout " + soTimeout + " ms, " 269 + ", UA=" + userAgent); 270 } 271 HttpConnectionParams.setSoTimeout(params, soTimeout); 272 return client; 273 } 274 275 /** 276 * Return the Accept-Language header. Use the current locale plus 277 * US if we are in a different locale than US. 278 */ 279 private static String getHttpAcceptLanguage() { 280 Locale locale = Locale.getDefault(); 281 StringBuilder builder = new StringBuilder(); 282 283 addLocaleToHttpAcceptLanguage(builder, locale); 284 if (!locale.equals(Locale.US)) { 285 if (builder.length() > 0) { 286 builder.append(", "); 287 } 288 addLocaleToHttpAcceptLanguage(builder, Locale.US); 289 } 290 return builder.toString(); 291 } 292 293 private static void addLocaleToHttpAcceptLanguage( 294 StringBuilder builder, Locale locale) { 295 String language = locale.getLanguage(); 296 297 if (language != null) { 298 builder.append(language); 299 300 String country = locale.getCountry(); 301 302 if (country != null) { 303 builder.append("-"); 304 builder.append(country); 305 } 306 } 307 } 308} 309