package com.xiaomi.xms.sales.request;
import android.text.TextUtils;
import com.xiaomi.xms.sales.ShopApp;
import com.xiaomi.xms.sales.request.HostManager.Parameters;
import com.xiaomi.xms.sales.util.Coder;
import com.xiaomi.xms.sales.util.Constants;
import com.xiaomi.xms.sales.util.Device;
import com.xiaomi.xms.sales.util.LogUtil;
import com.xiaomi.xms.sales.util.Utils;
import com.xiaomi.xms.sales.xmsf.account.LoginManager;
import org.apache.http.HttpStatus;
import org.apache.http.NameValuePair;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.client.utils.URLEncodedUtils;
import org.apache.http.message.BasicNameValuePair;
import org.apache.http.protocol.HTTP;
import org.json.JSONException;
import org.json.JSONObject;
import java.io.BufferedReader;
import java.io.DataOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.net.CookieManager;
import java.net.CookiePolicy;
import java.net.HttpCookie;
import java.net.HttpURLConnection;
import java.net.MalformedURLException;
import java.net.SocketTimeoutException;
import java.net.URI;
import java.net.URL;
import java.net.URLEncoder;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.UUID;
import java.util.zip.Inflater;
import java.util.zip.InflaterInputStream;
public class Request {
private static final String TAG = "Request";
/**
* The following variables started with STATUS_ are request response status
* code to indicate callers what happens.
*/
// Status OK
public static final int STATUS_OK = 0;
// Server error, related to HTTPStatus 40X and 50X
public static final int STATUS_SERVER_ERROR = 1;
// Client error, include io
public static final int STATUS_CLIENT_ERROR = 2;
// Connection parameters error
public static final int STATUS_PARAM_ERROR = 3;
// Status network unavailable
public static final int STATUS_NETWORK_UNAVAILABLE = 4;
// Status service unavailable
public static final int STATUS_SERVICE_UNAVAILABLE = 5;
// Status unknown error
public static final int STATUS_UNKNOWN_ERROR = 6;
// NOT MODIFIED
public static final int STATUS_NOT_MODIFIED = 7;
// Auth error
public static final int STATUS_AUTH_ERROR = 8;
// Timeout (in ms) we specify for each http request
protected static final int HTTP_REQUEST_TIMEOUT_MS = 10 * 1000;
protected static final int HTTP_REQUEST_DELAY_MS = 5 * 1000;
private static final CookieManager sCookieManager = new CookieManager(null,
CookiePolicy.ACCEPT_ALL);
// The responsed json result and the user id and Auth token
private JSONObject mJSONResult;
private String mUserId;
private ExtendedAuthToken mToken;
private static String sUserAgent;
private static String sCookie;
private String mEtag;
// The parameters list
private List<NameValuePair> mParamsList;
protected String mRequestUrl;
private String mRequestMethod;
private boolean mNeedSignature;
private HashMap<String, String> mRequestHeaders;
public Request(String url) {
mRequestUrl = url;
mRequestMethod = HttpPost.METHOD_NAME;
mNeedSignature = false;
mRequestHeaders = new HashMap<String, String>();
}
public Request addHeader(String name, String value) {
mRequestHeaders.put(name, value);
return this;
}
public Request setHttpMethod(String method) {
mRequestMethod = method;
return this;
}
// Get the parameters which will be appended to the requested url
public void addParam(String key, String value) {
if (mParamsList == null) {
mParamsList = new ArrayList<NameValuePair>();
}
BasicNameValuePair param = new BasicNameValuePair(key, value);
if (!mParamsList.contains(param)) {
mParamsList.add(new BasicNameValuePair(key, value));
}
}
// Clear all parameters
public void clearParams() {
if (mParamsList != null) {
mParamsList.clear();
}
}
/**
* Weather the parameters required to be signed
*
* @param needed
* @return this
*/
public Request setNeedSignature(boolean needed) {
mNeedSignature = needed;
return this;
}
protected HttpURLConnection getConn() {
final String url = getRequestUrl();
if (TextUtils.isEmpty(url)) {
return null;
}
LogUtil.d(TAG, "getConn:The connection url is " + url);
HttpURLConnection conn = null;
try {
final URL req = new URL(url);
conn = (HttpURLConnection) req.openConnection();
conn.setReadTimeout(HTTP_REQUEST_TIMEOUT_MS);
conn.setConnectTimeout(HTTP_REQUEST_TIMEOUT_MS);
conn.setRequestMethod(mRequestMethod);
if (TextUtils.equals(mRequestMethod, HttpPost.METHOD_NAME)) {
conn.setDoOutput(true);
conn.setUseCaches(false);
}
String cookie = getCookies();
if (!TextUtils.isEmpty(cookie)) {
conn.setRequestProperty("Cookie", getCookies());
}
conn.setRequestProperty("User-Agent", getUserAgent());
if (mRequestHeaders != null && mRequestHeaders.size() > 0) {
Iterator iter = mRequestHeaders.entrySet().iterator();
while (iter.hasNext()) {
Map.Entry<String, String> entry = (Map.Entry<String, String>) iter.next();
conn.setRequestProperty(entry.getKey(), entry.getValue());
}
}
} catch (MalformedURLException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
return conn;
}
// 获取请求结果
public int getStatus() {
if (!Utils.Network.isNetWorkConnected(ShopApp.getContext())) {
return STATUS_NETWORK_UNAVAILABLE;
}
HttpURLConnection conn = null;
BufferedReader br = null;
int statusCode = STATUS_CLIENT_ERROR;
try {
conn = getConn();
// Connect to the server
conn.connect();
if (TextUtils.equals(mRequestMethod, HttpPost.METHOD_NAME)) {
DataOutputStream out = new DataOutputStream(conn.getOutputStream());
out.writeBytes(getParams());
out.flush();
}
// Check the response code
int responseCode = conn.getResponseCode();
LogUtil.d(TAG, "The response code is:" + responseCode);
if (responseCode == HttpStatus.SC_OK) {
String etag = conn.getHeaderField("etag");
if (!TextUtils.isEmpty(etag)) {
mEtag = etag;
}
String compressed = conn
.getHeaderField(HostManager.Parameters.Keys.COMPRESS_HEADER);
// Read cookie
putCookies(conn.getHeaderFields());
// Read response from the connection to after posting info
InputStream in = conn.getInputStream();
if (compressed != null && compressed.equals(HostManager.Parameters.Keys.COMPRESS)) {
Inflater inflater = new Inflater(true);
in = new InflaterInputStream(in, inflater);
}
br = new BufferedReader(new InputStreamReader(in));
StringBuilder sb = new StringBuilder();
String line = null;
while ((line = br.readLine()) != null) {
sb.append(line);
}
if (mNeedSignature) {
if (mToken != null && !TextUtils.isEmpty(mToken.security)) {
mJSONResult = new JSONObject(Coder.decodeAES(
sb.toString(), mToken.security));
statusCode = STATUS_OK;
} else {
statusCode = STATUS_PARAM_ERROR;
}
} else {
mJSONResult = new JSONObject(sb.toString());
statusCode = STATUS_OK;
}
} else if (responseCode == HttpStatus.SC_NOT_MODIFIED) {
statusCode = STATUS_NOT_MODIFIED;
} else if (isServerError(responseCode)) {
if (responseCode == HttpStatus.SC_UNAUTHORIZED) {
LoginManager.getInstance().invalidAuthToken();
statusCode = STATUS_AUTH_ERROR;
} else {
statusCode = STATUS_SERVER_ERROR;
}
} else {
statusCode = STATUS_UNKNOWN_ERROR;
}
} catch (SocketTimeoutException e) {
e.printStackTrace();
statusCode = STATUS_SERVICE_UNAVAILABLE;
} catch (JSONException e) {
statusCode = STATUS_SERVICE_UNAVAILABLE;
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
if (!Utils.Network.isNetWorkConnected(ShopApp.getContext())) {
statusCode = STATUS_NETWORK_UNAVAILABLE;
} else {
statusCode = STATUS_SERVICE_UNAVAILABLE;
}
} finally {
try {
if (br != null) {
br.close();
}
} catch (IOException e) {
e.printStackTrace();
}
if (conn != null) {
conn.disconnect();
}
}
LogUtil.d(TAG, "getStatus:The status code is " + statusCode);
LogUtil.d(TAG, "etag is " + conn.getHeaderField("etag"));
return statusCode;
}
// 获取请求的JSON数据
public JSONObject requestJSON() {
return mJSONResult;
}
protected boolean isServerError(int statusCode) {
return statusCode == HttpStatus.SC_BAD_REQUEST
|| statusCode == HttpStatus.SC_UNAUTHORIZED
|| statusCode == HttpStatus.SC_FORBIDDEN
|| statusCode == HttpStatus.SC_NOT_ACCEPTABLE
|| statusCode / 100 == 5;
}
protected List<NameValuePair> signParamters() {
return mParamsList;
}
private String getParams() {
List<NameValuePair> paramList = null;
if (mNeedSignature) {
paramList = signParamters();
} else {
paramList = mParamsList;
}
if (paramList == null) {
paramList = new ArrayList<NameValuePair>();
}
paramList.add(new BasicNameValuePair(Parameters.Keys.COMPRESS, "1"));
paramList.add(new BasicNameValuePair(Parameters.Keys.CLIENT_ID, Parameters.Values.CLIENT_ID));
paramList.add(new BasicNameValuePair(Parameters.Keys.DEVICE_DENSITY, String
.valueOf(Device.DISPLAY_DENSITY)));
paramList.add(new BasicNameValuePair(Parameters.Keys.VERSION,
String.valueOf(Device.SHOP_VERSION)));
return URLEncodedUtils.format(paramList, HTTP.UTF_8);
}
// The constructed url to requested
public String getRequestUrl() {
if (TextUtils.equals(mRequestMethod, HttpPost.METHOD_NAME)) {
return mRequestUrl + "?random=" + UUID.randomUUID().toString().replaceAll("-", "");
}
final String params = getParams();
return TextUtils.isEmpty(params) ? mRequestUrl : mRequestUrl.contains("?") ? String.format("%s&%s",
mRequestUrl,
params) : String.format("%s?%s", mRequestUrl,
params);
}
private String getUserAgent() {
if (sUserAgent == null) {
StringBuilder sb = new StringBuilder();
sb.append(Device.COUNTRY).append(";");
sb.append(Device.LANGUAGE).append(";");
sb.append(Device.SHOP_VERSION);
sUserAgent = sb.toString();
}
return sUserAgent;
}
private void putCookies(Map<String, List<String>> map) {
try {
sCookieManager.put(URI.create(mRequestUrl), map);
} catch (IOException e) {
e.printStackTrace();
}
}
private String getCookies() {
String userId = LoginManager.getInstance().getUserId();
ExtendedAuthToken token = LoginManager.getInstance().getExtendedAuthToken(
Constants.Account.DEFAULT_SERVICE_ID);
if (token == null) {
token = ExtendedAuthToken.build("", "");
}
if (!TextUtils.equals(userId, mUserId) || !token.equals(mToken)) {
mUserId = userId;
if (TextUtils.isEmpty(token.authToken)) {
mToken = null;
} else {
mToken = token;
}
sCookie = null;
}
// 如果Cookie有变化,同时UserId和authToken不为空,那么重新构造验证Cookie
if (!TextUtils.isEmpty(mUserId) && mToken != null && !TextUtils.isEmpty(mToken.authToken)
&& sCookie == null) {
StringBuilder sb = new StringBuilder();
sb.append("serviceToken=");
sb.append(URLEncoder.encode(mToken.authToken));
sb.append("; userId=");
sb.append(mUserId);
sCookie = sb.toString();
}
List<HttpCookie> cookieList = sCookieManager.getCookieStore().getCookies();
if (cookieList == null || cookieList.size() == 0) {
return sCookie;
}
StringBuilder sbCookie = new StringBuilder();
for (HttpCookie cookie : cookieList) {
if (TextUtils.indexOf(URI.create(mRequestUrl).getHost(), cookie.getDomain()) > 0) {
sbCookie.append(cookie.getName());
sbCookie.append("=");
sbCookie.append(cookie.getValue());
sbCookie.append("; ");
}
}
return sbCookie.toString() + sCookie;
}
public String getEtag() {
return mEtag;
}
}