curl_http_request.h revision b1d89c147d079ab97356b6a677cbf5ee726313d6
1/* Copyright 2017 The TensorFlow Authors. All Rights Reserved. 2 3Licensed under the Apache License, Version 2.0 (the "License"); 4you may not use this file except in compliance with the License. 5You may obtain a copy of the License at 6 7 http://www.apache.org/licenses/LICENSE-2.0 8 9Unless required by applicable law or agreed to in writing, software 10distributed under the License is distributed on an "AS IS" BASIS, 11WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12See the License for the specific language governing permissions and 13limitations under the License. 14==============================================================================*/ 15 16#ifndef TENSORFLOW_CORE_PLATFORM_CLOUD_CURL_HTTP_REQUEST_H_ 17#define TENSORFLOW_CORE_PLATFORM_CLOUD_CURL_HTTP_REQUEST_H_ 18 19#include <string> 20#include <unordered_map> 21#include <vector> 22#include <curl/curl.h> 23#include "tensorflow/core/lib/core/errors.h" 24#include "tensorflow/core/lib/core/status.h" 25#include "tensorflow/core/lib/core/stringpiece.h" 26#include "tensorflow/core/platform/cloud/http_request.h" 27#include "tensorflow/core/platform/env.h" 28#include "tensorflow/core/platform/macros.h" 29#include "tensorflow/core/platform/protobuf.h" 30#include "tensorflow/core/platform/types.h" 31 32namespace tensorflow { 33 34class LibCurl; // libcurl interface as a class, for dependency injection. 35 36/// \brief A basic HTTP client based on the libcurl library. 37/// 38/// The usage pattern for the class reflects the one of the libcurl library: 39/// create a request object, set request parameters and call Send(). 40/// 41/// For example: 42/// std::unique_ptr<HttpRequest> request(http_request_factory->Create()); 43/// request->SetUri("http://www.google.com"); 44/// request->SetResultsBuffer(out_buffer); 45/// request->Send(); 46class CurlHttpRequest : public HttpRequest { 47 public: 48 class Factory : public HttpRequest::Factory { 49 public: 50 virtual ~Factory() {} 51 virtual HttpRequest* Create() { return new CurlHttpRequest(); } 52 }; 53 54 CurlHttpRequest(); 55 explicit CurlHttpRequest(LibCurl* libcurl) 56 : CurlHttpRequest(libcurl, Env::Default()) {} 57 CurlHttpRequest(LibCurl* libcurl, Env* env); 58 ~CurlHttpRequest() override; 59 60 Status Init() override; 61 62 /// Sets the request URI. 63 Status SetUri(const string& uri) override; 64 65 /// \brief Sets the Range header. 66 /// 67 /// Used for random seeks, for example "0-999" returns the first 1000 bytes 68 /// (note that the right border is included). 69 Status SetRange(uint64 start, uint64 end) override; 70 71 /// Sets a request header. 72 Status AddHeader(const string& name, const string& value) override; 73 74 Status AddResolveOverride(const string& hostname, int64 port, 75 const string& ip_addr) override; 76 77 /// Sets the 'Authorization' header to the value of 'Bearer ' + auth_token. 78 Status AddAuthBearerHeader(const string& auth_token) override; 79 80 /// Makes the request a DELETE request. 81 Status SetDeleteRequest() override; 82 83 /// \brief Makes the request a PUT request. 84 /// 85 /// The request body will be taken from the specified file starting from 86 /// the given offset. 87 Status SetPutFromFile(const string& body_filepath, size_t offset) override; 88 89 /// Makes the request a PUT request with an empty body. 90 Status SetPutEmptyBody() override; 91 92 /// \brief Makes the request a POST request. 93 /// 94 /// The request body will be taken from the specified buffer. 95 Status SetPostFromBuffer(const char* buffer, size_t size) override; 96 97 /// Makes the request a POST request with an empty body. 98 Status SetPostEmptyBody() override; 99 100 /// \brief Specifies the buffer for receiving the response body. 101 /// 102 /// Size of out_buffer after an access will be exactly the number of bytes 103 /// read. Existing content of the vector will be cleared. 104 Status SetResultBuffer(std::vector<char>* out_buffer) override; 105 106 /// \brief Returns the response headers of a completed request. 107 /// 108 /// If the header is not found, returns an empty string. 109 string GetResponseHeader(const string& name) const override; 110 111 /// Returns the response code of a completed request. 112 uint64 GetResponseCode() const override; 113 114 /// \brief Sends the formed request. 115 /// 116 /// If the result buffer was defined, the response will be written there. 117 /// The object is not designed to be re-used after Send() is executed. 118 Status Send() override; 119 120 // Url encodes str and returns a new string. 121 string EscapeString(const string& str) override; 122 123 private: 124 /// A write callback in the form which can be accepted by libcurl. 125 static size_t WriteCallback(const void* ptr, size_t size, size_t nmemb, 126 void* userdata); 127 /// A read callback in the form which can be accepted by libcurl. 128 static size_t ReadCallback(void* ptr, size_t size, size_t nmemb, 129 FILE* userdata); 130 /// A header callback in the form which can be accepted by libcurl. 131 static size_t HeaderCallback(const void* ptr, size_t size, size_t nmemb, 132 void* this_object); 133 /// A progress meter callback in the form which can be accepted by libcurl. 134 static int ProgressCallback(void* this_object, curl_off_t dltotal, 135 curl_off_t dlnow, curl_off_t ultotal, 136 curl_off_t ulnow); 137 Status CheckInitialized() const; 138 Status CheckMethodNotSet() const; 139 Status CheckNotSent() const; 140 141 LibCurl* libcurl_; 142 Env* env_; 143 144 FILE* put_body_ = nullptr; 145 146 StringPiece post_body_buffer_; 147 size_t post_body_read_ = 0; 148 149 std::vector<char>* response_buffer_ = nullptr; 150 CURL* curl_ = nullptr; 151 curl_slist* curl_headers_ = nullptr; 152 curl_slist* resolve_list_ = nullptr; 153 154 std::vector<char> default_response_buffer_; 155 156 std::unordered_map<string, string> response_headers_; 157 uint64 response_code_ = 0; 158 159 // The timestamp of the last activity related to the request execution, in 160 // seconds since epoch. 161 uint64 last_progress_timestamp_ = 0; 162 // The last progress in terms of bytes transmitted. 163 curl_off_t last_progress_bytes_ = 0; 164 165 // Members to enforce the usage flow. 166 bool is_initialized_ = false; 167 bool is_uri_set_ = false; 168 bool is_method_set_ = false; 169 bool is_sent_ = false; 170 171 TF_DISALLOW_COPY_AND_ASSIGN(CurlHttpRequest); 172}; 173 174/// \brief A proxy to the libcurl C interface as a dependency injection measure. 175/// 176/// This class is meant as a very thin wrapper for the libcurl C library. 177class LibCurl { 178 public: 179 virtual ~LibCurl() {} 180 181 virtual CURL* curl_easy_init() = 0; 182 virtual CURLcode curl_easy_setopt(CURL* curl, CURLoption option, 183 uint64 param) = 0; 184 virtual CURLcode curl_easy_setopt(CURL* curl, CURLoption option, 185 const char* param) = 0; 186 virtual CURLcode curl_easy_setopt(CURL* curl, CURLoption option, 187 void* param) = 0; 188 virtual CURLcode curl_easy_setopt(CURL* curl, CURLoption option, 189 size_t (*param)(void*, size_t, size_t, 190 FILE*)) = 0; 191 virtual CURLcode curl_easy_setopt(CURL* curl, CURLoption option, 192 size_t (*param)(const void*, size_t, size_t, 193 void*)) = 0; 194 virtual CURLcode curl_easy_setopt( 195 CURL* curl, CURLoption option, 196 int (*param)(void* clientp, curl_off_t dltotal, curl_off_t dlnow, 197 curl_off_t ultotal, curl_off_t ulnow)) = 0; 198 virtual CURLcode curl_easy_perform(CURL* curl) = 0; 199 virtual CURLcode curl_easy_getinfo(CURL* curl, CURLINFO info, 200 uint64* value) = 0; 201 virtual CURLcode curl_easy_getinfo(CURL* curl, CURLINFO info, 202 double* value) = 0; 203 virtual void curl_easy_cleanup(CURL* curl) = 0; 204 virtual curl_slist* curl_slist_append(curl_slist* list, const char* str) = 0; 205 virtual void curl_slist_free_all(curl_slist* list) = 0; 206 virtual char* curl_easy_escape(CURL* curl, const char* str, int length) = 0; 207 virtual void curl_free(void* p) = 0; 208}; 209 210} // namespace tensorflow 211 212#endif // TENSORFLOW_CORE_PLATFORM_CLOUD_CURL_HTTP_REQUEST_H_ 213