diff options
author | A. Unique TensorFlower <gardener@tensorflow.org> | 2018-01-04 15:23:23 -0800 |
---|---|---|
committer | TensorFlower Gardener <gardener@tensorflow.org> | 2018-01-04 15:28:57 -0800 |
commit | 9fa14867a61e3434e1fc9442e7102c40c4b6b5f0 (patch) | |
tree | eff309c4dc85ad31e0572e28779a47de44119e2b | |
parent | cbcf14d4065b8ba713589cdb45b67e0d924315f6 (diff) |
Make 403 errors due to GCS more verbose.
The current GCS client code neglects to print the nature of a 403 error. For
example, a 403 error can occur because of permissions or rate limiting. The
nature of a 403 error is communicated through the HTTP response. Thus, this
patch extends the 403 error message with the HTTP response returned by curl.
As an example, a 403 error looked like this before this patch:
PermissionDeniedError: Error executing an HTTP request (HTTP response code 403, error code 0, error message '')
With this patch, it might look like:
PermissionDeniedError: Error executing an HTTP request (HTTP response code 403, error code 0, error message ''), response {
"error": {
"errors": [
{
"domain": "usageLimits",
"reason": "userRateLimitExceeded",
"message": "User Rate Limit Exceeded"
}
],
"code": 403,
"message": "User Rate Limit Exceeded"
}
}
PiperOrigin-RevId: 180853399
-rw-r--r-- | tensorflow/core/platform/cloud/curl_http_request.cc | 27 | ||||
-rw-r--r-- | tensorflow/core/platform/cloud/curl_http_request.h | 7 |
2 files changed, 33 insertions, 1 deletions
diff --git a/tensorflow/core/platform/cloud/curl_http_request.cc b/tensorflow/core/platform/cloud/curl_http_request.cc index 9c52401802..88a5d1e96d 100644 --- a/tensorflow/core/platform/cloud/curl_http_request.cc +++ b/tensorflow/core/platform/cloud/curl_http_request.cc @@ -305,6 +305,10 @@ void CurlHttpRequest::SetResultBufferDirect(char* buffer, size_t size) { &CurlHttpRequest::WriteCallbackDirect); } +bool CurlHttpRequest::IsDirectResponse() const { + return direct_response_.buffer_ != nullptr; +} + size_t CurlHttpRequest::WriteCallbackDirect(const void* ptr, size_t size, size_t nmemb, void* userdata) { CHECK(ptr != nullptr); @@ -431,6 +435,8 @@ Status CurlHttpRequest::Send() { ", error code ", curl_result, ", error message '", error_buffer, "')"); Status result; + StringPiece response = GetResponse(); + string extended_error_message; switch (response_code_) { // The group of response codes indicating that the request achieved // the expected goal. @@ -463,7 +469,15 @@ Status CurlHttpRequest::Send() { // PERMISSION_DENIED indicates an authentication or an authorization issue. case 401: // Unauthorized case 403: // Forbidden - result = errors::PermissionDenied(error_message); + if (!response.empty()) { + extended_error_message = strings::StrCat( + error_message, ", response ", + response.substr( + 0, std::min(response.size(), response_to_error_limit_))); + result = errors::PermissionDenied(extended_error_message); + } else { + result = errors::PermissionDenied(error_message); + } break; // NOT_FOUND indicates that the requested resource does not exist. @@ -510,6 +524,17 @@ void CurlHttpRequest::CheckNotSent() const { CHECK(!is_sent_) << "The request has already been sent."; } +StringPiece CurlHttpRequest::GetResponse() const { + StringPiece response; + if (IsDirectResponse()) { + response = StringPiece(direct_response_.buffer_, + direct_response_.bytes_transferred_); + } else { + response = StringPiece(response_buffer_->data(), response_buffer_->size()); + } + return response; +} + string CurlHttpRequest::GetResponseHeader(const string& name) const { const auto& header = response_headers_.find(name); return header != response_headers_.end() ? header->second : ""; diff --git a/tensorflow/core/platform/cloud/curl_http_request.h b/tensorflow/core/platform/cloud/curl_http_request.h index 9ad4bd35ae..cfa26f2b79 100644 --- a/tensorflow/core/platform/cloud/curl_http_request.h +++ b/tensorflow/core/platform/cloud/curl_http_request.h @@ -113,6 +113,9 @@ class CurlHttpRequest : public HttpRequest { /// Using this method is mutually exclusive with using SetResultBuffer(). void SetResultBufferDirect(char* buffer, size_t size) override; + /// \brief Distinguish response type (direct vs. implicit). + bool IsDirectResponse() const; + /// \brief Returns the number of bytes (of the response body) that were /// transferred, when using the SetResultBufferDirect() method. The returned /// value will always be less than or equal to the 'size' parameter that @@ -160,6 +163,7 @@ class CurlHttpRequest : public HttpRequest { curl_off_t ulnow); void CheckMethodNotSet() const; void CheckNotSent() const; + StringPiece GetResponse() const; LibCurl* libcurl_; Env* env_; @@ -210,6 +214,9 @@ class CurlHttpRequest : public HttpRequest { // Store the URI to help disambiguate requests when errors occur. string uri_; + // Limit the size of a http response that is copied into an error message. + const size_t response_to_error_limit_ = 500; + TF_DISALLOW_COPY_AND_ASSIGN(CurlHttpRequest); }; |