aboutsummaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
authorGravatar A. Unique TensorFlower <gardener@tensorflow.org>2018-01-04 15:23:23 -0800
committerGravatar TensorFlower Gardener <gardener@tensorflow.org>2018-01-04 15:28:57 -0800
commit9fa14867a61e3434e1fc9442e7102c40c4b6b5f0 (patch)
treeeff309c4dc85ad31e0572e28779a47de44119e2b
parentcbcf14d4065b8ba713589cdb45b67e0d924315f6 (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.cc27
-rw-r--r--tensorflow/core/platform/cloud/curl_http_request.h7
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);
};