parent
ba0c8bc564
commit
6eda79830e
@ -0,0 +1,115 @@
|
||||
package com.omertron.themoviedbapi.tools;
|
||||
|
||||
import com.omertron.themoviedbapi.MovieDbException;
|
||||
import java.io.IOException;
|
||||
import java.net.URISyntaxException;
|
||||
import java.net.URL;
|
||||
import java.nio.charset.Charset;
|
||||
import org.apache.http.client.methods.HttpDelete;
|
||||
import org.apache.http.client.methods.HttpGet;
|
||||
import org.apache.http.client.methods.HttpPost;
|
||||
import org.apache.http.entity.ContentType;
|
||||
import org.apache.http.entity.StringEntity;
|
||||
import org.apache.http.impl.client.CloseableHttpClient;
|
||||
import org.apache.http.protocol.HTTP;
|
||||
import org.yamj.api.common.exception.ApiExceptionType;
|
||||
import org.yamj.api.common.http.DigestedResponse;
|
||||
import org.yamj.api.common.http.DigestedResponseReader;
|
||||
|
||||
/**
|
||||
* HTTP tools to aid in processing web requests
|
||||
*
|
||||
* @author Stuart.Boston
|
||||
*/
|
||||
public class HttpTools {
|
||||
|
||||
private final CloseableHttpClient httpClient;
|
||||
private static final Charset CHARSET = Charset.forName("UTF-8");
|
||||
private static final int HTTP_STATUS_300 = 300;
|
||||
private static final int HTTP_STATUS_500 = 500;
|
||||
|
||||
public HttpTools(CloseableHttpClient httpClient) {
|
||||
this.httpClient = httpClient;
|
||||
}
|
||||
|
||||
/**
|
||||
* GET data from the URL
|
||||
*
|
||||
* @param url URL to use in the request
|
||||
* @return String content
|
||||
* @throws MovieDbException
|
||||
*/
|
||||
public String getRequest(final URL url) throws MovieDbException {
|
||||
try {
|
||||
HttpGet httpGet = new HttpGet(url.toURI());
|
||||
httpGet.addHeader("accept", "application/json");
|
||||
return validateResponse(DigestedResponseReader.requestContent(httpClient, httpGet, CHARSET), url);
|
||||
} catch (URISyntaxException ex) {
|
||||
throw new MovieDbException(ApiExceptionType.CONNECTION_ERROR, null, url, ex);
|
||||
} catch (IOException ex) {
|
||||
throw new MovieDbException(ApiExceptionType.CONNECTION_ERROR, null, url, ex);
|
||||
} catch (RuntimeException ex) {
|
||||
throw new MovieDbException(ApiExceptionType.HTTP_503_ERROR, "Service Unavailable", url, ex);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Execute a DELETE on the URL
|
||||
*
|
||||
* @param url URL to use in the request
|
||||
* @return String content
|
||||
* @throws MovieDbException
|
||||
*/
|
||||
public String deleteRequest(final URL url) throws MovieDbException {
|
||||
try {
|
||||
HttpDelete httpDel = new HttpDelete(url.toURI());
|
||||
return validateResponse(DigestedResponseReader.deleteContent(httpClient, httpDel, CHARSET), url);
|
||||
} catch (URISyntaxException ex) {
|
||||
throw new MovieDbException(ApiExceptionType.CONNECTION_ERROR, null, url, ex);
|
||||
} catch (IOException ex) {
|
||||
throw new MovieDbException(ApiExceptionType.CONNECTION_ERROR, null, url, ex);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* POST content to the URL with the specified body
|
||||
*
|
||||
* @param url URL to use in the request
|
||||
* @param jsonBody Body to use in the request
|
||||
* @return String content
|
||||
* @throws MovieDbException
|
||||
*/
|
||||
public String postRequest(final URL url, final String jsonBody) throws MovieDbException {
|
||||
try {
|
||||
HttpPost httpPost = new HttpPost(url.toURI());
|
||||
httpPost.addHeader(HTTP.CONTENT_TYPE, "application/x-www-form-urlencoded");
|
||||
StringEntity params = new StringEntity(jsonBody, ContentType.APPLICATION_JSON);
|
||||
httpPost.setEntity(params);
|
||||
|
||||
return validateResponse(DigestedResponseReader.postContent(httpClient, httpPost, CHARSET), url);
|
||||
} catch (URISyntaxException ex) {
|
||||
throw new MovieDbException(ApiExceptionType.CONNECTION_ERROR, null, url, ex);
|
||||
} catch (IOException ex) {
|
||||
throw new MovieDbException(ApiExceptionType.CONNECTION_ERROR, null, url, ex);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Check the status codes of the response and throw exceptions if needed
|
||||
*
|
||||
* @param response DigestedResponse to process
|
||||
* @param url URL for notification purposes
|
||||
* @return String content
|
||||
* @throws MovieDbException
|
||||
*/
|
||||
private String validateResponse(final DigestedResponse response, final URL url) throws MovieDbException {
|
||||
if (response.getStatusCode() >= HTTP_STATUS_500) {
|
||||
throw new MovieDbException(ApiExceptionType.HTTP_503_ERROR, response.getContent(), response.getStatusCode(), url, null);
|
||||
} else if (response.getStatusCode() >= HTTP_STATUS_300) {
|
||||
throw new MovieDbException(ApiExceptionType.HTTP_404_ERROR, response.getContent(), response.getStatusCode(), url, null);
|
||||
}
|
||||
|
||||
return response.getContent();
|
||||
}
|
||||
|
||||
}
|
||||
@ -1,335 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 2004-2015 Stuart Boston
|
||||
*
|
||||
* This file is part of TheMovieDB API.
|
||||
*
|
||||
* TheMovieDB API is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* any later version.
|
||||
*
|
||||
* TheMovieDB API is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with TheMovieDB API. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
package com.omertron.themoviedbapi.tools;
|
||||
|
||||
import com.omertron.themoviedbapi.MovieDbException;
|
||||
import java.io.BufferedReader;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStreamReader;
|
||||
import java.io.OutputStreamWriter;
|
||||
import java.io.StringWriter;
|
||||
import java.net.HttpURLConnection;
|
||||
import java.net.MalformedURLException;
|
||||
import java.net.URL;
|
||||
import java.net.URLConnection;
|
||||
import java.nio.charset.Charset;
|
||||
import java.nio.charset.UnsupportedCharsetException;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.regex.Matcher;
|
||||
import java.util.regex.Pattern;
|
||||
import org.apache.commons.codec.binary.Base64;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import org.apache.http.protocol.HTTP;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.yamj.api.common.exception.ApiExceptionType;
|
||||
|
||||
/**
|
||||
* Web browser with simple cookies support
|
||||
*/
|
||||
public final class WebBrowser {
|
||||
|
||||
private static final Logger LOG = LoggerFactory.getLogger(WebBrowser.class);
|
||||
private static final Map<String, String> BROWSER_PROPERTIES = new HashMap<String, String>();
|
||||
private static final Map<String, Map<String, String>> COOKIES = new HashMap<String, Map<String, String>>();
|
||||
private static String proxyHost = null;
|
||||
private static int proxyPort = 0;
|
||||
private static String proxyUsername = null;
|
||||
private static String proxyPassword = null;
|
||||
private static String proxyEncodedPassword = null;
|
||||
// 25 second timeout
|
||||
private static int webTimeoutConnect = 25000;
|
||||
// 90 second timeout
|
||||
private static int webTimeoutRead = 90000;
|
||||
|
||||
// Hide the constructor
|
||||
protected WebBrowser() {
|
||||
// prevents calls from subclass
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
/**
|
||||
* Populate the browser properties
|
||||
*/
|
||||
private static void populateBrowserProperties() {
|
||||
if (BROWSER_PROPERTIES.isEmpty()) {
|
||||
BROWSER_PROPERTIES.put(HTTP.USER_AGENT, "Mozilla/5.25 Netscape/5.0 (Windows; I; Win95)");
|
||||
BROWSER_PROPERTIES.put("Accept", "application/json");
|
||||
BROWSER_PROPERTIES.put(HTTP.CONTENT_TYPE, "application/json");
|
||||
}
|
||||
}
|
||||
|
||||
public static String request(String url) throws MovieDbException {
|
||||
try {
|
||||
return request(new URL(url));
|
||||
} catch (MalformedURLException ex) {
|
||||
throw new MovieDbException(ApiExceptionType.INVALID_URL, null, url, ex);
|
||||
}
|
||||
}
|
||||
|
||||
public static URLConnection openProxiedConnection(URL url) throws MovieDbException {
|
||||
try {
|
||||
if (proxyHost != null) {
|
||||
System.getProperties().put("proxySet", "true");
|
||||
System.getProperties().put("proxyHost", proxyHost);
|
||||
System.getProperties().put("proxyPort", proxyPort);
|
||||
}
|
||||
|
||||
URLConnection cnx = url.openConnection();
|
||||
|
||||
if (proxyUsername != null) {
|
||||
cnx.setRequestProperty("Proxy-Authorization", proxyEncodedPassword);
|
||||
}
|
||||
|
||||
return cnx;
|
||||
} catch (IOException ex) {
|
||||
throw new MovieDbException(ApiExceptionType.INVALID_URL, null, url, ex);
|
||||
}
|
||||
}
|
||||
|
||||
public static String request(URL url) throws MovieDbException {
|
||||
return request(url, null, Boolean.FALSE);
|
||||
}
|
||||
|
||||
public static String request(URL url, String jsonBody) throws MovieDbException {
|
||||
return request(url, jsonBody, Boolean.FALSE);
|
||||
}
|
||||
|
||||
public static String request(URL url, String jsonBody, boolean isDeleteRequest) throws MovieDbException {
|
||||
|
||||
StringWriter content = null;
|
||||
|
||||
try {
|
||||
content = new StringWriter();
|
||||
|
||||
BufferedReader in = null;
|
||||
HttpURLConnection cnx = null;
|
||||
OutputStreamWriter wr = null;
|
||||
try {
|
||||
cnx = (HttpURLConnection) openProxiedConnection(url);
|
||||
|
||||
// If we get a null connection, then throw an exception
|
||||
if (cnx == null) {
|
||||
throw new MovieDbException(ApiExceptionType.CONNECTION_ERROR, "No HTTP connection could be made.", url);
|
||||
}
|
||||
|
||||
if (isDeleteRequest) {
|
||||
cnx.setDoOutput(true);
|
||||
cnx.setRequestProperty(HTTP.CONTENT_TYPE, "application/x-www-form-urlencoded");
|
||||
cnx.setRequestMethod("DELETE");
|
||||
}
|
||||
|
||||
sendHeader(cnx);
|
||||
|
||||
if (StringUtils.isNotBlank(jsonBody)) {
|
||||
cnx.setDoOutput(true);
|
||||
wr = new OutputStreamWriter(cnx.getOutputStream());
|
||||
wr.write(jsonBody);
|
||||
}
|
||||
|
||||
readHeader(cnx);
|
||||
|
||||
// http://stackoverflow.com/questions/4633048/httpurlconnection-reading-response-content-on-403-error
|
||||
if (cnx.getResponseCode() >= 400) {
|
||||
in = new BufferedReader(new InputStreamReader(cnx.getErrorStream(), getCharset(cnx)));
|
||||
} else {
|
||||
in = new BufferedReader(new InputStreamReader(cnx.getInputStream(), getCharset(cnx)));
|
||||
}
|
||||
|
||||
String line;
|
||||
while ((line = in.readLine()) != null) {
|
||||
content.write(line);
|
||||
}
|
||||
} finally {
|
||||
if (wr != null) {
|
||||
wr.flush();
|
||||
wr.close();
|
||||
}
|
||||
|
||||
if (in != null) {
|
||||
in.close();
|
||||
}
|
||||
|
||||
if (cnx instanceof HttpURLConnection) {
|
||||
((HttpURLConnection) cnx).disconnect();
|
||||
}
|
||||
}
|
||||
return content.toString();
|
||||
} catch (IOException ex) {
|
||||
throw new MovieDbException(ApiExceptionType.CONNECTION_ERROR, null, url, ex);
|
||||
} finally {
|
||||
if (content != null) {
|
||||
try {
|
||||
content.close();
|
||||
} catch (IOException ex) {
|
||||
LOG.debug("Failed to close connection: {}", ex.getMessage());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static void sendHeader(URLConnection cnx) {
|
||||
populateBrowserProperties();
|
||||
|
||||
// send browser properties
|
||||
for (Map.Entry<String, String> browserProperty : BROWSER_PROPERTIES.entrySet()) {
|
||||
cnx.setRequestProperty(browserProperty.getKey(), browserProperty.getValue());
|
||||
}
|
||||
// send cookies
|
||||
String cookieHeader = createCookieHeader(cnx);
|
||||
if (!cookieHeader.isEmpty()) {
|
||||
cnx.setRequestProperty("Cookie", cookieHeader);
|
||||
}
|
||||
}
|
||||
|
||||
private static String createCookieHeader(URLConnection cnx) {
|
||||
String host = cnx.getURL().getHost();
|
||||
StringBuilder cookiesHeader = new StringBuilder();
|
||||
for (Map.Entry<String, Map<String, String>> domainCookies : COOKIES.entrySet()) {
|
||||
if (host.endsWith(domainCookies.getKey())) {
|
||||
for (Map.Entry<String, String> cookie : domainCookies.getValue().entrySet()) {
|
||||
cookiesHeader.append(cookie.getKey());
|
||||
cookiesHeader.append("=");
|
||||
cookiesHeader.append(cookie.getValue());
|
||||
cookiesHeader.append(";");
|
||||
}
|
||||
}
|
||||
}
|
||||
if (cookiesHeader.length() > 0) {
|
||||
// remove last ; char
|
||||
cookiesHeader.deleteCharAt(cookiesHeader.length() - 1);
|
||||
}
|
||||
return cookiesHeader.toString();
|
||||
}
|
||||
|
||||
private static void readHeader(URLConnection cnx) {
|
||||
// read new cookies and update our cookies
|
||||
for (Map.Entry<String, List<String>> header : cnx.getHeaderFields().entrySet()) {
|
||||
if ("Set-Cookie".equals(header.getKey())) {
|
||||
for (String cookieHeader : header.getValue()) {
|
||||
String[] cookieElements = cookieHeader.split(" *; *");
|
||||
if (cookieElements.length >= 1) {
|
||||
String[] firstElem = cookieElements[0].split(" *= *");
|
||||
String cookieName = firstElem[0];
|
||||
String cookieValue = firstElem.length > 1 ? firstElem[1] : null;
|
||||
String cookieDomain = null;
|
||||
// find cookie domain
|
||||
for (int i = 1; i < cookieElements.length; i++) {
|
||||
String[] cookieElement = cookieElements[i].split(" *= *");
|
||||
if ("domain".equals(cookieElement[0])) {
|
||||
cookieDomain = cookieElement.length > 1 ? cookieElement[1] : null;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (cookieDomain == null) {
|
||||
// if domain isn't set take current host
|
||||
cookieDomain = cnx.getURL().getHost();
|
||||
}
|
||||
Map<String, String> domainCookies = COOKIES.get(cookieDomain);
|
||||
if (domainCookies == null) {
|
||||
domainCookies = new HashMap<String, String>();
|
||||
COOKIES.put(cookieDomain, domainCookies);
|
||||
}
|
||||
// add or replace cookie
|
||||
domainCookies.put(cookieName, cookieValue);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static Charset getCharset(URLConnection cnx) {
|
||||
Charset charset = null;
|
||||
// content type will be string like "text/html; charset=UTF-8" or "text/html"
|
||||
String contentType = cnx.getContentType();
|
||||
if (contentType != null) {
|
||||
// changed 'charset' to 'harset' in regexp because some sites send 'Charset'
|
||||
Matcher m = Pattern.compile("harset *=[ '\"]*([^ ;'\"]+)[ ;'\"]*").matcher(contentType);
|
||||
if (m.find()) {
|
||||
String encoding = m.group(1);
|
||||
try {
|
||||
charset = Charset.forName(encoding);
|
||||
} catch (UnsupportedCharsetException e) {
|
||||
// there will be used default charset
|
||||
}
|
||||
}
|
||||
}
|
||||
if (charset == null) {
|
||||
charset = Charset.defaultCharset();
|
||||
}
|
||||
|
||||
return charset;
|
||||
}
|
||||
|
||||
public static String getProxyHost() {
|
||||
return proxyHost;
|
||||
}
|
||||
|
||||
public static void setProxyHost(String myProxyHost) {
|
||||
WebBrowser.proxyHost = myProxyHost;
|
||||
}
|
||||
|
||||
public static int getProxyPort() {
|
||||
return proxyPort;
|
||||
}
|
||||
|
||||
public static void setProxyPort(int myProxyPort) {
|
||||
WebBrowser.proxyPort = myProxyPort;
|
||||
}
|
||||
|
||||
public static String getProxyUsername() {
|
||||
return proxyUsername;
|
||||
}
|
||||
|
||||
public static void setProxyUsername(String myProxyUsername) {
|
||||
WebBrowser.proxyUsername = myProxyUsername;
|
||||
}
|
||||
|
||||
public static String getProxyPassword() {
|
||||
return proxyPassword;
|
||||
}
|
||||
|
||||
public static void setProxyPassword(String myProxyPassword) {
|
||||
WebBrowser.proxyPassword = myProxyPassword;
|
||||
|
||||
if (proxyUsername != null) {
|
||||
proxyEncodedPassword = proxyUsername + ":" + proxyPassword;
|
||||
proxyEncodedPassword = "Basic " + new String(Base64.encodeBase64((proxyUsername + ":" + proxyPassword).getBytes()));
|
||||
}
|
||||
}
|
||||
|
||||
public static int getWebTimeoutConnect() {
|
||||
return webTimeoutConnect;
|
||||
}
|
||||
|
||||
public static int getWebTimeoutRead() {
|
||||
return webTimeoutRead;
|
||||
}
|
||||
|
||||
public static void setWebTimeoutConnect(int webTimeoutConnect) {
|
||||
WebBrowser.webTimeoutConnect = webTimeoutConnect;
|
||||
}
|
||||
|
||||
public static void setWebTimeoutRead(int webTimeoutRead) {
|
||||
WebBrowser.webTimeoutRead = webTimeoutRead;
|
||||
}
|
||||
}
|
||||
Loading…
Reference in New Issue