diff --git a/android/src/com/google/zxing/client/android/AndroidHttpClient.java b/android/src/com/google/zxing/client/android/AndroidHttpClient.java deleted file mode 100644 index f8e93c786..000000000 --- a/android/src/com/google/zxing/client/android/AndroidHttpClient.java +++ /dev/null @@ -1,170 +0,0 @@ -/* - * Copyright (C) 2008 ZXing authors - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.google.zxing.client.android; - -import org.apache.http.HttpHost; -import org.apache.http.HttpRequest; -import org.apache.http.HttpRequestInterceptor; -import org.apache.http.HttpResponse; -import org.apache.http.client.HttpClient; -import org.apache.http.client.ResponseHandler; -import org.apache.http.client.methods.HttpUriRequest; -import org.apache.http.client.params.HttpClientParams; -import org.apache.http.client.protocol.ClientContext; -import org.apache.http.conn.ClientConnectionManager; -import org.apache.http.conn.scheme.PlainSocketFactory; -import org.apache.http.conn.scheme.Scheme; -import org.apache.http.conn.scheme.SchemeRegistry; -import org.apache.http.conn.ssl.SSLSocketFactory; -import org.apache.http.impl.client.DefaultHttpClient; -import org.apache.http.impl.conn.tsccm.ThreadSafeClientConnManager; -import org.apache.http.params.BasicHttpParams; -import org.apache.http.params.HttpConnectionParams; -import org.apache.http.params.HttpParams; -import org.apache.http.params.HttpProtocolParams; -import org.apache.http.protocol.BasicHttpContext; -import org.apache.http.protocol.HttpContext; - -import java.io.IOException; - -/** - *

Subclass of the Apache {@link DefaultHttpClient} that is configured with - * reasonable default settings and registered schemes for Android, and - * also lets the user add {@link HttpRequestInterceptor} classes. - * Don't create this directly, use the {@link #newInstance} factory method.

- *

- *

This client processes cookies but does not retain them by default. - * To retain cookies, simply add a cookie store to the HttpContext: - *

context.setAttribute(ClientContext.COOKIE_STORE, cookieStore);
- *

- */ -public final class AndroidHttpClient implements HttpClient { - - /** - * Create a new HttpClient with reasonable defaults (which you can update). - * - * @param userAgent to report in your HTTP requests. - * @return AndroidHttpClient for you to use for all your requests. - */ - public static AndroidHttpClient newInstance(String userAgent) { - HttpParams params = new BasicHttpParams(); - - // Turn off stale checking. Our connections break all the time anyway, - // and it's not worth it to pay the penalty of checking every time. - HttpConnectionParams.setStaleCheckingEnabled(params, false); - - // Default connection and socket timeout of 20 seconds. Tweak to taste. - HttpConnectionParams.setConnectionTimeout(params, 20 * 1000); - HttpConnectionParams.setSoTimeout(params, 20 * 1000); - HttpConnectionParams.setSocketBufferSize(params, 8192); - - // Don't handle redirects -- return them to the caller. Our code - // often wants to re-POST after a redirect, which we must do ourselves. - HttpClientParams.setRedirecting(params, false); - - // Set the specified user agent and register standard protocols. - if (userAgent != null) { - HttpProtocolParams.setUserAgent(params, userAgent); - } - SchemeRegistry schemeRegistry = new SchemeRegistry(); - schemeRegistry.register(new Scheme("http", PlainSocketFactory.getSocketFactory(), 80)); - schemeRegistry.register(new Scheme("https", SSLSocketFactory.getSocketFactory(), 443)); - ClientConnectionManager manager = new ThreadSafeClientConnManager(params, schemeRegistry); - - // We use a factory method to modify superclass initialization - // parameters without the funny call-a-static-method dance. - return new AndroidHttpClient(manager, params); - } - - private final HttpClient delegate; - - - private AndroidHttpClient(ClientConnectionManager ccm, HttpParams params) { - this.delegate = new DelegateHttpClient(ccm, params); - } - - /** - * Release resources associated with this client. You must call this, - * or significant resources (sockets and memory) may be leaked. - */ - public void close() { - getConnectionManager().shutdown(); - } - - public HttpParams getParams() { - return delegate.getParams(); - } - - public ClientConnectionManager getConnectionManager() { - return delegate.getConnectionManager(); - } - - public HttpResponse execute(HttpUriRequest request) throws IOException { - return delegate.execute(request); - } - - public HttpResponse execute(HttpUriRequest request, HttpContext context) throws IOException { - return delegate.execute(request, context); - } - - public HttpResponse execute(HttpHost target, HttpRequest request) throws IOException { - return delegate.execute(target, request); - } - - public HttpResponse execute(HttpHost target, HttpRequest request, HttpContext context) throws IOException { - return delegate.execute(target, request, context); - } - - public T execute(HttpUriRequest request, ResponseHandler responseHandler) throws IOException { - return delegate.execute(request, responseHandler); - } - - public T execute(HttpUriRequest request, ResponseHandler responseHandler, HttpContext context) - throws IOException { - return delegate.execute(request, responseHandler, context); - } - - public T execute(HttpHost target, HttpRequest request, ResponseHandler responseHandler) - throws IOException { - return delegate.execute(target, request, responseHandler); - } - - public T execute(HttpHost target, HttpRequest request, - ResponseHandler responseHandler, - HttpContext context) throws IOException { - return delegate.execute(target, request, responseHandler, context); - } - - private static class DelegateHttpClient extends DefaultHttpClient { - - private DelegateHttpClient(ClientConnectionManager ccm, HttpParams params) { - super(ccm, params); - } - - @Override - protected HttpContext createHttpContext() { - // Same as DefaultHttpClient.createHttpContext() minus the - // cookie store. - HttpContext context = new BasicHttpContext(); - context.setAttribute(ClientContext.AUTHSCHEME_REGISTRY, getAuthSchemes()); - context.setAttribute(ClientContext.COOKIESPEC_REGISTRY, getCookieSpecs()); - context.setAttribute(ClientContext.CREDS_PROVIDER, getCredentialsProvider()); - return context; - } - } - -} diff --git a/android/src/com/google/zxing/client/android/HttpHelper.java b/android/src/com/google/zxing/client/android/HttpHelper.java new file mode 100644 index 000000000..ee30f7644 --- /dev/null +++ b/android/src/com/google/zxing/client/android/HttpHelper.java @@ -0,0 +1,168 @@ +/* + * Copyright 2011 ZXing authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.google.zxing.client.android; + +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.io.InputStream; +import java.io.UnsupportedEncodingException; +import java.net.HttpURLConnection; +import java.net.URI; +import java.net.URISyntaxException; +import java.net.URL; +import java.util.Arrays; +import java.util.Collection; +import java.util.HashSet; + +/** + * Utility methods for retrieving content over HTTP using the more-supported {@code java.net} classes + * in Android. + */ +public final class HttpHelper { + + private static final Collection REDIRECTOR_DOMAINS = new HashSet(Arrays.asList( + "amzn.to", "bit.ly", "bitly.com", "fb.me", "goo.gl", "is.gd", "j.mp", "lnkd.in", "ow.ly", + "SCN.BY", "su.pr", "t.co", "tinyurl.com", "tr.im" + )); + + private HttpHelper() { + } + + public enum ContentType { + /** HTML-like content type, including HTML, XHTML, etc. */ + HTML, + /** JSON content */ + JSON, + /** Plain text content */ + TEXT, + } + + /** + * @param uri URI to retrieve + * @param type expected text-like MIME type of that content + * @return content as a {@code String} + * @throws IOException if the content can't be retrieved because of a bad URI, network problem, etc. + */ + public static String downloadViaHttp(String uri, ContentType type) throws IOException { + String contentTypes; + switch (type) { + case HTML: + contentTypes = "application/xhtml+xml,text/html,text/*,*/*"; + break; + case JSON: + contentTypes = "application/json,text/*,*/*"; + break; + case TEXT: + default: + contentTypes = "text/*,*/*"; + } + return downloadViaHttp(uri, contentTypes); + } + + private static String downloadViaHttp(String uri, String contentTypes) throws IOException { + URL url = new URL(uri); + HttpURLConnection connection = (HttpURLConnection) url.openConnection(); + connection.setRequestProperty("Accept", contentTypes); + connection.setRequestProperty("Accept-Charset", "utf-8,*"); + connection.setRequestProperty("User-Agent", "ZXing (Android)"); + try { + connection.connect(); + if (connection.getResponseCode() != HttpURLConnection.HTTP_OK) { + throw new IOException("Bad HTTP response: " + connection.getResponseCode()); + } + return consume(connection); + } finally { + connection.disconnect(); + } + } + + private static String getEncoding(HttpURLConnection connection) { + String contentTypeHeader = connection.getHeaderField("Content-Type"); + if (contentTypeHeader != null) { + int charsetStart = contentTypeHeader.indexOf("charset="); + if (charsetStart >= 0) { + return contentTypeHeader.substring(charsetStart + "charset=".length()); + } + } + return "UTF-8"; + } + + private static String consume(HttpURLConnection connection) throws IOException { + String encoding = getEncoding(connection); + ByteArrayOutputStream out = new ByteArrayOutputStream(); + InputStream in = connection.getInputStream(); + try { + in = connection.getInputStream(); + byte[] buffer = new byte[1024]; + int bytesRead; + while ((bytesRead = in.read(buffer)) > 0) { + out.write(buffer, 0, bytesRead); + } + } finally { + try { + in.close(); + } catch (IOException ioe) { + // continue + } + } + try { + return new String(out.toByteArray(), encoding); + } catch (UnsupportedEncodingException uee) { + try { + return new String(out.toByteArray(), "UTF-8"); + } catch (UnsupportedEncodingException uee2) { + // can't happen + throw new IllegalStateException(uee2); + } + } + } + + public static URI unredirect(URI uri) throws IOException { + if (!REDIRECTOR_DOMAINS.contains(uri.getHost())) { + return uri; + } + URL url = uri.toURL(); + + HttpURLConnection connection = (HttpURLConnection) url.openConnection(); + connection.setInstanceFollowRedirects(false); + connection.setDoInput(false); + connection.setRequestMethod("HEAD"); + connection.setRequestProperty("User-Agent", "ZXing (Android)"); + try { + connection.connect(); + switch (connection.getResponseCode()) { + case HttpURLConnection.HTTP_MULT_CHOICE: + case HttpURLConnection.HTTP_MOVED_PERM: + case HttpURLConnection.HTTP_MOVED_TEMP: + case HttpURLConnection.HTTP_SEE_OTHER: + case 307: // No constant for 307 Temporary Redirect ? + String location = connection.getHeaderField("Location"); + if (location != null) { + try { + return new URI(location); + } catch (URISyntaxException e) { + // nevermind + } + } + } + return uri; + } finally { + connection.disconnect(); + } + } + +} diff --git a/android/src/com/google/zxing/client/android/book/NetworkWorker.java b/android/src/com/google/zxing/client/android/book/NetworkWorker.java new file mode 100644 index 000000000..429000070 --- /dev/null +++ b/android/src/com/google/zxing/client/android/book/NetworkWorker.java @@ -0,0 +1,76 @@ +/* + * Copyright (C) 2010 ZXing authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.google.zxing.client.android.book; + +import android.os.Handler; +import android.os.Message; +import android.util.Log; +import com.google.zxing.client.android.HttpHelper; +import com.google.zxing.client.android.LocaleManager; +import com.google.zxing.client.android.R; +import org.json.JSONException; +import org.json.JSONObject; + +import java.io.IOException; + +final class NetworkWorker implements Runnable { + + private static final String TAG = NetworkWorker.class.getSimpleName(); + + private final String isbn; + private final String query; + private final Handler handler; + + NetworkWorker(String isbn, String query, Handler handler) { + this.isbn = isbn; + this.query = query; + this.handler = handler; + } + + @Override + public void run() { + try { + // These return a JSON result which describes if and where the query was found. This API may + // break or disappear at any time in the future. Since this is an API call rather than a + // website, we don't use LocaleManager to change the TLD. + String uri; + if (LocaleManager.isBookSearchUrl(isbn)) { + int equals = isbn.indexOf('='); + String volumeId = isbn.substring(equals + 1); + uri = "http://www.google.com/books?id=" + volumeId + "&jscmd=SearchWithinVolume2&q=" + query; + } else { + uri = "http://www.google.com/books?vid=isbn" + isbn + "&jscmd=SearchWithinVolume2&q=" + query; + } + + try { + String content = HttpHelper.downloadViaHttp(uri, HttpHelper.ContentType.JSON); + JSONObject json = new JSONObject(content); + Message message = Message.obtain(handler, R.id.search_book_contents_succeeded); + message.obj = json; + message.sendToTarget(); + } catch (IOException ioe) { + Message message = Message.obtain(handler, R.id.search_book_contents_failed); + message.sendToTarget(); + } + } catch (JSONException je) { + Log.w(TAG, "Error accessing book search", je); + Message message = Message.obtain(handler, R.id.search_book_contents_failed); + message.sendToTarget(); + } + } + +} diff --git a/android/src/com/google/zxing/client/android/book/SearchBookContentsActivity.java b/android/src/com/google/zxing/client/android/book/SearchBookContentsActivity.java index c9f422e96..3c5e10389 100644 --- a/android/src/com/google/zxing/client/android/book/SearchBookContentsActivity.java +++ b/android/src/com/google/zxing/client/android/book/SearchBookContentsActivity.java @@ -31,19 +31,10 @@ import android.widget.Button; import android.widget.EditText; import android.widget.ListView; import android.widget.TextView; -import org.apache.http.Header; -import org.apache.http.HttpEntity; -import org.apache.http.HttpResponse; -import org.apache.http.client.methods.HttpGet; -import org.apache.http.client.methods.HttpHead; -import org.apache.http.client.methods.HttpUriRequest; import org.json.JSONArray; import org.json.JSONException; import org.json.JSONObject; -import java.io.ByteArrayOutputStream; -import java.io.IOException; -import java.net.URI; import java.util.ArrayList; import java.util.List; import java.util.regex.Pattern; @@ -51,7 +42,6 @@ import java.util.regex.Pattern; import com.google.zxing.client.android.LocaleManager; import com.google.zxing.client.android.R; import com.google.zxing.client.android.Intents; -import com.google.zxing.client.android.AndroidHttpClient; /** * Uses Google Book Search to find a word or phrase in the requested book. @@ -59,16 +49,16 @@ import com.google.zxing.client.android.AndroidHttpClient; * @author dswitkin@google.com (Daniel Switkin) */ public final class SearchBookContentsActivity extends Activity { + private static final String TAG = SearchBookContentsActivity.class.getSimpleName(); - private static final String USER_AGENT = "ZXing (Android)"; private static final Pattern TAG_PATTERN = Pattern.compile("\\<.*?\\>"); private static final Pattern LT_ENTITY_PATTERN = Pattern.compile("<"); private static final Pattern GT_ENTITY_PATTERN = Pattern.compile(">"); private static final Pattern QUOTE_ENTITY_PATTERN = Pattern.compile("'"); private static final Pattern QUOT_ENTITY_PATTERN = Pattern.compile("""); - private NetworkThread networkThread; + private Thread networkThread; private String isbn; private EditText queryTextView; private Button queryButton; @@ -169,7 +159,7 @@ public final class SearchBookContentsActivity extends Activity { if (networkThread == null) { String query = queryTextView.getText().toString(); if (query != null && query.length() > 0) { - networkThread = new NetworkThread(isbn, query, handler); + networkThread = new Thread(new NetworkWorker(isbn, query, handler)); networkThread.start(); headerView.setText(R.string.msg_sbc_searching_book); resultListView.setAdapter(null); @@ -240,105 +230,4 @@ public final class SearchBookContentsActivity extends Activity { } } - private static final class NetworkThread extends Thread { - private final String isbn; - private final String query; - private final Handler handler; - - NetworkThread(String isbn, String query, Handler handler) { - this.isbn = isbn; - this.query = query; - this.handler = handler; - } - - @Override - public void run() { - AndroidHttpClient client = null; - try { - // These return a JSON result which describes if and where the query was found. This API may - // break or disappear at any time in the future. Since this is an API call rather than a - // website, we don't use LocaleManager to change the TLD. - URI uri; - if (LocaleManager.isBookSearchUrl(isbn)) { - int equals = isbn.indexOf('='); - String volumeId = isbn.substring(equals + 1); - uri = new URI("http", null, "www.google.com", -1, "/books", "id=" + volumeId + - "&jscmd=SearchWithinVolume2&q=" + query, null); - } else { - uri = new URI("http", null, "www.google.com", -1, "/books", "vid=isbn" + isbn + - "&jscmd=SearchWithinVolume2&q=" + query, null); - } - HttpUriRequest get = new HttpGet(uri); - get.setHeader("cookie", getCookie(uri.toString())); - client = AndroidHttpClient.newInstance(USER_AGENT); - HttpResponse response = client.execute(get); - if (response.getStatusLine().getStatusCode() == 200) { - HttpEntity entity = response.getEntity(); - ByteArrayOutputStream jsonHolder = new ByteArrayOutputStream(); - entity.writeTo(jsonHolder); - jsonHolder.flush(); - JSONObject json = new JSONObject(jsonHolder.toString(getEncoding(entity))); - jsonHolder.close(); - - Message message = Message.obtain(handler, R.id.search_book_contents_succeeded); - message.obj = json; - message.sendToTarget(); - } else { - Log.w(TAG, "HTTP returned " + response.getStatusLine().getStatusCode() + " for " + uri); - Message message = Message.obtain(handler, R.id.search_book_contents_failed); - message.sendToTarget(); - } - } catch (Exception e) { - Log.w(TAG, "Error accessing book search", e); - Message message = Message.obtain(handler, R.id.search_book_contents_failed); - message.sendToTarget(); - } finally { - if (client != null) { - client.close(); - } - } - } - - // Book Search requires a cookie to work, which we store persistently. If the cookie does - // not exist, this could be the first search or it has expired. Either way, do a quick HEAD - // request to fetch it, save it via the CookieSyncManager to flash, then return it. - private static String getCookie(String url) { - String cookie = CookieManager.getInstance().getCookie(url); - if (cookie == null || cookie.length() == 0) { - Log.d(TAG, "Book Search cookie was missing or expired"); - HttpUriRequest head = new HttpHead(url); - AndroidHttpClient client = AndroidHttpClient.newInstance(USER_AGENT); - try { - HttpResponse response = client.execute(head); - if (response.getStatusLine().getStatusCode() == 200) { - Header[] cookies = response.getHeaders("set-cookie"); - for (Header theCookie : cookies) { - CookieManager.getInstance().setCookie(url, theCookie.getValue()); - } - CookieSyncManager.getInstance().sync(); - cookie = CookieManager.getInstance().getCookie(url); - } - } catch (IOException e) { - Log.w(TAG, "Error setting book search cookie", e); - } - client.close(); - } - return cookie; - } - - private static String getEncoding(HttpEntity entity) { - // FIXME: The server is returning ISO-8859-1 but the content is actually windows-1252. - // Once Jeff fixes the HTTP response, remove this hardcoded value and go back to getting - // the encoding dynamically. - return "windows-1252"; -// HeaderElement[] elements = entity.getContentType().getElements(); -// if (elements != null && elements.length > 0) { -// String encoding = elements[0].getParameterByName("charset").getValue(); -// if (encoding != null && encoding.length() > 0) { -// return encoding; -// } -// } -// return "UTF-8"; - } - } } diff --git a/android/src/com/google/zxing/client/android/result/supplement/BookResultInfoRetriever.java b/android/src/com/google/zxing/client/android/result/supplement/BookResultInfoRetriever.java index bdc8eb610..9479e7d0a 100644 --- a/android/src/com/google/zxing/client/android/result/supplement/BookResultInfoRetriever.java +++ b/android/src/com/google/zxing/client/android/result/supplement/BookResultInfoRetriever.java @@ -22,6 +22,7 @@ import java.util.Collection; import android.content.Context; import android.widget.TextView; +import com.google.zxing.client.android.HttpHelper; import com.google.zxing.client.android.LocaleManager; import com.google.zxing.client.android.R; import org.json.JSONArray; @@ -58,7 +59,8 @@ public final class BookResultInfoRetriever extends SupplementalInfoRetriever { @Override void retrieveSupplementalInfo() throws IOException, InterruptedException { - String contents = downloadViaHttp("https://www.googleapis.com/books/v1/volumes?q=isbn:" + isbn); + String contents = HttpHelper.downloadViaHttp("https://www.googleapis.com/books/v1/volumes?q=isbn:" + isbn, + HttpHelper.ContentType.JSON); if (contents.length() == 0) { return; diff --git a/android/src/com/google/zxing/client/android/result/supplement/ProductResultInfoRetriever.java b/android/src/com/google/zxing/client/android/result/supplement/ProductResultInfoRetriever.java index 5d873985b..919d35192 100644 --- a/android/src/com/google/zxing/client/android/result/supplement/ProductResultInfoRetriever.java +++ b/android/src/com/google/zxing/client/android/result/supplement/ProductResultInfoRetriever.java @@ -20,6 +20,7 @@ import android.content.Context; import android.os.Handler; import android.text.Html; import android.widget.TextView; +import com.google.zxing.client.android.HttpHelper; import com.google.zxing.client.android.R; import com.google.zxing.client.android.history.HistoryManager; import com.google.zxing.client.android.LocaleManager; @@ -56,7 +57,7 @@ final class ProductResultInfoRetriever extends SupplementalInfoRetriever { String encodedProductID = URLEncoder.encode(productID, "UTF-8"); String uri = BASE_PRODUCT_URI + encodedProductID; - String content = downloadViaHttp(uri); + String content = HttpHelper.downloadViaHttp(uri, HttpHelper.ContentType.HTML); Matcher matcher = PRODUCT_NAME_PRICE_PATTERN.matcher(content); if (matcher.find()) { diff --git a/android/src/com/google/zxing/client/android/result/supplement/SupplementalInfoRetriever.java b/android/src/com/google/zxing/client/android/result/supplement/SupplementalInfoRetriever.java index c40ad6e20..3c40aa752 100644 --- a/android/src/com/google/zxing/client/android/result/supplement/SupplementalInfoRetriever.java +++ b/android/src/com/google/zxing/client/android/result/supplement/SupplementalInfoRetriever.java @@ -24,21 +24,13 @@ import android.text.Spanned; import android.text.method.LinkMovementMethod; import android.text.style.URLSpan; import android.widget.TextView; -import com.google.zxing.client.android.AndroidHttpClient; import com.google.zxing.client.result.ISBNParsedResult; import com.google.zxing.client.result.ParsedResult; import com.google.zxing.client.result.ProductParsedResult; import com.google.zxing.client.result.URIParsedResult; import com.google.zxing.client.android.history.HistoryManager; -import org.apache.http.HttpEntity; -import org.apache.http.HttpResponse; -import org.apache.http.client.methods.HttpGet; -import org.apache.http.client.methods.HttpUriRequest; -import java.io.ByteArrayOutputStream; import java.io.IOException; -import java.io.InputStream; -import java.io.UnsupportedEncodingException; import java.lang.ref.WeakReference; import java.util.ArrayList; import java.util.Collection; @@ -156,42 +148,4 @@ public abstract class SupplementalInfoRetriever implements Callable { historyManager.addHistoryItemDetails(itemID, newText); } - protected static String downloadViaHttp(String uri) throws IOException { - HttpUriRequest get = new HttpGet(uri); - AndroidHttpClient client = AndroidHttpClient.newInstance(null); - HttpResponse response = client.execute(get); - int status = response.getStatusLine().getStatusCode(); - if (status != 200) { - throw new IOException(); - } - return consume(response.getEntity()); - } - - private static String consume(HttpEntity entity) throws IOException { - ByteArrayOutputStream out = new ByteArrayOutputStream(); - InputStream in = null; - try { - in = entity.getContent(); - byte[] buffer = new byte[1024]; - int bytesRead; - while ((bytesRead = in.read(buffer)) > 0) { - out.write(buffer, 0, bytesRead); - } - } finally { - if (in != null) { - try { - in.close(); - } catch (IOException ioe) { - // continue - } - } - } - try { - return new String(out.toByteArray(), "UTF-8"); - } catch (UnsupportedEncodingException uee) { - // can't happen - throw new IllegalStateException(uee); - } - } - } diff --git a/android/src/com/google/zxing/client/android/result/supplement/URIResultInfoRetriever.java b/android/src/com/google/zxing/client/android/result/supplement/URIResultInfoRetriever.java index 08cf74024..658e0c5f5 100644 --- a/android/src/com/google/zxing/client/android/result/supplement/URIResultInfoRetriever.java +++ b/android/src/com/google/zxing/client/android/result/supplement/URIResultInfoRetriever.java @@ -19,26 +19,18 @@ package com.google.zxing.client.android.result.supplement; import android.content.Context; import android.os.Handler; import android.widget.TextView; +import com.google.zxing.client.android.HttpHelper; import com.google.zxing.client.android.history.HistoryManager; -import com.google.zxing.client.android.AndroidHttpClient; import com.google.zxing.client.android.R; import com.google.zxing.client.result.URIParsedResult; -import org.apache.http.Header; -import org.apache.http.HttpResponse; -import org.apache.http.client.methods.HttpHead; -import org.apache.http.client.methods.HttpUriRequest; import java.io.IOException; +import java.net.URI; +import java.net.URISyntaxException; final class URIResultInfoRetriever extends SupplementalInfoRetriever { - private static final String[] REDIRECTOR_HOSTS = { - "http://bit.ly/", - "http://tinyurl.com/", - "http://tr.im/", - "http://goo.gl/", - "http://ow.ly/", - }; + private static final int MAX_REDIRECTS = 5; private final URIParsedResult result; private final String redirectString; @@ -55,44 +47,22 @@ final class URIResultInfoRetriever extends SupplementalInfoRetriever { @Override void retrieveSupplementalInfo() throws IOException, InterruptedException { - String oldURI = result.getURI(); - String newURI = unredirect(oldURI); + URI oldURI; + try { + oldURI = new URI(result.getURI()); + } catch (URISyntaxException e) { + return; + } + URI newURI = HttpHelper.unredirect(oldURI); int count = 0; - while (count < 3 && !oldURI.equals(newURI)) { - append(result.getDisplayResult(), null, new String[] { redirectString + " : " + newURI }, newURI); - count++; + while (count++ < MAX_REDIRECTS && !oldURI.equals(newURI)) { + append(result.getDisplayResult(), + null, + new String[] { redirectString + " : " + newURI }, + newURI.toString()); oldURI = newURI; - newURI = unredirect(newURI); + newURI = HttpHelper.unredirect(newURI); } } - private static String unredirect(String uri) throws IOException { - if (!isRedirector(uri)) { - return uri; - } - HttpUriRequest head = new HttpHead(uri); - AndroidHttpClient client = AndroidHttpClient.newInstance(null); - HttpResponse response = client.execute(head); - int status = response.getStatusLine().getStatusCode(); - if (status == 301 || status == 302) { - Header redirect = response.getFirstHeader("Location"); - if (redirect != null) { - String location = redirect.getValue(); - if (location != null) { - return location; - } - } - } - return uri; - } - - private static boolean isRedirector(String uri) { - for (String redirectorHost : REDIRECTOR_HOSTS) { - if (uri.startsWith(redirectorHost)) { - return true; - } - } - return false; - } - }