#include "content/browser/loader/detachable_resource_handler.h"
#include "base/logging.h"
+#include "base/metrics/histogram.h"
#include "base/time/time.h"
#include "content/browser/loader/resource_request_info_impl.h"
#include "net/base/io_buffer.h"
#include "net/url_request/url_request_status.h"
namespace {
+
// This matches the maximum allocation size of AsyncResourceHandler.
const int kReadBufSize = 32 * 1024;
-}
+
+// Enum type for <a ping> result histograms. Only add new values to the end.
+enum UMAPingResultType {
+ // The ping request completed successfully.
+ UMA_PING_RESULT_TYPE_SUCCESS = 0,
+ // The ping request received a response, but did not consume the entire body.
+ UMA_PING_RESULT_TYPE_RESPONSE_STARTED = 1,
+ // The ping request was canceled due to the internal timeout.
+ UMA_PING_RESULT_TYPE_TIMEDOUT = 2,
+ // The ping request was canceled for some other reason.
+ UMA_PING_RESULT_TYPE_CANCELED = 3,
+ // The ping request failed for some reason.
+ UMA_PING_RESULT_TYPE_FAILED = 4,
+ // The ping request was deleted before OnResponseCompleted.
+ UMA_PING_RESULT_TYPE_UNCOMPLETED = 5,
+
+ UMA_PING_RESULT_TYPE_MAX,
+};
+
+} // namespace
namespace content {
next_handler_(next_handler.Pass()),
cancel_delay_(cancel_delay),
is_deferred_(false),
- is_finished_(false) {
+ is_finished_(false),
+ timed_out_(false),
+ response_started_(false),
+ status_(net::URLRequestStatus::IO_PENDING) {
GetRequestInfo()->set_detachable_handler(this);
}
DetachableResourceHandler::~DetachableResourceHandler() {
// Cleanup back-pointer stored on the request info.
GetRequestInfo()->set_detachable_handler(NULL);
+
+ // Record the status of <a ping> requests.
+ // http://crbug.com/302816
+ if (GetRequestInfo()->GetResourceType() == ResourceType::PING) {
+ UMAPingResultType result_type = UMA_PING_RESULT_TYPE_MAX;
+
+ if (status_ == net::URLRequestStatus::SUCCESS) {
+ result_type = UMA_PING_RESULT_TYPE_SUCCESS;
+ } else if (response_started_) {
+ // However the request ended, bucket this under RESPONSE_STARTED because
+ // OnResponseStarted was received. Note: OnResponseCompleted is also sent
+ // when a request is canceled before completion, so it is possible to
+ // receive OnResponseCompleted without OnResponseStarted.
+ result_type = UMA_PING_RESULT_TYPE_RESPONSE_STARTED;
+ } else if (status_ == net::URLRequestStatus::IO_PENDING) {
+ // The request was deleted without OnResponseCompleted and before any
+ // response was received.
+ result_type = UMA_PING_RESULT_TYPE_UNCOMPLETED;
+ } else if (status_ == net::URLRequestStatus::CANCELED) {
+ if (timed_out_) {
+ result_type = UMA_PING_RESULT_TYPE_TIMEDOUT;
+ } else {
+ result_type = UMA_PING_RESULT_TYPE_CANCELED;
+ }
+ } else if (status_ == net::URLRequestStatus::FAILED) {
+ result_type = UMA_PING_RESULT_TYPE_FAILED;
+ }
+
+ if (result_type < UMA_PING_RESULT_TYPE_MAX) {
+ UMA_HISTOGRAM_ENUMERATION("Net.Ping_Result", result_type,
+ UMA_PING_RESULT_TYPE_MAX);
+ } else {
+ NOTREACHED();
+ }
+ }
}
void DetachableResourceHandler::Detach() {
// Time the request out if it takes too long.
detached_timer_.reset(new base::OneShotTimer<DetachableResourceHandler>());
detached_timer_->Start(
- FROM_HERE, cancel_delay_, this, &DetachableResourceHandler::Cancel);
+ FROM_HERE, cancel_delay_, this, &DetachableResourceHandler::TimedOut);
// Resume if necessary. The request may have been deferred, say, waiting on a
// full buffer in AsyncResourceHandler. Now that it has been detached, resume
ResourceResponse* response,
bool* defer) {
DCHECK(!is_deferred_);
+ DCHECK(!response_started_);
+ response_started_ = true;
+
+ // Record how long it takes for <a ping> to respond.
+ // http://crbug.com/302816
+ if (GetRequestInfo()->GetResourceType() == ResourceType::PING) {
+ UMA_HISTOGRAM_MEDIUM_TIMES("Net.Ping_ResponseStartedTime",
+ time_since_start_.Elapsed());
+ }
if (!next_handler_)
return true;
// No DCHECK(!is_deferred_) as the request may have been cancelled while
// deferred.
+ status_ = status.status();
+ DCHECK_NE(net::URLRequestStatus::IO_PENDING, status_);
+
if (!next_handler_)
return;
controller()->CancelWithError(error_code);
}
+void DetachableResourceHandler::TimedOut() {
+ timed_out_ = true;
+ controller()->Cancel();
+}
+
} // namespace content