/*
* Copyright 2010-2016 Amazon.com, Inc. or its affiliates. All Rights Reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License").
* You may not use this file except in compliance with the License.
* A copy of the License is located at
*
* http://aws.amazon.com/apache2.0
*
* or in the "license" file accompanying this file. This file 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.amazonaws.mobileconnectors.amazonmobileanalytics.internal.core.http;
import android.util.Log;
import com.amazonaws.handlers.RequestHandler2;
import com.amazonaws.mobileconnectors.amazonmobileanalytics.AnalyticsEvent;
import com.amazonaws.mobileconnectors.amazonmobileanalytics.internal.core.system.Connectivity;
import com.amazonaws.mobileconnectors.amazonmobileanalytics.internal.core.util.DateUtil;
import com.amazonaws.mobileconnectors.amazonmobileanalytics.internal.core.util.StringUtil;
import com.amazonaws.mobileconnectors.amazonmobileanalytics.internal.event.InternalEventClient;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.text.DateFormat;
import java.util.Date;
import java.util.Map;
public class RequestTimingHandler extends RequestHandler2 {
private static final String TAG = "RequestTimingHandler";
public static final String REQUESTTIME_HEADER = "x-amzn-RequestTime";
public static final String REQUESTATTEMPTS_HEADER = "x-amzn-RequestAttempts";
public static final String SERVERINFO_HEADER = "x-amzn-ServerInfo";
private static final String TIMEZONE_FORMAT = "Z";
private DateFormat df;
private final InternalEventClient eventClient;
private final Connectivity connectivity;
private long startTime;
private int contentLength;
public RequestTimingHandler(final Connectivity connectivity,
final InternalEventClient eventClient) {
df = DateUtil.createLocaleIndependentDateFormatter(TIMEZONE_FORMAT);
this.eventClient = eventClient;
this.connectivity = connectivity;
}
private synchronized String getTimeZone() {
// TODO: Add clockskew
return df.format(new Date());
}
@Override
public void afterError(com.amazonaws.Request<?> request, com.amazonaws.Response<?> response,
Exception exception) {
}
@Override
public void afterResponse(com.amazonaws.Request<?> request, com.amazonaws.Response<?> response) {
try {
if (response == null) {
return;
}
Map<String, String> headers = response.getHttpResponse().getHeaders();
String responseTimeStr = headers.get(REQUESTTIME_HEADER);
long responseTime = startTime - System.currentTimeMillis();
if (responseTimeStr != null && responseTimeStr.trim().length() > 0) {
try {
responseTime = Long.parseLong(responseTimeStr.trim());
} catch (NumberFormatException e) {
}
}
double responseDouble = -1;
try {
responseDouble = Double.valueOf(Long.toString(responseTime));
} catch (NumberFormatException numberFormatException) {
Log.e(TAG, "Couldn't convert response time to double format", numberFormatException);
}
String requestAttemptsStr = headers.get(REQUESTATTEMPTS_HEADER);
double requestAttempts = 0;
if (requestAttemptsStr != null && requestAttemptsStr.trim().length() > 0) {
try {
requestAttempts = Double.parseDouble(requestAttemptsStr.trim());
} catch (NumberFormatException e) {
}
}
String serverInfo = headers.get(SERVERINFO_HEADER);
if (!StringUtil.isNullOrEmpty(responseTimeStr)) {
if (eventClient == null) {
return;
}
AnalyticsEvent recordEvent = eventClient
.createEvent("_httpRequestTiming")
.withAttribute("url", request.getEndpoint().toURL().toString())
.withAttribute("responseCode",
Integer.toString(response.getHttpResponse().getStatusCode()))
.withAttribute("timeZone", getTimeZone())
.withMetric("attempts", requestAttempts)
.withMetric("totalTime", responseDouble)
.withMetric("requestSize", (double) contentLength);
String connectionType = "UNKNOWN";
if (connectivity != null) {
if (connectivity.hasWifi()) {
connectionType = "WIFI";
} else if (connectivity.hasWAN()) {
connectionType = "WAN";
}
}
recordEvent.withAttribute("network", connectionType);
if (serverInfo != null) {
recordEvent.withAttribute("serverInfo", serverInfo);
}
eventClient.recordEvent(recordEvent);
}
} catch (Exception e) {
Log.e(TAG, "Unable to record _RequestTime event", e);
}
}
@Override
public void beforeRequest(com.amazonaws.Request<?> request) {
// TODO: factor in clockskew
startTime = System.currentTimeMillis();
ByteArrayOutputStream baos = new ByteArrayOutputStream();
InputStream is = request.getContent();
int currentByte = 0;
try {
while ((currentByte = is.read()) != -1) {
baos.write(currentByte);
}
contentLength = baos.size();
request.setContent(new ByteArrayInputStream(baos.toByteArray()));
} catch (IOException e) {
Log.e(TAG, "Cannot read content of request");
throw new RuntimeException(e);
}
}
}