package org.softeg.slartus.forpdacommon;
import android.util.Log;
import org.apache.http.Header;
import org.apache.http.HeaderElement;
import org.apache.http.HttpEntity;
import org.apache.http.HttpException;
import org.apache.http.HttpHost;
import org.apache.http.HttpRequest;
import org.apache.http.HttpRequestInterceptor;
import org.apache.http.HttpResponse;
import org.apache.http.HttpResponseInterceptor;
import org.apache.http.HttpStatus;
import org.apache.http.HttpVersion;
import org.apache.http.NameValuePair;
import org.apache.http.StatusLine;
import org.apache.http.auth.AuthScope;
import org.apache.http.auth.UsernamePasswordCredentials;
import org.apache.http.client.CookieStore;
import org.apache.http.client.ResponseHandler;
import org.apache.http.client.entity.UrlEncodedFormEntity;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.client.methods.HttpRequestBase;
import org.apache.http.client.params.ClientPNames;
import org.apache.http.client.utils.URIUtils;
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.cookie.Cookie;
import org.apache.http.entity.HttpEntityWrapper;
import org.apache.http.impl.client.DefaultHttpClient;
import org.apache.http.impl.client.DefaultRedirectHandler;
import org.apache.http.impl.client.RedirectLocations;
import org.apache.http.impl.conn.tsccm.ThreadSafeClientConnManager;
import org.apache.http.message.BasicNameValuePair;
import org.apache.http.params.BasicHttpParams;
import org.apache.http.params.CoreConnectionPNames;
import org.apache.http.params.CoreProtocolPNames;
import org.apache.http.params.HttpParams;
import org.apache.http.params.HttpProtocolParams;
import org.apache.http.protocol.ExecutionContext;
import org.apache.http.protocol.HttpContext;
import org.apache.http.util.EntityUtils;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.ObjectInput;
import java.io.ObjectInputStream;
import java.io.ObjectOutput;
import java.io.ObjectOutputStream;
import java.io.UnsupportedEncodingException;
import java.net.URI;
import java.net.URISyntaxException;
import java.net.URLEncoder;
import java.util.ArrayList;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import java.util.zip.GZIPInputStream;
/**
* Created by IntelliJ IDEA.
* User: Admin
* Date: 16.09.11
* Time: 19:10
* To change this template use File | Settings | File Templates.
*/
public class HttpHelper {
protected static final String TAG = "HttpHelper";
protected static final String CONTENT_TYPE = "Content-Type";
protected static final int POST_TYPE = 1;
protected static final int GET_TYPE = 2;
protected static final int DOWNLOAD_TYPE = 3;
public static final String GZIP = "gzip";
public static final String ACCEPT_ENCODING = "Accept-Encoding";
public static String HTTP_CONTENT_CHARSET = "windows-1251";
public static String USER_AGENT = "android";
public static String FULL_USER_AGENT = "Mozilla";
public static final String MIME_FORM_ENCODED = "application/x-www-form-urlencoded";
public static final String MIME_TEXT_PLAIN = "text/plain";
public static final String HTTP_RESPONSE = "HTTP_RESPONSE";
public static final String HTTP_RESPONSE_ERROR = "HTTP_RESPONSE_ERROR";
// Establish client once, as static field with static setup block.
// (This is a best practice in HttpClient docs - but will leave reference until *process* stopped on Android.)
protected final DefaultHttpClient client;
public CookieStore getCookieStore() {
return client.getCookieStore();
}
public List<Cookie> getLastCookies() {
return client.getCookieStore().getCookies();
}
public void writeExternalCookies(String cookiesFile) throws Exception {
if (!FileUtils.mkDirs(cookiesFile))
throw new Exception("Не могу создать директорию '" + cookiesFile + "' для cookies");
new File(cookiesFile).createNewFile();
FileOutputStream fw = new FileOutputStream(cookiesFile, false);
ObjectOutput out = new ObjectOutputStream(fw);
final List<Cookie> cookies = client.getCookieStore().getCookies();
for (Cookie cookie : cookies) {
new SerializableCookie(cookie).writeExternal(out);
}
out.close();
fw.close();
}
protected RuntimeException mLeakedException = new IllegalStateException(
"AndroidHttpClient created and never closed");
@Override
protected void finalize() throws Throwable {
super.finalize();
if (mLeakedException != null) {
mLeakedException = null;
}
}
/**
* Release resources associated with this client. You must call this,
* or significant resources (sockets and memory) may be leaked.
*/
public void close() {
if (mLeakedException != null) {
getConnectionManager().shutdown();
mLeakedException = null;
}
}
public ClientConnectionManager getConnectionManager() {
return client.getConnectionManager();
}
public void clearCookies() {
client.getCookieStore().clear();
}
public static void readExternalCookies(CookieStore cookieStore, String cookieFile) throws IOException {
FileInputStream fw = new FileInputStream(cookieFile);
ObjectInput input = new ObjectInputStream(fw);
while (true) {
try {
SerializableCookie serializableCookie = new SerializableCookie();
serializableCookie.readExternal(input);
cookieStore.addCookie(serializableCookie);
} catch (Exception ex) {
break;
}
}
input.close();
fw.close();
}
public List<Cookie> getCookies() {
return client.getCookieStore().getCookies();
}
public HttpHelper(String userAgent, final String cookiesPath) {
responseHandler = new ResponseHandler<String>() {
public String handleResponse(HttpResponse httpResponse) throws IOException {
StatusLine status = httpResponse.getStatusLine();
checkStatus(status, m_LastUrl);
return EntityUtils.toString(httpResponse.getEntity(), HTTP_CONTENT_CHARSET);
}
};
HttpParams params = new BasicHttpParams();
params.setParameter(CoreProtocolPNames.PROTOCOL_VERSION, HttpVersion.HTTP_1_1);
params.setParameter(CoreProtocolPNames.HTTP_CONTENT_CHARSET, HTTP_CONTENT_CHARSET);
params.setParameter(CoreProtocolPNames.USER_AGENT, userAgent);
params.setParameter(CoreConnectionPNames.STALE_CONNECTION_CHECK, false);
HttpProtocolParams.setUseExpectContinue(params, false);
SchemeRegistry schemeRegistry = new SchemeRegistry();
schemeRegistry.register(new Scheme("http", PlainSocketFactory.getSocketFactory(), 80));
schemeRegistry.register(new Scheme("https", SSLSocketFactory.getSocketFactory(), 443));
ThreadSafeClientConnManager cm = new ThreadSafeClientConnManager(params, schemeRegistry);
client = new DefaultHttpClient(cm, params);
client.setCookieStore(new CookieStore() {
private List<Cookie> m_Cookies = null;
public void addCookie(Cookie cookie) {
for (int i = 0; i < m_Cookies.size(); i++) {
if (m_Cookies.get(i).getName().equals(cookie.getName())) {
m_Cookies.remove(i);
break;
}
}
m_Cookies.add(cookie);
}
public List<Cookie> getCookies() {
if (m_Cookies == null) {
m_Cookies = new ArrayList<Cookie>();
try {
readExternalCookies(this, cookiesPath);
} catch (IOException ignoreEx) {
// e.printStackTrace(); //To change body of catch statement use File | Settings | File Templates.
}
}
return m_Cookies;
}
public boolean clearExpired(Date date) {
for (int i = m_Cookies.size() - 1; i >= 0; i--) {
if (m_Cookies.get(i).getExpiryDate() != null && date != null && date.after(m_Cookies.get(i).getExpiryDate())) {
m_Cookies.remove(i);
break;
}
}
return true; //To change body of implemented methods use File | Settings | File Templates.
}
public void clear() {
if (m_Cookies != null)
m_Cookies.clear();
}
});
// add gzip decompressor to handle gzipped content in responses
// (default we *do* always send accept encoding gzip cat_name in request)
client.addResponseInterceptor(new HttpResponseInterceptor() {
public void process(final HttpResponse response, final HttpContext context) throws HttpException, IOException {
HttpEntity entity = response.getEntity();
Header contentEncodingHeader = entity.getContentEncoding();
if (contentEncodingHeader != null) {
HeaderElement[] codecs = contentEncodingHeader.getElements();
for (HeaderElement codec : codecs) {
if (codec.getName().equalsIgnoreCase(HttpHelper.GZIP)) {
response.setEntity(new GzipDecompressingEntity(response.getEntity()));
return;
}
}
}
}
});
client.setRedirectHandler(new DefaultRedirectHandler() {
private static final String REDIRECT_LOCATIONS = "http.protocol.redirect-locations";
public URI getLocationURI(HttpResponse response, HttpContext context) {
if (response == null) {
throw new IllegalArgumentException("HTTP response may not be null");
}
//get the location header to find out where to redirect to
Header locationHeader = response.getFirstHeader("location");
assert locationHeader != null;
String location = locationHeader.getValue();
Matcher matcher = Pattern.compile("(http://sdl\\d+.4pda.ru/\\d+/)(.*?)(\\?.*)").matcher(location);
if (matcher.find()) {
location = matcher.group(1) + URLEncoder.encode(matcher.group(2)) + matcher.group(3);
} else
location = location.replaceAll(" ", "%20");
if (location.contains("/#"))
location = location.substring(0, location.indexOf("#"));
URI uri = null;
try {
uri = new URI(location);
} catch (URISyntaxException ignored) {
}
HttpParams params = response.getParams();
// rfc2616 demands the location value be a complete URI
// Location = "Location" ":" absoluteURI
assert uri != null;
if (!uri.isAbsolute()) {
// Adjust location URI
HttpHost target = (HttpHost) context.getAttribute(
ExecutionContext.HTTP_TARGET_HOST);
if (target == null) {
throw new IllegalStateException("Target host not available " +
"in the HTTP context");
}
HttpRequest request = (HttpRequest) context.getAttribute(
ExecutionContext.HTTP_REQUEST);
try {
URI requestURI = new URI(request.getRequestLine().getUri());
URI absoluteRequestURI = URIUtils.rewriteURI(requestURI, target, true);
uri = URIUtils.resolve(absoluteRequestURI, uri);
} catch (URISyntaxException ignored) {
}
}
if (params.isParameterFalse(ClientPNames.ALLOW_CIRCULAR_REDIRECTS)) {
RedirectLocations redirectLocations = (RedirectLocations) context.getAttribute(
REDIRECT_LOCATIONS);
if (redirectLocations == null) {
redirectLocations = new RedirectLocations();
context.setAttribute(REDIRECT_LOCATIONS, redirectLocations);
}
URI redirectURI = null;
if (uri.getFragment() != null) {
try {
HttpHost target = new HttpHost(
uri.getHost(),
uri.getPort(),
uri.getScheme());
redirectURI = URIUtils.rewriteURI(uri, target, true);
} catch (URISyntaxException ignored) {
}
} else {
redirectURI = uri;
}
if (!redirectLocations.contains(redirectURI)) {
redirectLocations.add(redirectURI);
}
}
m_RedirectUri = uri;
return uri;
}
});
}
protected final ResponseHandler<String> responseHandler;
public String performGet(final String url) throws IOException {
return performRequest(null, url, null, null, null, new ArrayList<NameValuePair>(), HttpHelper.GET_TYPE, HTTP_CONTENT_CHARSET);
}
/**
* Perform an HTTP GET operation with user/pass and headers.
*/
public String performGet(final String url, final String user, final String pass,
final Map<String, String> additionalHeaders) throws IOException {
return performRequest(null, url, user, pass, additionalHeaders, new ArrayList<NameValuePair>(), HttpHelper.GET_TYPE, HTTP_CONTENT_CHARSET);
}
/**
* Perform a simplified HTTP POST operation.
*/
public String performPost(final String url, final Map<String, String> params) throws IOException {
return performRequest(HttpHelper.MIME_FORM_ENCODED, url, null, null, null, params, HttpHelper.POST_TYPE, HTTP_CONTENT_CHARSET);
}
/**
* Perform a simplified HTTP POST operation.
*/
public String performPost(final String url, final List<NameValuePair> params) throws IOException {
return performRequest(HttpHelper.MIME_FORM_ENCODED, url, null, null, null, params, HttpHelper.POST_TYPE, HTTP_CONTENT_CHARSET);
}
public String performPost(final String url, final Map<String, String> params, String encoding) throws IOException {
return performRequest(HttpHelper.MIME_FORM_ENCODED, url, null, null, null, params, HttpHelper.POST_TYPE, encoding);
}
protected static URI m_RedirectUri;
protected static String m_LastUrl;
public static URI getRedirectUri() {
return m_RedirectUri;
}
public static String getLastUri() {
return m_LastUrl;
}
private String performRequest(final String contentType, String url, final String user, final String pass,
final Map<String, String> headers, final Map<String, String> params, final int requestType,
String encoding) throws IOException {
List<NameValuePair> nvps = null;
if ((params != null) && (params.size() > 0)) {
nvps = new ArrayList<>();
for (Map.Entry<String, String> entry : params.entrySet()) {
nvps.add(new BasicNameValuePair(entry.getKey(), entry.getValue()));
}
}
return performRequest(contentType, url, user, pass, headers, nvps, requestType, encoding);
}
//
// private methods
//
private String performRequest(final String contentType, String url, final String user, final String pass,
final Map<String, String> headers, final List<NameValuePair> nvps, final int requestType,
String encoding) throws IOException {
Log.d("kek", "request url " + url);
if (url.substring(0, 2).equals("//")) {
url = "http:".concat(url);
Log.d("kek", "fixed request url " + url);
}
url = url.replace("\"", "").replace("'", "");
m_LastUrl = url;
android.util.Log.i("HttpHelper", url);
// add user and pass to client credentials if present
if ((user != null) && (pass != null)) {
client.getCredentialsProvider().setCredentials(AuthScope.ANY,
new UsernamePasswordCredentials(user, pass));
}
// process headers using request interceptor
final Map<String, String> sendHeaders = new HashMap<String, String>();
// add encoding cat_name for gzip if not present
sendHeaders.put(HttpHelper.ACCEPT_ENCODING, HttpHelper.GZIP);
if ((headers != null) && (headers.size() > 0)) {
sendHeaders.putAll(headers);
}
if (requestType == HttpHelper.POST_TYPE) {
sendHeaders.put(HttpHelper.CONTENT_TYPE, contentType);
}
if (sendHeaders.size() > 0) {
client.addRequestInterceptor(new HttpRequestInterceptor() {
public void process(final HttpRequest request, final HttpContext context) throws HttpException, IOException {
for (String key : sendHeaders.keySet()) {
if (!request.containsHeader(key)) {
request.addHeader(key, sendHeaders.get(key));
}
}
}
});
}
m_RedirectUri = null;
// handle POST or GET request respectively
HttpRequestBase method = null;
if (requestType == HttpHelper.POST_TYPE) {
method = new HttpPost(url);
// data - name/value params
if (nvps != null) {
try {
HttpPost methodPost = (HttpPost) method;
methodPost.setEntity(new UrlEncodedFormEntity(nvps, encoding));
} catch (UnsupportedEncodingException e) {
throw new RuntimeException("Error peforming HTTP request: " + e.getMessage(), e);
}
}
} else if (requestType == HttpHelper.GET_TYPE) {
method = new HttpGet(url);
}
// execute request
return execute(method);
}
private synchronized String execute(final HttpRequestBase method) throws IOException {
String response;
// execute method returns?!? (rather than async) - do it here sync, and wrap async elsewhere
response = client.execute(method, responseHandler);
return response;
}
protected void checkStatus(StatusLine status, String url) throws IOException {
int statusCode = status.getStatusCode();
if (statusCode != HttpStatus.SC_OK && statusCode != HttpStatus.SC_PARTIAL_CONTENT) {
if (statusCode != 200 && statusCode != 300) {
if (statusCode >= 500 && statusCode < 600)
throw new ShowInBrowserException("Сайт не отвечает: " + statusCode + " " + AppHttpStatus.getReasonPhrase(statusCode, status.getReasonPhrase()), url);
else if (statusCode == 404)
throw new ShowInBrowserException("Сайт не отвечает: " + statusCode + " " + AppHttpStatus.getReasonPhrase(statusCode, status.getReasonPhrase()), url);
else
throw new ShowInBrowserException(statusCode + " " + AppHttpStatus.getReasonPhrase(statusCode, status.getReasonPhrase()), url);
}
}
}
static class GzipDecompressingEntity extends HttpEntityWrapper {
public GzipDecompressingEntity(final HttpEntity entity) {
super(entity);
}
@Override
public InputStream getContent() throws IOException, IllegalStateException {
// the wrapped entity's getContent() decides about repeatability
InputStream wrappedin = wrappedEntity.getContent();
return new GZIPInputStream(wrappedin);
}
@Override
public long getContentLength() {
// length of ungzipped content is not known
return -1;
}
}
}