libcurl_http_fetcher.h revision 3270f7411f55b872db385d0edffdfed18a684121
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), 2649fdf1889b965be25f929eeebc5b60cd40b9043rspangler@google.com 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 } 7649fdf1889b965be25f929eeebc5b60cd40b9043rspangler@google.com 7749fdf1889b965be25f929eeebc5b60cd40b9043rspangler@google.com // Calls into curl_multi_perform to let libcurl do its work. Returns after 7849fdf1889b965be25f929eeebc5b60cd40b9043rspangler@google.com // curl_multi_perform is finished, which may actually be after more than 7949fdf1889b965be25f929eeebc5b60cd40b9043rspangler@google.com // one call to curl_multi_perform. This method will set up the glib run 8049fdf1889b965be25f929eeebc5b60cd40b9043rspangler@google.com // loop with sources for future work that libcurl will do. 8149fdf1889b965be25f929eeebc5b60cd40b9043rspangler@google.com // This method will not block. 823270f7411f55b872db385d0edffdfed18a684121Andrew de los Reyes // Returns true if we should resume immediately after this call. 833270f7411f55b872db385d0edffdfed18a684121Andrew de los Reyes bool CurlPerformOnce(); 8449fdf1889b965be25f929eeebc5b60cd40b9043rspangler@google.com 8549fdf1889b965be25f929eeebc5b60cd40b9043rspangler@google.com // Sets up glib main loop sources as needed by libcurl. This is generally 8649fdf1889b965be25f929eeebc5b60cd40b9043rspangler@google.com // the file descriptor of the socket and a timer in case nothing happens 8749fdf1889b965be25f929eeebc5b60cd40b9043rspangler@google.com // on the fds. 8849fdf1889b965be25f929eeebc5b60cd40b9043rspangler@google.com void SetupMainloopSources(); 8949fdf1889b965be25f929eeebc5b60cd40b9043rspangler@google.com 9049fdf1889b965be25f929eeebc5b60cd40b9043rspangler@google.com // Callback called by libcurl when new data has arrived on the transfer 9149fdf1889b965be25f929eeebc5b60cd40b9043rspangler@google.com size_t LibcurlWrite(void *ptr, size_t size, size_t nmemb); 9249fdf1889b965be25f929eeebc5b60cd40b9043rspangler@google.com static size_t StaticLibcurlWrite(void *ptr, size_t size, 9349fdf1889b965be25f929eeebc5b60cd40b9043rspangler@google.com size_t nmemb, void *stream) { 9449fdf1889b965be25f929eeebc5b60cd40b9043rspangler@google.com return reinterpret_cast<LibcurlHttpFetcher*>(stream)-> 9549fdf1889b965be25f929eeebc5b60cd40b9043rspangler@google.com LibcurlWrite(ptr, size, nmemb); 9649fdf1889b965be25f929eeebc5b60cd40b9043rspangler@google.com } 9749fdf1889b965be25f929eeebc5b60cd40b9043rspangler@google.com 9849fdf1889b965be25f929eeebc5b60cd40b9043rspangler@google.com // Cleans up the following if they are non-null: 9949fdf1889b965be25f929eeebc5b60cd40b9043rspangler@google.com // curl(m) handles, io_channels_, timeout_source_. 10049fdf1889b965be25f929eeebc5b60cd40b9043rspangler@google.com void CleanUp(); 10149fdf1889b965be25f929eeebc5b60cd40b9043rspangler@google.com 10249fdf1889b965be25f929eeebc5b60cd40b9043rspangler@google.com // Handles for the libcurl library 10349fdf1889b965be25f929eeebc5b60cd40b9043rspangler@google.com CURLM *curl_multi_handle_; 10449fdf1889b965be25f929eeebc5b60cd40b9043rspangler@google.com CURL *curl_handle_; 10549fdf1889b965be25f929eeebc5b60cd40b9043rspangler@google.com 10649fdf1889b965be25f929eeebc5b60cd40b9043rspangler@google.com // a list of all file descriptors that we're waiting on from the 10749fdf1889b965be25f929eeebc5b60cd40b9043rspangler@google.com // glib main loop 10849fdf1889b965be25f929eeebc5b60cd40b9043rspangler@google.com typedef std::map<int, std::pair<GIOChannel*, guint> > IOChannels; 10949fdf1889b965be25f929eeebc5b60cd40b9043rspangler@google.com IOChannels io_channels_; 11049fdf1889b965be25f929eeebc5b60cd40b9043rspangler@google.com 11149fdf1889b965be25f929eeebc5b60cd40b9043rspangler@google.com // if non-NULL, a timer we're waiting on. glib main loop will call us back 11249fdf1889b965be25f929eeebc5b60cd40b9043rspangler@google.com // when it fires. 11349fdf1889b965be25f929eeebc5b60cd40b9043rspangler@google.com GSource* timeout_source_; 11449fdf1889b965be25f929eeebc5b60cd40b9043rspangler@google.com 11549fdf1889b965be25f929eeebc5b60cd40b9043rspangler@google.com bool transfer_in_progress_; 11649fdf1889b965be25f929eeebc5b60cd40b9043rspangler@google.com 117c98a7edf648aad88b3f66df3b5a7d43d6a6d7fa9adlr@google.com // The transfer size. -1 if not known. 118c98a7edf648aad88b3f66df3b5a7d43d6a6d7fa9adlr@google.com off_t transfer_size_; 119c98a7edf648aad88b3f66df3b5a7d43d6a6d7fa9adlr@google.com 120c98a7edf648aad88b3f66df3b5a7d43d6a6d7fa9adlr@google.com // How many bytes have been downloaded and sent to the delegate. 121c98a7edf648aad88b3f66df3b5a7d43d6a6d7fa9adlr@google.com off_t bytes_downloaded_; 122c98a7edf648aad88b3f66df3b5a7d43d6a6d7fa9adlr@google.com 123c98a7edf648aad88b3f66df3b5a7d43d6a6d7fa9adlr@google.com // If we resumed an earlier transfer, data offset that we used for the 124c98a7edf648aad88b3f66df3b5a7d43d6a6d7fa9adlr@google.com // new connection. 0 otherwise. 125c98a7edf648aad88b3f66df3b5a7d43d6a6d7fa9adlr@google.com off_t resume_offset_; 126c98a7edf648aad88b3f66df3b5a7d43d6a6d7fa9adlr@google.com 12749fdf1889b965be25f929eeebc5b60cd40b9043rspangler@google.com long idle_ms_; 12849fdf1889b965be25f929eeebc5b60cd40b9043rspangler@google.com DISALLOW_COPY_AND_ASSIGN(LibcurlHttpFetcher); 12949fdf1889b965be25f929eeebc5b60cd40b9043rspangler@google.com}; 13049fdf1889b965be25f929eeebc5b60cd40b9043rspangler@google.com 13149fdf1889b965be25f929eeebc5b60cd40b9043rspangler@google.com} // namespace chromeos_update_engine 13249fdf1889b965be25f929eeebc5b60cd40b9043rspangler@google.com 133c98a7edf648aad88b3f66df3b5a7d43d6a6d7fa9adlr@google.com#endif // CHROMEOS_PLATFORM_UPDATE_ENGINE_LIBCURL_HTTP_FETCHER_H__ 134