void Send()

in tensorflow_io/core/filesystems/http/http_filesystem.cc [215:391]


  void Send(TF_Status* status) {
    CURLcode s = CURLE_OK;

    if (curl_headers_) {
      if ((s = curl_easy_setopt(curl_, CURLOPT_HTTPHEADER, curl_headers_)) !=
          CURLE_OK) {
        std::string error_message =
            absl::StrCat("Unable to set CURLOPT_HTTPHEADER: ", s);
        TF_SetStatus(status, TF_INTERNAL, error_message.c_str());
        return;
      }
    }
    if (resolve_list_) {
      if ((s = curl_easy_setopt(curl_, CURLOPT_RESOLVE, resolve_list_)) !=
          CURLE_OK) {
        std::string error_message =
            absl::StrCat("Unable to set CURLOPT_RESOLVE: ", s);
        TF_SetStatus(status, TF_INTERNAL, error_message.c_str());
        return;
      }
    }
    if ((s = curl_easy_setopt(curl_, CURLOPT_HEADERDATA,
                              reinterpret_cast<void*>(this))) != CURLE_OK) {
      std::string error_message =
          absl::StrCat("Unable to set CURLOPT_HEADERDATA: ", s);
      TF_SetStatus(status, TF_INTERNAL, error_message.c_str());
      return;
    }
    if ((s = curl_easy_setopt(curl_, CURLOPT_HEADERFUNCTION,
                              &CurlHttpRequest::HeaderCallback)) != CURLE_OK) {
      std::string error_message =
          absl::StrCat("Unable to set CURLOPT_HEADERFUNCTION: ", s);
      TF_SetStatus(status, TF_INTERNAL, error_message.c_str());
      return;
    }

    if ((s = curl_easy_setopt(curl_, CURLOPT_TIMEOUT, request_timeout_secs_)) !=
        CURLE_OK) {
      std::string error_message = absl::StrCat(
          "Unable to set CURLOPT_TIMEOUT (", request_timeout_secs_, "): ", s);
      TF_SetStatus(status, TF_INTERNAL, error_message.c_str());
      return;
    }
    if ((s = curl_easy_setopt(curl_, CURLOPT_CONNECTTIMEOUT,
                              connect_timeout_secs_)) != CURLE_OK) {
      std::string error_message =
          absl::StrCat("Unable to set CURLOPT_CONNECTTIMEOUT (",
                       connect_timeout_secs_, "): ", s);
      TF_SetStatus(status, TF_INTERNAL, error_message.c_str());
      return;
    }

    char error_buffer[CURL_ERROR_SIZE] = {0};
    if ((s = curl_easy_setopt(curl_, CURLOPT_ERRORBUFFER, error_buffer)) !=
        CURLE_OK) {
      std::string error_message =
          absl::StrCat("Unable to set CURLOPT_ERRORBUFFER: ", s);
      TF_SetStatus(status, TF_INTERNAL, error_message.c_str());
      return;
    }

    if ((s = curl_easy_perform(curl_)) != CURLE_OK) {
      std::string error_message =
          absl::StrCat("Unable to perform (", s, "): ", error_buffer);
      TF_SetStatus(status, TF_INTERNAL, error_message.c_str());
      return;
    }

    double written_size = 0;
    if ((s = curl_easy_getinfo(curl_, CURLINFO_SIZE_DOWNLOAD, &written_size)) !=
        CURLE_OK) {
      std::string error_message =
          absl::StrCat("Unable to set CURLINFO_SIZE_DOWNLOAD: ", s);
      TF_SetStatus(status, TF_INTERNAL, error_message.c_str());
      return;
    }

    if ((s = curl_easy_getinfo(curl_, CURLINFO_RESPONSE_CODE,
                               &response_code_)) != CURLE_OK) {
      std::string error_message =
          absl::StrCat("Unable to set CURLINFO_RESPONSE_CODE: ", s);
      TF_SetStatus(status, TF_INTERNAL, error_message.c_str());
      return;
    }

    auto get_error_message = [this]() -> std::string {
      std::string error_message =
          absl::StrCat("Error executing an HTTP request: HTTP response code ",
                       response_code_);
      absl::string_view body = GetResponse();
      if (!body.empty()) {
        return absl::StrCat(
            error_message, " with body '",
            body.substr(0, std::min(body.size(), response_to_error_limit_)),
            "'");
      }
      return error_message;
    };

    switch (response_code_) {
      // The group of response codes indicating that the request achieved
      // the expected goal.
      case 200:  // OK
      case 201:  // Created
      case 204:  // No Content
      case 206:  // Partial Content
        TF_SetStatus(status, TF_OK, "");
        break;

      case 416:  // Requested Range Not Satisfiable
        // The requested range had no overlap with the available range.
        // This doesn't indicate an error, but we should produce an empty
        // response body. (Not all servers do; GCS returns a short error message
        // body.)
        response_buffer_.clear();
        if (IsDirectResponse()) {
          direct_response_.bytes_transferred_ = 0;
        }
        TF_SetStatus(status, TF_OK, "");
        break;

      // INVALID_ARGUMENT indicates a problem with how the request is
      // constructed.
      case 400:  // Bad Request
      case 406:  // Not Acceptable
      case 411:  // Length Required
      case 414:  // URI Too Long
        TF_SetStatus(status, TF_INVALID_ARGUMENT, get_error_message().c_str());
        break;

      // PERMISSION_DENIED indicates an authentication or an authorization
      // issue.
      case 401:  // Unauthorized
      case 403:  // Forbidden
      case 407:  // Proxy Authorization Required
        TF_SetStatus(status, TF_PERMISSION_DENIED, get_error_message().c_str());
        break;

      // NOT_FOUND indicates that the requested resource does not exist.
      case 404:  // Not found
      case 410:  // Gone
        TF_SetStatus(status, TF_NOT_FOUND, get_error_message().c_str());
        break;

      // FAILED_PRECONDITION indicates that the request failed because some
      // of the underlying assumptions were not satisfied. The request
      // shouldn't be retried unless the external context has changed.
      case 302:  // Found
      case 303:  // See Other
      case 304:  // Not Modified
      case 307:  // Temporary Redirect
      case 412:  // Precondition Failed
      case 413:  // Payload Too Large
        TF_SetStatus(status, TF_FAILED_PRECONDITION,
                     get_error_message().c_str());
        break;

      // UNAVAILABLE indicates a problem that can go away if the request
      // is just retried without any modification. 308 return codes are intended
      // for write requests that can be retried. See the documentation and the
      // official library:
      // https://cloud.google.com/storage/docs/json_api/v1/how-tos/resumable-upload
      // https://github.com/google/apitools/blob/master/apitools/base/py/transfer.py
      case 308:  // Resume Incomplete
      case 409:  // Conflict
      case 429:  // Too Many Requests
      case 500:  // Internal Server Error
      case 502:  // Bad Gateway
      case 503:  // Service Unavailable
      default:   // All other HTTP response codes also should be retried.
        TF_SetStatus(status, TF_UNAVAILABLE, get_error_message().c_str());
        break;
    }
    if (TF_GetCode(status) != TF_OK) {
      response_buffer_.clear();
    }
  }