blob: a7799cb007eb4a64b8ec0ff7320d57e5432420d0 [file] [log] [blame]
rspangler@google.com49fdf182009-10-10 00:57:34 +00001// Copyright (c) 2009 The Chromium OS Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
adlr@google.comc98a7ed2009-12-04 18:54:03 +00005#ifndef CHROMEOS_PLATFORM_UPDATE_ENGINE_LIBCURL_HTTP_FETCHER_H__
6#define CHROMEOS_PLATFORM_UPDATE_ENGINE_LIBCURL_HTTP_FETCHER_H__
rspangler@google.com49fdf182009-10-10 00:57:34 +00007
8#include <map>
9#include <string>
10#include <curl/curl.h>
11#include <glib.h>
12#include "base/basictypes.h"
adlr@google.comc98a7ed2009-12-04 18:54:03 +000013#include "chromeos/obsolete_logging.h"
rspangler@google.com49fdf182009-10-10 00:57:34 +000014#include "update_engine/http_fetcher.h"
15
16// This is a concrete implementation of HttpFetcher that uses libcurl to do the
17// http work.
18
19namespace chromeos_update_engine {
20
21class LibcurlHttpFetcher : public HttpFetcher {
22 public:
23 LibcurlHttpFetcher()
24 : curl_multi_handle_(NULL), curl_handle_(NULL),
25 timeout_source_(NULL), transfer_in_progress_(false),
Andrew de los Reyes9bbd1872010-07-16 14:52:29 -070026 retry_count_(0), idle_ms_(1000) {}
rspangler@google.com49fdf182009-10-10 00:57:34 +000027
28 // Cleans up all internal state. Does not notify delegate
29 ~LibcurlHttpFetcher();
30
31 // Begins the transfer if it hasn't already begun.
32 virtual void BeginTransfer(const std::string& url);
33
34 // If the transfer is in progress, aborts the transfer early.
35 // The transfer cannot be resumed.
36 virtual void TerminateTransfer();
37
38 // Suspend the transfer by calling curl_easy_pause(CURLPAUSE_ALL).
39 virtual void Pause();
40
41 // Resume the transfer by calling curl_easy_pause(CURLPAUSE_CONT).
42 virtual void Unpause();
43
44 // Libcurl sometimes asks to be called back after some time while
45 // leaving that time unspecified. In that case, we pick a reasonable
46 // default of one second, but it can be overridden here. This is
47 // primarily useful for testing.
48 // From http://curl.haxx.se/libcurl/c/curl_multi_timeout.html:
49 // if libcurl returns a -1 timeout here, it just means that libcurl
50 // currently has no stored timeout value. You must not wait too long
51 // (more than a few seconds perhaps) before you call
52 // curl_multi_perform() again.
53 void set_idle_ms(long ms) {
54 idle_ms_ = ms;
55 }
56 private:
adlr@google.comc98a7ed2009-12-04 18:54:03 +000057 // Resumes a transfer where it left off. This will use the
58 // HTTP Range: header to make a new connection from where the last
59 // left off.
60 virtual void ResumeTransfer(const std::string& url);
rspangler@google.com49fdf182009-10-10 00:57:34 +000061
62 // These two methods are for glib main loop callbacks. They are called
63 // when either a file descriptor is ready for work or when a timer
64 // has fired. The static versions are shims for libcurl which has a C API.
65 bool FDCallback(GIOChannel *source, GIOCondition condition);
66 static gboolean StaticFDCallback(GIOChannel *source,
67 GIOCondition condition,
68 gpointer data) {
69 return reinterpret_cast<LibcurlHttpFetcher*>(data)->FDCallback(source,
70 condition);
71 }
Andrew de los Reyes3270f742010-07-15 22:28:14 -070072 gboolean TimeoutCallback();
rspangler@google.com49fdf182009-10-10 00:57:34 +000073 static gboolean StaticTimeoutCallback(gpointer data) {
74 return reinterpret_cast<LibcurlHttpFetcher*>(data)->TimeoutCallback();
75 }
Andrew de los Reyes9bbd1872010-07-16 14:52:29 -070076
77 gboolean RetryTimeoutCallback();
78 static gboolean StaticRetryTimeoutCallback(void* arg) {
79 return static_cast<LibcurlHttpFetcher*>(arg)->RetryTimeoutCallback();
80 }
rspangler@google.com49fdf182009-10-10 00:57:34 +000081
82 // Calls into curl_multi_perform to let libcurl do its work. Returns after
83 // curl_multi_perform is finished, which may actually be after more than
84 // one call to curl_multi_perform. This method will set up the glib run
85 // loop with sources for future work that libcurl will do.
86 // This method will not block.
Andrew de los Reyes3270f742010-07-15 22:28:14 -070087 // Returns true if we should resume immediately after this call.
88 bool CurlPerformOnce();
rspangler@google.com49fdf182009-10-10 00:57:34 +000089
90 // Sets up glib main loop sources as needed by libcurl. This is generally
91 // the file descriptor of the socket and a timer in case nothing happens
92 // on the fds.
93 void SetupMainloopSources();
94
95 // Callback called by libcurl when new data has arrived on the transfer
96 size_t LibcurlWrite(void *ptr, size_t size, size_t nmemb);
97 static size_t StaticLibcurlWrite(void *ptr, size_t size,
98 size_t nmemb, void *stream) {
99 return reinterpret_cast<LibcurlHttpFetcher*>(stream)->
100 LibcurlWrite(ptr, size, nmemb);
101 }
102
103 // Cleans up the following if they are non-null:
104 // curl(m) handles, io_channels_, timeout_source_.
105 void CleanUp();
106
107 // Handles for the libcurl library
108 CURLM *curl_multi_handle_;
109 CURL *curl_handle_;
110
111 // a list of all file descriptors that we're waiting on from the
112 // glib main loop
113 typedef std::map<int, std::pair<GIOChannel*, guint> > IOChannels;
114 IOChannels io_channels_;
115
116 // if non-NULL, a timer we're waiting on. glib main loop will call us back
117 // when it fires.
118 GSource* timeout_source_;
119
120 bool transfer_in_progress_;
121
adlr@google.comc98a7ed2009-12-04 18:54:03 +0000122 // The transfer size. -1 if not known.
123 off_t transfer_size_;
124
125 // How many bytes have been downloaded and sent to the delegate.
126 off_t bytes_downloaded_;
127
128 // If we resumed an earlier transfer, data offset that we used for the
129 // new connection. 0 otherwise.
130 off_t resume_offset_;
Andrew de los Reyes9bbd1872010-07-16 14:52:29 -0700131
132 // Number of resumes performed.
133 int retry_count_;
adlr@google.comc98a7ed2009-12-04 18:54:03 +0000134
rspangler@google.com49fdf182009-10-10 00:57:34 +0000135 long idle_ms_;
136 DISALLOW_COPY_AND_ASSIGN(LibcurlHttpFetcher);
137};
138
139} // namespace chromeos_update_engine
140
adlr@google.comc98a7ed2009-12-04 18:54:03 +0000141#endif // CHROMEOS_PLATFORM_UPDATE_ENGINE_LIBCURL_HTTP_FETCHER_H__