libcurl_http_fetcher.h revision 9bbd18757660a09fb8831147b17916df8a3212e5
149fdf1889b965be25f929eeebc5b60cd40b9043rspangler@google.com// Copyright (c) 2009 The Chromium OS Authors. All rights reserved. 249fdf1889b965be25f929eeebc5b60cd40b9043rspangler@google.com// Use of this source code is governed by a BSD-style license that can be 349fdf1889b965be25f929eeebc5b60cd40b9043rspangler@google.com// found in the LICENSE file. 449fdf1889b965be25f929eeebc5b60cd40b9043rspangler@google.com 5c98a7edf648aad88b3f66df3b5a7d43d6a6d7fa9adlr@google.com#ifndef CHROMEOS_PLATFORM_UPDATE_ENGINE_LIBCURL_HTTP_FETCHER_H__ 6c98a7edf648aad88b3f66df3b5a7d43d6a6d7fa9adlr@google.com#define CHROMEOS_PLATFORM_UPDATE_ENGINE_LIBCURL_HTTP_FETCHER_H__ 749fdf1889b965be25f929eeebc5b60cd40b9043rspangler@google.com 849fdf1889b965be25f929eeebc5b60cd40b9043rspangler@google.com#include <map> 949fdf1889b965be25f929eeebc5b60cd40b9043rspangler@google.com#include <string> 1049fdf1889b965be25f929eeebc5b60cd40b9043rspangler@google.com#include <curl/curl.h> 1149fdf1889b965be25f929eeebc5b60cd40b9043rspangler@google.com#include <glib.h> 1249fdf1889b965be25f929eeebc5b60cd40b9043rspangler@google.com#include "base/basictypes.h" 13c98a7edf648aad88b3f66df3b5a7d43d6a6d7fa9adlr@google.com#include "chromeos/obsolete_logging.h" 1449fdf1889b965be25f929eeebc5b60cd40b9043rspangler@google.com#include "update_engine/http_fetcher.h" 1549fdf1889b965be25f929eeebc5b60cd40b9043rspangler@google.com 1649fdf1889b965be25f929eeebc5b60cd40b9043rspangler@google.com// This is a concrete implementation of HttpFetcher that uses libcurl to do the 1749fdf1889b965be25f929eeebc5b60cd40b9043rspangler@google.com// http work. 1849fdf1889b965be25f929eeebc5b60cd40b9043rspangler@google.com 1949fdf1889b965be25f929eeebc5b60cd40b9043rspangler@google.comnamespace chromeos_update_engine { 2049fdf1889b965be25f929eeebc5b60cd40b9043rspangler@google.com 2149fdf1889b965be25f929eeebc5b60cd40b9043rspangler@google.comclass LibcurlHttpFetcher : public HttpFetcher { 2249fdf1889b965be25f929eeebc5b60cd40b9043rspangler@google.com public: 2349fdf1889b965be25f929eeebc5b60cd40b9043rspangler@google.com LibcurlHttpFetcher() 2449fdf1889b965be25f929eeebc5b60cd40b9043rspangler@google.com : curl_multi_handle_(NULL), curl_handle_(NULL), 2549fdf1889b965be25f929eeebc5b60cd40b9043rspangler@google.com timeout_source_(NULL), transfer_in_progress_(false), 269bbd18757660a09fb8831147b17916df8a3212e5Andrew de los Reyes retry_count_(0), idle_ms_(1000) {} 2749fdf1889b965be25f929eeebc5b60cd40b9043rspangler@google.com 2849fdf1889b965be25f929eeebc5b60cd40b9043rspangler@google.com // Cleans up all internal state. Does not notify delegate 2949fdf1889b965be25f929eeebc5b60cd40b9043rspangler@google.com ~LibcurlHttpFetcher(); 3049fdf1889b965be25f929eeebc5b60cd40b9043rspangler@google.com 3149fdf1889b965be25f929eeebc5b60cd40b9043rspangler@google.com // Begins the transfer if it hasn't already begun. 3249fdf1889b965be25f929eeebc5b60cd40b9043rspangler@google.com virtual void BeginTransfer(const std::string& url); 3349fdf1889b965be25f929eeebc5b60cd40b9043rspangler@google.com 3449fdf1889b965be25f929eeebc5b60cd40b9043rspangler@google.com // If the transfer is in progress, aborts the transfer early. 3549fdf1889b965be25f929eeebc5b60cd40b9043rspangler@google.com // The transfer cannot be resumed. 3649fdf1889b965be25f929eeebc5b60cd40b9043rspangler@google.com virtual void TerminateTransfer(); 3749fdf1889b965be25f929eeebc5b60cd40b9043rspangler@google.com 3849fdf1889b965be25f929eeebc5b60cd40b9043rspangler@google.com // Suspend the transfer by calling curl_easy_pause(CURLPAUSE_ALL). 3949fdf1889b965be25f929eeebc5b60cd40b9043rspangler@google.com virtual void Pause(); 4049fdf1889b965be25f929eeebc5b60cd40b9043rspangler@google.com 4149fdf1889b965be25f929eeebc5b60cd40b9043rspangler@google.com // Resume the transfer by calling curl_easy_pause(CURLPAUSE_CONT). 4249fdf1889b965be25f929eeebc5b60cd40b9043rspangler@google.com virtual void Unpause(); 4349fdf1889b965be25f929eeebc5b60cd40b9043rspangler@google.com 4449fdf1889b965be25f929eeebc5b60cd40b9043rspangler@google.com // Libcurl sometimes asks to be called back after some time while 4549fdf1889b965be25f929eeebc5b60cd40b9043rspangler@google.com // leaving that time unspecified. In that case, we pick a reasonable 4649fdf1889b965be25f929eeebc5b60cd40b9043rspangler@google.com // default of one second, but it can be overridden here. This is 4749fdf1889b965be25f929eeebc5b60cd40b9043rspangler@google.com // primarily useful for testing. 4849fdf1889b965be25f929eeebc5b60cd40b9043rspangler@google.com // From http://curl.haxx.se/libcurl/c/curl_multi_timeout.html: 4949fdf1889b965be25f929eeebc5b60cd40b9043rspangler@google.com // if libcurl returns a -1 timeout here, it just means that libcurl 5049fdf1889b965be25f929eeebc5b60cd40b9043rspangler@google.com // currently has no stored timeout value. You must not wait too long 5149fdf1889b965be25f929eeebc5b60cd40b9043rspangler@google.com // (more than a few seconds perhaps) before you call 5249fdf1889b965be25f929eeebc5b60cd40b9043rspangler@google.com // curl_multi_perform() again. 5349fdf1889b965be25f929eeebc5b60cd40b9043rspangler@google.com void set_idle_ms(long ms) { 5449fdf1889b965be25f929eeebc5b60cd40b9043rspangler@google.com idle_ms_ = ms; 5549fdf1889b965be25f929eeebc5b60cd40b9043rspangler@google.com } 5649fdf1889b965be25f929eeebc5b60cd40b9043rspangler@google.com private: 57c98a7edf648aad88b3f66df3b5a7d43d6a6d7fa9adlr@google.com // Resumes a transfer where it left off. This will use the 58c98a7edf648aad88b3f66df3b5a7d43d6a6d7fa9adlr@google.com // HTTP Range: header to make a new connection from where the last 59c98a7edf648aad88b3f66df3b5a7d43d6a6d7fa9adlr@google.com // left off. 60c98a7edf648aad88b3f66df3b5a7d43d6a6d7fa9adlr@google.com virtual void ResumeTransfer(const std::string& url); 6149fdf1889b965be25f929eeebc5b60cd40b9043rspangler@google.com 6249fdf1889b965be25f929eeebc5b60cd40b9043rspangler@google.com // These two methods are for glib main loop callbacks. They are called 6349fdf1889b965be25f929eeebc5b60cd40b9043rspangler@google.com // when either a file descriptor is ready for work or when a timer 6449fdf1889b965be25f929eeebc5b60cd40b9043rspangler@google.com // has fired. The static versions are shims for libcurl which has a C API. 6549fdf1889b965be25f929eeebc5b60cd40b9043rspangler@google.com bool FDCallback(GIOChannel *source, GIOCondition condition); 6649fdf1889b965be25f929eeebc5b60cd40b9043rspangler@google.com static gboolean StaticFDCallback(GIOChannel *source, 6749fdf1889b965be25f929eeebc5b60cd40b9043rspangler@google.com GIOCondition condition, 6849fdf1889b965be25f929eeebc5b60cd40b9043rspangler@google.com gpointer data) { 6949fdf1889b965be25f929eeebc5b60cd40b9043rspangler@google.com return reinterpret_cast<LibcurlHttpFetcher*>(data)->FDCallback(source, 7049fdf1889b965be25f929eeebc5b60cd40b9043rspangler@google.com condition); 7149fdf1889b965be25f929eeebc5b60cd40b9043rspangler@google.com } 723270f7411f55b872db385d0edffdfed18a684121Andrew de los Reyes gboolean TimeoutCallback(); 7349fdf1889b965be25f929eeebc5b60cd40b9043rspangler@google.com static gboolean StaticTimeoutCallback(gpointer data) { 7449fdf1889b965be25f929eeebc5b60cd40b9043rspangler@google.com return reinterpret_cast<LibcurlHttpFetcher*>(data)->TimeoutCallback(); 7549fdf1889b965be25f929eeebc5b60cd40b9043rspangler@google.com } 769bbd18757660a09fb8831147b17916df8a3212e5Andrew de los Reyes 779bbd18757660a09fb8831147b17916df8a3212e5Andrew de los Reyes gboolean RetryTimeoutCallback(); 789bbd18757660a09fb8831147b17916df8a3212e5Andrew de los Reyes static gboolean StaticRetryTimeoutCallback(void* arg) { 799bbd18757660a09fb8831147b17916df8a3212e5Andrew de los Reyes return static_cast<LibcurlHttpFetcher*>(arg)->RetryTimeoutCallback(); 809bbd18757660a09fb8831147b17916df8a3212e5Andrew de los Reyes } 8149fdf1889b965be25f929eeebc5b60cd40b9043rspangler@google.com 8249fdf1889b965be25f929eeebc5b60cd40b9043rspangler@google.com // Calls into curl_multi_perform to let libcurl do its work. Returns after 8349fdf1889b965be25f929eeebc5b60cd40b9043rspangler@google.com // curl_multi_perform is finished, which may actually be after more than 8449fdf1889b965be25f929eeebc5b60cd40b9043rspangler@google.com // one call to curl_multi_perform. This method will set up the glib run 8549fdf1889b965be25f929eeebc5b60cd40b9043rspangler@google.com // loop with sources for future work that libcurl will do. 8649fdf1889b965be25f929eeebc5b60cd40b9043rspangler@google.com // This method will not block. 873270f7411f55b872db385d0edffdfed18a684121Andrew de los Reyes // Returns true if we should resume immediately after this call. 883270f7411f55b872db385d0edffdfed18a684121Andrew de los Reyes bool CurlPerformOnce(); 8949fdf1889b965be25f929eeebc5b60cd40b9043rspangler@google.com 9049fdf1889b965be25f929eeebc5b60cd40b9043rspangler@google.com // Sets up glib main loop sources as needed by libcurl. This is generally 9149fdf1889b965be25f929eeebc5b60cd40b9043rspangler@google.com // the file descriptor of the socket and a timer in case nothing happens 9249fdf1889b965be25f929eeebc5b60cd40b9043rspangler@google.com // on the fds. 9349fdf1889b965be25f929eeebc5b60cd40b9043rspangler@google.com void SetupMainloopSources(); 9449fdf1889b965be25f929eeebc5b60cd40b9043rspangler@google.com 9549fdf1889b965be25f929eeebc5b60cd40b9043rspangler@google.com // Callback called by libcurl when new data has arrived on the transfer 9649fdf1889b965be25f929eeebc5b60cd40b9043rspangler@google.com size_t LibcurlWrite(void *ptr, size_t size, size_t nmemb); 9749fdf1889b965be25f929eeebc5b60cd40b9043rspangler@google.com static size_t StaticLibcurlWrite(void *ptr, size_t size, 9849fdf1889b965be25f929eeebc5b60cd40b9043rspangler@google.com size_t nmemb, void *stream) { 9949fdf1889b965be25f929eeebc5b60cd40b9043rspangler@google.com return reinterpret_cast<LibcurlHttpFetcher*>(stream)-> 10049fdf1889b965be25f929eeebc5b60cd40b9043rspangler@google.com LibcurlWrite(ptr, size, nmemb); 10149fdf1889b965be25f929eeebc5b60cd40b9043rspangler@google.com } 10249fdf1889b965be25f929eeebc5b60cd40b9043rspangler@google.com 10349fdf1889b965be25f929eeebc5b60cd40b9043rspangler@google.com // Cleans up the following if they are non-null: 10449fdf1889b965be25f929eeebc5b60cd40b9043rspangler@google.com // curl(m) handles, io_channels_, timeout_source_. 10549fdf1889b965be25f929eeebc5b60cd40b9043rspangler@google.com void CleanUp(); 10649fdf1889b965be25f929eeebc5b60cd40b9043rspangler@google.com 10749fdf1889b965be25f929eeebc5b60cd40b9043rspangler@google.com // Handles for the libcurl library 10849fdf1889b965be25f929eeebc5b60cd40b9043rspangler@google.com CURLM *curl_multi_handle_; 10949fdf1889b965be25f929eeebc5b60cd40b9043rspangler@google.com CURL *curl_handle_; 11049fdf1889b965be25f929eeebc5b60cd40b9043rspangler@google.com 11149fdf1889b965be25f929eeebc5b60cd40b9043rspangler@google.com // a list of all file descriptors that we're waiting on from the 11249fdf1889b965be25f929eeebc5b60cd40b9043rspangler@google.com // glib main loop 11349fdf1889b965be25f929eeebc5b60cd40b9043rspangler@google.com typedef std::map<int, std::pair<GIOChannel*, guint> > IOChannels; 11449fdf1889b965be25f929eeebc5b60cd40b9043rspangler@google.com IOChannels io_channels_; 11549fdf1889b965be25f929eeebc5b60cd40b9043rspangler@google.com 11649fdf1889b965be25f929eeebc5b60cd40b9043rspangler@google.com // if non-NULL, a timer we're waiting on. glib main loop will call us back 11749fdf1889b965be25f929eeebc5b60cd40b9043rspangler@google.com // when it fires. 11849fdf1889b965be25f929eeebc5b60cd40b9043rspangler@google.com GSource* timeout_source_; 11949fdf1889b965be25f929eeebc5b60cd40b9043rspangler@google.com 12049fdf1889b965be25f929eeebc5b60cd40b9043rspangler@google.com bool transfer_in_progress_; 12149fdf1889b965be25f929eeebc5b60cd40b9043rspangler@google.com 122c98a7edf648aad88b3f66df3b5a7d43d6a6d7fa9adlr@google.com // The transfer size. -1 if not known. 123c98a7edf648aad88b3f66df3b5a7d43d6a6d7fa9adlr@google.com off_t transfer_size_; 124c98a7edf648aad88b3f66df3b5a7d43d6a6d7fa9adlr@google.com 125c98a7edf648aad88b3f66df3b5a7d43d6a6d7fa9adlr@google.com // How many bytes have been downloaded and sent to the delegate. 126c98a7edf648aad88b3f66df3b5a7d43d6a6d7fa9adlr@google.com off_t bytes_downloaded_; 127c98a7edf648aad88b3f66df3b5a7d43d6a6d7fa9adlr@google.com 128c98a7edf648aad88b3f66df3b5a7d43d6a6d7fa9adlr@google.com // If we resumed an earlier transfer, data offset that we used for the 129c98a7edf648aad88b3f66df3b5a7d43d6a6d7fa9adlr@google.com // new connection. 0 otherwise. 130c98a7edf648aad88b3f66df3b5a7d43d6a6d7fa9adlr@google.com off_t resume_offset_; 1319bbd18757660a09fb8831147b17916df8a3212e5Andrew de los Reyes 1329bbd18757660a09fb8831147b17916df8a3212e5Andrew de los Reyes // Number of resumes performed. 1339bbd18757660a09fb8831147b17916df8a3212e5Andrew de los Reyes int retry_count_; 134c98a7edf648aad88b3f66df3b5a7d43d6a6d7fa9adlr@google.com 13549fdf1889b965be25f929eeebc5b60cd40b9043rspangler@google.com long idle_ms_; 13649fdf1889b965be25f929eeebc5b60cd40b9043rspangler@google.com DISALLOW_COPY_AND_ASSIGN(LibcurlHttpFetcher); 13749fdf1889b965be25f929eeebc5b60cd40b9043rspangler@google.com}; 13849fdf1889b965be25f929eeebc5b60cd40b9043rspangler@google.com 13949fdf1889b965be25f929eeebc5b60cd40b9043rspangler@google.com} // namespace chromeos_update_engine 14049fdf1889b965be25f929eeebc5b60cd40b9043rspangler@google.com 141c98a7edf648aad88b3f66df3b5a7d43d6a6d7fa9adlr@google.com#endif // CHROMEOS_PLATFORM_UPDATE_ENGINE_LIBCURL_HTTP_FETCHER_H__ 142