• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 
18 package com.android.mms.transaction;
19 
20 import org.apache.http.HttpEntity;
21 import org.apache.http.HttpHost;
22 import org.apache.http.HttpRequest;
23 import org.apache.http.HttpResponse;
24 import org.apache.http.StatusLine;
25 import org.apache.http.client.methods.HttpGet;
26 import org.apache.http.client.methods.HttpPost;
27 import org.apache.http.conn.params.ConnRouteParams;
28 import org.apache.http.params.HttpParams;
29 import org.apache.http.params.HttpProtocolParams;
30 import org.apache.http.params.HttpConnectionParams;
31 
32 import com.android.mms.MmsConfig;
33 import com.android.mms.LogTag;
34 
35 import android.content.Context;
36 import android.net.http.AndroidHttpClient;
37 import android.telephony.TelephonyManager;
38 import android.text.TextUtils;
39 import android.util.Config;
40 import android.util.Log;
41 
42 import java.io.DataInputStream;
43 import java.io.IOException;
44 import java.net.SocketException;
45 import java.net.URI;
46 import java.net.URISyntaxException;
47 import java.util.Locale;
48 
49 public 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 
HttpUtils()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      */
httpConnection(Context context, long token, String url, byte[] pdu, int method, boolean isProxySet, String proxyHost, int proxyPort)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();
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                     req.addHeader(xWapProfileTagName, xWapProfileUrl);
161                 }
162             }
163 
164             // Extra http parameters. Split by '|' to get a list of value pairs.
165             // Separate each pair by the first occurrence of ':' to obtain a name and
166             // value. Replace the occurrence of the string returned by
167             // MmsConfig.getHttpParamsLine1Key() with the users telephone number inside
168             // the value.
169             String extraHttpParams = MmsConfig.getHttpParams();
170 
171             if (extraHttpParams != null) {
172                 String line1Number = ((TelephonyManager)context
173                         .getSystemService(Context.TELEPHONY_SERVICE))
174                         .getLine1Number();
175                 String line1Key = MmsConfig.getHttpParamsLine1Key();
176                 String paramList[] = extraHttpParams.split("\\|");
177 
178                 for (String paramPair : paramList) {
179                     String splitPair[] = paramPair.split(":", 2);
180 
181                     if (splitPair.length == 2) {
182                         String name = splitPair[0].trim();
183                         String value = splitPair[1].trim();
184 
185                         if (line1Key != null) {
186                             value = value.replace(line1Key, line1Number);
187                         }
188                         if (!TextUtils.isEmpty(name) && !TextUtils.isEmpty(value)) {
189                             req.addHeader(name, value);
190                         }
191                     }
192                 }
193             }
194             req.addHeader(HDR_KEY_ACCEPT_LANGUAGE, HDR_VALUE_ACCEPT_LANGUAGE);
195 
196             HttpResponse response = client.execute(target, req);
197             StatusLine status = response.getStatusLine();
198             if (status.getStatusCode() != 200) { // HTTP 200 is success.
199                 throw new IOException("HTTP error: " + status.getReasonPhrase());
200             }
201 
202             HttpEntity entity = response.getEntity();
203             byte[] body = null;
204             if (entity != null) {
205                 try {
206                     if (entity.getContentLength() > 0) {
207                         body = new byte[(int) entity.getContentLength()];
208                         DataInputStream dis = new DataInputStream(entity.getContent());
209                         try {
210                             dis.readFully(body);
211                         } finally {
212                             try {
213                                 dis.close();
214                             } catch (IOException e) {
215                                 Log.e(TAG, "Error closing input stream: " + e.getMessage());
216                             }
217                         }
218                     }
219                 } finally {
220                     if (entity != null) {
221                         entity.consumeContent();
222                     }
223                 }
224             }
225             return body;
226         } catch (URISyntaxException e) {
227             handleHttpConnectionException(e);
228         } catch (IllegalStateException e) {
229             handleHttpConnectionException(e);
230         } catch (IllegalArgumentException e) {
231             handleHttpConnectionException(e);
232         } catch (SocketException e) {
233             handleHttpConnectionException(e);
234         } catch (Exception e) {
235             handleHttpConnectionException(e);
236         }
237         finally {
238             if (client != null) {
239                 client.close();
240             }
241         }
242         return null;
243     }
244 
handleHttpConnectionException(Exception exception)245     private static void handleHttpConnectionException(Exception exception)
246             throws IOException {
247         // Inner exception should be logged to make life easier.
248         Log.e(TAG, exception.getMessage());
249         throw new IOException(exception.getMessage());
250     }
251 
createHttpClient()252     private static AndroidHttpClient createHttpClient() {
253         String userAgent = MmsConfig.getUserAgent();
254         AndroidHttpClient client = AndroidHttpClient.newInstance(userAgent);
255         HttpParams params = client.getParams();
256         HttpProtocolParams.setContentCharset(params, "UTF-8");
257 
258         // set the socket timeout
259         int soTimeout = MmsConfig.getHttpSocketTimeout();
260 
261         if (Log.isLoggable(LogTag.TRANSACTION, Log.DEBUG)) {
262             Log.d(TAG, "[HttpUtils] createHttpClient w/ socket timeout " + soTimeout + " ms, "
263                     + ", UA=" + userAgent);
264         }
265         HttpConnectionParams.setSoTimeout(params, soTimeout);
266         return client;
267     }
268 
269     /**
270      * Return the Accept-Language header.  Use the current locale plus
271      * US if we are in a different locale than US.
272      */
getHttpAcceptLanguage()273     private static String getHttpAcceptLanguage() {
274         Locale locale = Locale.getDefault();
275         StringBuilder builder = new StringBuilder();
276 
277         addLocaleToHttpAcceptLanguage(builder, locale);
278         if (!locale.equals(Locale.US)) {
279             if (builder.length() > 0) {
280                 builder.append(", ");
281             }
282             addLocaleToHttpAcceptLanguage(builder, Locale.US);
283         }
284         return builder.toString();
285     }
286 
addLocaleToHttpAcceptLanguage( StringBuilder builder, Locale locale)287     private static void addLocaleToHttpAcceptLanguage(
288             StringBuilder builder, Locale locale) {
289         String language = locale.getLanguage();
290 
291         if (language != null) {
292             builder.append(language);
293 
294             String country = locale.getCountry();
295 
296             if (country != null) {
297                 builder.append("-");
298                 builder.append(country);
299             }
300         }
301     }
302 }
303