blob: fd55d8e683dc2c02f1fd88baf8022f6b6e17a4f8 [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),
26 idle_ms_(1000) {}
27
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 }
76
77 // Calls into curl_multi_perform to let libcurl do its work. Returns after
78 // curl_multi_perform is finished, which may actually be after more than
79 // one call to curl_multi_perform. This method will set up the glib run
80 // loop with sources for future work that libcurl will do.
81 // This method will not block.
Andrew de los Reyes3270f742010-07-15 22:28:14 -070082 // Returns true if we should resume immediately after this call.
83 bool CurlPerformOnce();
rspangler@google.com49fdf182009-10-10 00:57:34 +000084
85 // Sets up glib main loop sources as needed by libcurl. This is generally
86 // the file descriptor of the socket and a timer in case nothing happens
87 // on the fds.
88 void SetupMainloopSources();
89
90 // Callback called by libcurl when new data has arrived on the transfer
91 size_t LibcurlWrite(void *ptr, size_t size, size_t nmemb);
92 static size_t StaticLibcurlWrite(void *ptr, size_t size,
93 size_t nmemb, void *stream) {
94 return reinterpret_cast<LibcurlHttpFetcher*>(stream)->
95 LibcurlWrite(ptr, size, nmemb);
96 }
97
98 // Cleans up the following if they are non-null:
99 // curl(m) handles, io_channels_, timeout_source_.
100 void CleanUp();
101
102 // Handles for the libcurl library
103 CURLM *curl_multi_handle_;
104 CURL *curl_handle_;
105
106 // a list of all file descriptors that we're waiting on from the
107 // glib main loop
108 typedef std::map<int, std::pair<GIOChannel*, guint> > IOChannels;
109 IOChannels io_channels_;
110
111 // if non-NULL, a timer we're waiting on. glib main loop will call us back
112 // when it fires.
113 GSource* timeout_source_;
114
115 bool transfer_in_progress_;
116
adlr@google.comc98a7ed2009-12-04 18:54:03 +0000117 // The transfer size. -1 if not known.
118 off_t transfer_size_;
119
120 // How many bytes have been downloaded and sent to the delegate.
121 off_t bytes_downloaded_;
122
123 // If we resumed an earlier transfer, data offset that we used for the
124 // new connection. 0 otherwise.
125 off_t resume_offset_;
126
rspangler@google.com49fdf182009-10-10 00:57:34 +0000127 long idle_ms_;
128 DISALLOW_COPY_AND_ASSIGN(LibcurlHttpFetcher);
129};
130
131} // namespace chromeos_update_engine
132
adlr@google.comc98a7ed2009-12-04 18:54:03 +0000133#endif // CHROMEOS_PLATFORM_UPDATE_ENGINE_LIBCURL_HTTP_FETCHER_H__