blob: 433feeb91bcc84957357a09019da4afeb43c0eb3 [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
5#ifndef UPDATE_ENGINE_LIBCURL_HTTP_FETCHER_H__
6#define UPDATE_ENGINE_LIBCURL_HTTP_FETCHER_H__
7
8#include <map>
9#include <string>
10#include <curl/curl.h>
11#include <glib.h>
12#include "base/basictypes.h"
seanparent@google.comd2e4ccc2009-11-05 22:56:33 +000013#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()
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:
57
58 // These two methods are for glib main loop callbacks. They are called
59 // when either a file descriptor is ready for work or when a timer
60 // has fired. The static versions are shims for libcurl which has a C API.
61 bool FDCallback(GIOChannel *source, GIOCondition condition);
62 static gboolean StaticFDCallback(GIOChannel *source,
63 GIOCondition condition,
64 gpointer data) {
65 return reinterpret_cast<LibcurlHttpFetcher*>(data)->FDCallback(source,
66 condition);
67 }
68 bool TimeoutCallback();
69 static gboolean StaticTimeoutCallback(gpointer data) {
70 return reinterpret_cast<LibcurlHttpFetcher*>(data)->TimeoutCallback();
71 }
72
73 // Calls into curl_multi_perform to let libcurl do its work. Returns after
74 // curl_multi_perform is finished, which may actually be after more than
75 // one call to curl_multi_perform. This method will set up the glib run
76 // loop with sources for future work that libcurl will do.
77 // This method will not block.
78 void CurlPerformOnce();
79
80 // Sets up glib main loop sources as needed by libcurl. This is generally
81 // the file descriptor of the socket and a timer in case nothing happens
82 // on the fds.
83 void SetupMainloopSources();
84
85 // Callback called by libcurl when new data has arrived on the transfer
86 size_t LibcurlWrite(void *ptr, size_t size, size_t nmemb);
87 static size_t StaticLibcurlWrite(void *ptr, size_t size,
88 size_t nmemb, void *stream) {
89 return reinterpret_cast<LibcurlHttpFetcher*>(stream)->
90 LibcurlWrite(ptr, size, nmemb);
91 }
92
93 // Cleans up the following if they are non-null:
94 // curl(m) handles, io_channels_, timeout_source_.
95 void CleanUp();
96
97 // Handles for the libcurl library
98 CURLM *curl_multi_handle_;
99 CURL *curl_handle_;
100
101 // a list of all file descriptors that we're waiting on from the
102 // glib main loop
103 typedef std::map<int, std::pair<GIOChannel*, guint> > IOChannels;
104 IOChannels io_channels_;
105
106 // if non-NULL, a timer we're waiting on. glib main loop will call us back
107 // when it fires.
108 GSource* timeout_source_;
109
110 bool transfer_in_progress_;
111
112 long idle_ms_;
113 DISALLOW_COPY_AND_ASSIGN(LibcurlHttpFetcher);
114};
115
116} // namespace chromeos_update_engine
117
118#endif // UPDATE_ENGINE_LIBCURL_HTTP_FETCHER_H__