// Copyright 2015 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
package org.chromium.chrome.browser.physicalweb;
import org.chromium.base.ThreadUtils;
import java.io.BufferedInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.net.HttpURLConnection;
import java.net.MalformedURLException;
import java.net.URL;
/**
* This class represents an HTTP request.
* This is to be used as a base class for more specific request classes.
* @param <T> The type representing the request payload.
*/
abstract class HttpRequest<T> implements Runnable {
// HTTP request header field names
private static final String USER_AGENT_HEADER_NAME = "User-Agent";
private static final String ACCEPT_LANGUAGE_HEADER_NAME = "Accept-Language";
private final URL mUrl;
private final String mUserAgent;
private final String mAcceptLanguage;
private final HttpRequestCallback<T> mCallback;
/**
* Construct a Request object.
* @param url The URL to make an HTTP request to.
* @param userAgent The string to set as the User-Agent request header.
* @param acceptLanguage The string to set as the Accept-Language request header.
* @param callback The callback run when the HTTP response is received.
* The callback will be run on the main thread.
* @throws MalformedURLException on invalid url
*/
public HttpRequest(String url, String userAgent, String acceptLanguage,
HttpRequestCallback<T> callback)
throws MalformedURLException {
mUrl = new URL(url);
mUserAgent = userAgent;
mAcceptLanguage = acceptLanguage;
if (!mUrl.getProtocol().equals("http") && !mUrl.getProtocol().equals("https")) {
throw new MalformedURLException("This is not a http or https URL: " + url);
}
mCallback = callback;
}
/**
* The callback that gets run after the request is made.
*/
public interface HttpRequestCallback<T> {
/**
* The callback run on a valid response.
* @param result The result object.
*/
void onResponse(T result);
/**
* The callback run on an Exception.
* @param httpResponseCode The HTTP response code. This will be 0 if no
* response was received.
* @param e The encountered Exception.
*/
void onError(int httpResponseCode, Exception e);
}
/**
* Make the HTTP request and parse the HTTP response.
*/
@Override
public void run() {
// Setup some values
HttpURLConnection urlConnection = null;
T result = null;
InputStream inputStream = null;
int responseCode = 0;
IOException ioException = null;
// Make the request
try {
urlConnection = (HttpURLConnection) mUrl.openConnection();
urlConnection.setRequestProperty(USER_AGENT_HEADER_NAME, mUserAgent);
urlConnection.setRequestProperty(ACCEPT_LANGUAGE_HEADER_NAME, mAcceptLanguage);
writeToUrlConnection(urlConnection);
responseCode = urlConnection.getResponseCode();
inputStream = new BufferedInputStream(urlConnection.getInputStream());
result = readInputStream(inputStream);
} catch (IOException e) {
ioException = e;
} finally {
if (urlConnection != null) {
urlConnection.disconnect();
}
}
// Invoke the callback on the main thread.
final Exception finalException = ioException;
final T finalResult = result;
final int finalResponseCode = responseCode;
ThreadUtils.postOnUiThread(new Runnable() {
@Override
public void run() {
if (finalException == null) {
mCallback.onResponse(finalResult);
} else {
mCallback.onError(finalResponseCode, finalException);
}
}
});
}
/**
* Helper method to make an HTTP request.
* @param urlConnection The HTTP connection.
* @throws IOException on error
*/
protected abstract void writeToUrlConnection(HttpURLConnection urlConnection)
throws IOException;
/**
* Helper method to read an HTTP response.
* @param is The InputStream.
* @return An object representing the HTTP response.
* @throws IOException on error
*/
protected abstract T readInputStream(InputStream is) throws IOException;
}