blob: a4ed52fa356d88686db40719512be5843e8364de [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"
Chris Masone790e62e2010-08-12 10:41:18 -070013#include "base/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()
Darin Petkovb83371f2010-08-17 09:34:49 -070024 : curl_multi_handle_(NULL),
25 curl_handle_(NULL),
26 timeout_source_(NULL),
27 transfer_in_progress_(false),
28 retry_count_(0),
29 retry_seconds_(60),
30 idle_seconds_(1) {}
rspangler@google.com49fdf182009-10-10 00:57:34 +000031
32 // Cleans up all internal state. Does not notify delegate
33 ~LibcurlHttpFetcher();
34
35 // Begins the transfer if it hasn't already begun.
36 virtual void BeginTransfer(const std::string& url);
37
38 // If the transfer is in progress, aborts the transfer early.
39 // The transfer cannot be resumed.
40 virtual void TerminateTransfer();
41
42 // Suspend the transfer by calling curl_easy_pause(CURLPAUSE_ALL).
43 virtual void Pause();
44
45 // Resume the transfer by calling curl_easy_pause(CURLPAUSE_CONT).
46 virtual void Unpause();
47
48 // Libcurl sometimes asks to be called back after some time while
49 // leaving that time unspecified. In that case, we pick a reasonable
50 // default of one second, but it can be overridden here. This is
51 // primarily useful for testing.
52 // From http://curl.haxx.se/libcurl/c/curl_multi_timeout.html:
53 // if libcurl returns a -1 timeout here, it just means that libcurl
54 // currently has no stored timeout value. You must not wait too long
55 // (more than a few seconds perhaps) before you call
56 // curl_multi_perform() again.
Darin Petkovb83371f2010-08-17 09:34:49 -070057 void set_idle_seconds(int seconds) { idle_seconds_ = seconds; }
58
59 // Sets the retry timeout. Useful for testing.
60 void set_retry_seconds(int seconds) { retry_seconds_ = seconds; }
61
rspangler@google.com49fdf182009-10-10 00:57:34 +000062 private:
adlr@google.comc98a7ed2009-12-04 18:54:03 +000063 // Resumes a transfer where it left off. This will use the
64 // HTTP Range: header to make a new connection from where the last
65 // left off.
66 virtual void ResumeTransfer(const std::string& url);
rspangler@google.com49fdf182009-10-10 00:57:34 +000067
68 // These two methods are for glib main loop callbacks. They are called
69 // when either a file descriptor is ready for work or when a timer
70 // has fired. The static versions are shims for libcurl which has a C API.
71 bool FDCallback(GIOChannel *source, GIOCondition condition);
72 static gboolean StaticFDCallback(GIOChannel *source,
73 GIOCondition condition,
74 gpointer data) {
75 return reinterpret_cast<LibcurlHttpFetcher*>(data)->FDCallback(source,
76 condition);
77 }
Andrew de los Reyes3270f742010-07-15 22:28:14 -070078 gboolean TimeoutCallback();
rspangler@google.com49fdf182009-10-10 00:57:34 +000079 static gboolean StaticTimeoutCallback(gpointer data) {
80 return reinterpret_cast<LibcurlHttpFetcher*>(data)->TimeoutCallback();
81 }
Darin Petkovb83371f2010-08-17 09:34:49 -070082
Andrew de los Reyes9bbd1872010-07-16 14:52:29 -070083 gboolean RetryTimeoutCallback();
84 static gboolean StaticRetryTimeoutCallback(void* arg) {
85 return static_cast<LibcurlHttpFetcher*>(arg)->RetryTimeoutCallback();
86 }
rspangler@google.com49fdf182009-10-10 00:57:34 +000087
88 // Calls into curl_multi_perform to let libcurl do its work. Returns after
89 // curl_multi_perform is finished, which may actually be after more than
90 // one call to curl_multi_perform. This method will set up the glib run
91 // loop with sources for future work that libcurl will do.
92 // This method will not block.
Andrew de los Reyes3270f742010-07-15 22:28:14 -070093 // Returns true if we should resume immediately after this call.
Andrew de los Reyescb319332010-07-19 10:55:01 -070094 void CurlPerformOnce();
rspangler@google.com49fdf182009-10-10 00:57:34 +000095
96 // Sets up glib main loop sources as needed by libcurl. This is generally
97 // the file descriptor of the socket and a timer in case nothing happens
98 // on the fds.
99 void SetupMainloopSources();
100
101 // Callback called by libcurl when new data has arrived on the transfer
102 size_t LibcurlWrite(void *ptr, size_t size, size_t nmemb);
103 static size_t StaticLibcurlWrite(void *ptr, size_t size,
104 size_t nmemb, void *stream) {
105 return reinterpret_cast<LibcurlHttpFetcher*>(stream)->
106 LibcurlWrite(ptr, size, nmemb);
107 }
108
109 // Cleans up the following if they are non-null:
110 // curl(m) handles, io_channels_, timeout_source_.
111 void CleanUp();
112
113 // Handles for the libcurl library
114 CURLM *curl_multi_handle_;
115 CURL *curl_handle_;
116
117 // a list of all file descriptors that we're waiting on from the
118 // glib main loop
119 typedef std::map<int, std::pair<GIOChannel*, guint> > IOChannels;
120 IOChannels io_channels_;
121
122 // if non-NULL, a timer we're waiting on. glib main loop will call us back
123 // when it fires.
124 GSource* timeout_source_;
125
126 bool transfer_in_progress_;
127
adlr@google.comc98a7ed2009-12-04 18:54:03 +0000128 // The transfer size. -1 if not known.
129 off_t transfer_size_;
130
131 // How many bytes have been downloaded and sent to the delegate.
132 off_t bytes_downloaded_;
133
134 // If we resumed an earlier transfer, data offset that we used for the
135 // new connection. 0 otherwise.
136 off_t resume_offset_;
Darin Petkovb83371f2010-08-17 09:34:49 -0700137
Andrew de los Reyes9bbd1872010-07-16 14:52:29 -0700138 // Number of resumes performed.
139 int retry_count_;
adlr@google.comc98a7ed2009-12-04 18:54:03 +0000140
Darin Petkovb83371f2010-08-17 09:34:49 -0700141 // Seconds to wait before retrying a resume.
142 int retry_seconds_;
143
144 // Seconds to wait before asking libcurl to "perform".
145 int idle_seconds_;
146
rspangler@google.com49fdf182009-10-10 00:57:34 +0000147 DISALLOW_COPY_AND_ASSIGN(LibcurlHttpFetcher);
148};
149
150} // namespace chromeos_update_engine
151
adlr@google.comc98a7ed2009-12-04 18:54:03 +0000152#endif // CHROMEOS_PLATFORM_UPDATE_ENGINE_LIBCURL_HTTP_FETCHER_H__