libcurl_http_fetcher.h 9.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277
  1. //
  2. // Copyright (C) 2009 The Android Open Source Project
  3. //
  4. // Licensed under the Apache License, Version 2.0 (the "License");
  5. // you may not use this file except in compliance with the License.
  6. // You may obtain a copy of the License at
  7. //
  8. // http://www.apache.org/licenses/LICENSE-2.0
  9. //
  10. // Unless required by applicable law or agreed to in writing, software
  11. // distributed under the License is distributed on an "AS IS" BASIS,
  12. // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  13. // See the License for the specific language governing permissions and
  14. // limitations under the License.
  15. //
  16. #ifndef UPDATE_ENGINE_LIBCURL_HTTP_FETCHER_H_
  17. #define UPDATE_ENGINE_LIBCURL_HTTP_FETCHER_H_
  18. #include <map>
  19. #include <memory>
  20. #include <string>
  21. #include <utility>
  22. #include <curl/curl.h>
  23. #include <base/logging.h>
  24. #include <base/macros.h>
  25. #include <brillo/message_loops/message_loop.h>
  26. #include "update_engine/certificate_checker.h"
  27. #include "update_engine/common/hardware_interface.h"
  28. #include "update_engine/common/http_fetcher.h"
  29. // This is a concrete implementation of HttpFetcher that uses libcurl to do the
  30. // http work.
  31. namespace chromeos_update_engine {
  32. class LibcurlHttpFetcher : public HttpFetcher {
  33. public:
  34. LibcurlHttpFetcher(ProxyResolver* proxy_resolver,
  35. HardwareInterface* hardware);
  36. // Cleans up all internal state. Does not notify delegate
  37. ~LibcurlHttpFetcher() override;
  38. void SetOffset(off_t offset) override { bytes_downloaded_ = offset; }
  39. void SetLength(size_t length) override { download_length_ = length; }
  40. void UnsetLength() override { SetLength(0); }
  41. // Begins the transfer if it hasn't already begun.
  42. void BeginTransfer(const std::string& url) override;
  43. // If the transfer is in progress, aborts the transfer early. The transfer
  44. // cannot be resumed.
  45. void TerminateTransfer() override;
  46. // Pass the headers to libcurl.
  47. void SetHeader(const std::string& header_name,
  48. const std::string& header_value) override;
  49. // Suspend the transfer by calling curl_easy_pause(CURLPAUSE_ALL).
  50. void Pause() override;
  51. // Resume the transfer by calling curl_easy_pause(CURLPAUSE_CONT).
  52. void Unpause() override;
  53. // Libcurl sometimes asks to be called back after some time while
  54. // leaving that time unspecified. In that case, we pick a reasonable
  55. // default of one second, but it can be overridden here. This is
  56. // primarily useful for testing.
  57. // From http://curl.haxx.se/libcurl/c/curl_multi_timeout.html:
  58. // if libcurl returns a -1 timeout here, it just means that libcurl
  59. // currently has no stored timeout value. You must not wait too long
  60. // (more than a few seconds perhaps) before you call
  61. // curl_multi_perform() again.
  62. void set_idle_seconds(int seconds) override { idle_seconds_ = seconds; }
  63. // Sets the retry timeout. Useful for testing.
  64. void set_retry_seconds(int seconds) override { retry_seconds_ = seconds; }
  65. void set_no_network_max_retries(int retries) {
  66. no_network_max_retries_ = retries;
  67. }
  68. void set_server_to_check(ServerToCheck server_to_check) {
  69. server_to_check_ = server_to_check;
  70. }
  71. size_t GetBytesDownloaded() override {
  72. return static_cast<size_t>(bytes_downloaded_);
  73. }
  74. void set_low_speed_limit(int low_speed_bps, int low_speed_sec) override {
  75. low_speed_limit_bps_ = low_speed_bps;
  76. low_speed_time_seconds_ = low_speed_sec;
  77. }
  78. void set_connect_timeout(int connect_timeout_seconds) override {
  79. connect_timeout_seconds_ = connect_timeout_seconds;
  80. }
  81. void set_max_retry_count(int max_retry_count) override {
  82. max_retry_count_ = max_retry_count;
  83. }
  84. private:
  85. // libcurl's CURLOPT_CLOSESOCKETFUNCTION callback function. Called when
  86. // closing a socket created with the CURLOPT_OPENSOCKETFUNCTION callback.
  87. static int LibcurlCloseSocketCallback(void* clientp, curl_socket_t item);
  88. // Callback for when proxy resolution has completed. This begins the
  89. // transfer.
  90. void ProxiesResolved();
  91. // Asks libcurl for the http response code and stores it in the object.
  92. void GetHttpResponseCode();
  93. // Checks whether stored HTTP response is within the success range.
  94. inline bool IsHttpResponseSuccess() {
  95. return (http_response_code_ >= 200 && http_response_code_ < 300);
  96. }
  97. // Checks whether stored HTTP response is within the error range. This
  98. // includes both errors with the request (4xx) and server errors (5xx).
  99. inline bool IsHttpResponseError() {
  100. return (http_response_code_ >= 400 && http_response_code_ < 600);
  101. }
  102. // Resumes a transfer where it left off. This will use the
  103. // HTTP Range: header to make a new connection from where the last
  104. // left off.
  105. virtual void ResumeTransfer(const std::string& url);
  106. void TimeoutCallback();
  107. void RetryTimeoutCallback();
  108. // Calls into curl_multi_perform to let libcurl do its work. Returns after
  109. // curl_multi_perform is finished, which may actually be after more than
  110. // one call to curl_multi_perform. This method will set up the message
  111. // loop with sources for future work that libcurl will do, if any, or complete
  112. // the transfer and finish the action if no work left to do.
  113. // This method will not block.
  114. void CurlPerformOnce();
  115. // Sets up message loop sources as needed by libcurl. This is generally
  116. // the file descriptor of the socket and a timer in case nothing happens
  117. // on the fds.
  118. void SetupMessageLoopSources();
  119. // Callback called by libcurl when new data has arrived on the transfer
  120. size_t LibcurlWrite(void* ptr, size_t size, size_t nmemb);
  121. static size_t StaticLibcurlWrite(void* ptr,
  122. size_t size,
  123. size_t nmemb,
  124. void* stream) {
  125. return reinterpret_cast<LibcurlHttpFetcher*>(stream)->LibcurlWrite(
  126. ptr, size, nmemb);
  127. }
  128. // Cleans up the following if they are non-null:
  129. // curl(m) handles, fd_task_maps_, timeout_id_.
  130. void CleanUp();
  131. // Force terminate the transfer. This will invoke the delegate's (if any)
  132. // TransferTerminated callback so, after returning, this fetcher instance may
  133. // be destroyed.
  134. void ForceTransferTermination();
  135. // Sets the curl options for HTTP URL.
  136. void SetCurlOptionsForHttp();
  137. // Sets the curl options for HTTPS URL.
  138. void SetCurlOptionsForHttps();
  139. // Sets the curl options for file URI.
  140. void SetCurlOptionsForFile();
  141. // Convert a proxy URL into a curl proxy type, if applicable. Returns true iff
  142. // conversion was successful, false otherwise (in which case nothing is
  143. // written to |out_type|).
  144. bool GetProxyType(const std::string& proxy, curl_proxytype* out_type);
  145. // Hardware interface used to query dev-mode and official build settings.
  146. HardwareInterface* hardware_;
  147. // Handles for the libcurl library
  148. CURLM* curl_multi_handle_{nullptr};
  149. CURL* curl_handle_{nullptr};
  150. struct curl_slist* curl_http_headers_{nullptr};
  151. // The extra headers that will be sent on each request.
  152. std::map<std::string, std::string> extra_headers_;
  153. // Lists of all read(0)/write(1) file descriptors that we're waiting on from
  154. // the message loop. libcurl may open/close descriptors and switch their
  155. // directions so maintain two separate lists so that watch conditions can be
  156. // set appropriately.
  157. std::map<int, brillo::MessageLoop::TaskId> fd_task_maps_[2];
  158. // The TaskId of the timer we're waiting on. kTaskIdNull if we are not waiting
  159. // on it.
  160. brillo::MessageLoop::TaskId timeout_id_{brillo::MessageLoop::kTaskIdNull};
  161. bool transfer_in_progress_{false};
  162. bool transfer_paused_{false};
  163. // Whether it should ignore transfer failures for the purpose of retrying the
  164. // connection.
  165. bool ignore_failure_{false};
  166. // Whether we should restart the transfer once Unpause() is called. This can
  167. // be caused because either the connection dropped while pause or the proxy
  168. // was resolved and we never started the transfer in the first place.
  169. bool restart_transfer_on_unpause_{false};
  170. // The transfer size. -1 if not known.
  171. off_t transfer_size_{0};
  172. // How many bytes have been downloaded and sent to the delegate.
  173. off_t bytes_downloaded_{0};
  174. // The remaining maximum number of bytes to download. Zero represents an
  175. // unspecified length.
  176. size_t download_length_{0};
  177. // If we resumed an earlier transfer, data offset that we used for the
  178. // new connection. 0 otherwise.
  179. // In this class, resume refers to resuming a dropped HTTP connection,
  180. // not to resuming an interrupted download.
  181. off_t resume_offset_{0};
  182. // Number of resumes performed so far and the max allowed.
  183. int retry_count_{0};
  184. int max_retry_count_{kDownloadMaxRetryCount};
  185. // Seconds to wait before retrying a resume.
  186. int retry_seconds_{20};
  187. // When waiting for a retry, the task id of the retry callback.
  188. brillo::MessageLoop::TaskId retry_task_id_{brillo::MessageLoop::kTaskIdNull};
  189. // Number of resumes due to no network (e.g., HTTP response code 0).
  190. int no_network_retry_count_{0};
  191. int no_network_max_retries_{0};
  192. // Seconds to wait before asking libcurl to "perform".
  193. int idle_seconds_{1};
  194. // If true, we are currently performing a write callback on the delegate.
  195. bool in_write_callback_{false};
  196. // If true, we have returned at least one byte in the write callback
  197. // to the delegate.
  198. bool sent_byte_{false};
  199. // We can't clean everything up while we're in a write callback, so
  200. // if we get a terminate request, queue it until we can handle it.
  201. bool terminate_requested_{false};
  202. // The ServerToCheck used when checking this connection's certificate. If no
  203. // certificate check needs to be performed, this should be set to
  204. // ServerToCheck::kNone.
  205. ServerToCheck server_to_check_{ServerToCheck::kNone};
  206. int low_speed_limit_bps_{kDownloadLowSpeedLimitBps};
  207. int low_speed_time_seconds_{kDownloadLowSpeedTimeSeconds};
  208. int connect_timeout_seconds_{kDownloadConnectTimeoutSeconds};
  209. DISALLOW_COPY_AND_ASSIGN(LibcurlHttpFetcher);
  210. };
  211. } // namespace chromeos_update_engine
  212. #endif // UPDATE_ENGINE_LIBCURL_HTTP_FETCHER_H_