Branch data Line data Source code
1 : : /* SPDX-License-Identifier: LGPL-2.1+ */
2 : :
3 : : #include <fcntl.h>
4 : :
5 : : #include "alloc-util.h"
6 : : #include "build.h"
7 : : #include "curl-util.h"
8 : : #include "fd-util.h"
9 : : #include "locale-util.h"
10 : : #include "string-util.h"
11 : :
12 : 0 : static void curl_glue_check_finished(CurlGlue *g) {
13 : : CURLMsg *msg;
14 : 0 : int k = 0;
15 : :
16 [ # # ]: 0 : assert(g);
17 : :
18 : 0 : msg = curl_multi_info_read(g->curl, &k);
19 [ # # ]: 0 : if (!msg)
20 : 0 : return;
21 : :
22 [ # # ]: 0 : if (msg->msg != CURLMSG_DONE)
23 : 0 : return;
24 : :
25 [ # # ]: 0 : if (g->on_finished)
26 : 0 : g->on_finished(g, msg->easy_handle, msg->data.result);
27 : : }
28 : :
29 : 0 : static int curl_glue_on_io(sd_event_source *s, int fd, uint32_t revents, void *userdata) {
30 : 0 : CurlGlue *g = userdata;
31 : 0 : int action, k = 0;
32 : :
33 [ # # ]: 0 : assert(s);
34 [ # # ]: 0 : assert(g);
35 : :
36 [ # # ]: 0 : if (FLAGS_SET(revents, EPOLLIN | EPOLLOUT))
37 : 0 : action = CURL_POLL_INOUT;
38 [ # # ]: 0 : else if (revents & EPOLLIN)
39 : 0 : action = CURL_POLL_IN;
40 [ # # ]: 0 : else if (revents & EPOLLOUT)
41 : 0 : action = CURL_POLL_OUT;
42 : : else
43 : 0 : action = 0;
44 : :
45 [ # # ]: 0 : if (curl_multi_socket_action(g->curl, fd, action, &k) != CURLM_OK)
46 [ # # ]: 0 : return log_debug_errno(SYNTHETIC_ERRNO(EINVAL),
47 : : "Failed to propagate IO event.");
48 : :
49 : 0 : curl_glue_check_finished(g);
50 : 0 : return 0;
51 : : }
52 : :
53 : 0 : static int curl_glue_socket_callback(CURLM *curl, curl_socket_t s, int action, void *userdata, void *socketp) {
54 : 0 : sd_event_source *io = socketp;
55 : 0 : CurlGlue *g = userdata;
56 : 0 : uint32_t events = 0;
57 : : int r;
58 : :
59 [ # # ]: 0 : assert(curl);
60 [ # # ]: 0 : assert(g);
61 : :
62 [ # # ]: 0 : if (action == CURL_POLL_REMOVE) {
63 [ # # ]: 0 : if (io) {
64 : 0 : sd_event_source_disable_unref(io);
65 : :
66 : 0 : hashmap_remove(g->ios, FD_TO_PTR(s));
67 : : }
68 : :
69 : 0 : return 0;
70 : : }
71 : :
72 : 0 : r = hashmap_ensure_allocated(&g->ios, &trivial_hash_ops);
73 [ # # ]: 0 : if (r < 0) {
74 : 0 : log_oom();
75 : 0 : return -1;
76 : : }
77 : :
78 [ # # ]: 0 : if (action == CURL_POLL_IN)
79 : 0 : events = EPOLLIN;
80 [ # # ]: 0 : else if (action == CURL_POLL_OUT)
81 : 0 : events = EPOLLOUT;
82 [ # # ]: 0 : else if (action == CURL_POLL_INOUT)
83 : 0 : events = EPOLLIN|EPOLLOUT;
84 : :
85 [ # # ]: 0 : if (io) {
86 [ # # ]: 0 : if (sd_event_source_set_io_events(io, events) < 0)
87 : 0 : return -1;
88 : :
89 [ # # ]: 0 : if (sd_event_source_set_enabled(io, SD_EVENT_ON) < 0)
90 : 0 : return -1;
91 : : } else {
92 [ # # ]: 0 : if (sd_event_add_io(g->event, &io, s, events, curl_glue_on_io, g) < 0)
93 : 0 : return -1;
94 : :
95 [ # # ]: 0 : if (curl_multi_assign(g->curl, s, io) != CURLM_OK)
96 : 0 : return -1;
97 : :
98 : 0 : (void) sd_event_source_set_description(io, "curl-io");
99 : :
100 : 0 : r = hashmap_put(g->ios, FD_TO_PTR(s), io);
101 [ # # ]: 0 : if (r < 0) {
102 : 0 : log_oom();
103 : 0 : sd_event_source_unref(io);
104 : 0 : return -1;
105 : : }
106 : : }
107 : :
108 : 0 : return 0;
109 : : }
110 : :
111 : 0 : static int curl_glue_on_timer(sd_event_source *s, uint64_t usec, void *userdata) {
112 : 0 : CurlGlue *g = userdata;
113 : 0 : int k = 0;
114 : :
115 [ # # ]: 0 : assert(s);
116 [ # # ]: 0 : assert(g);
117 : :
118 [ # # ]: 0 : if (curl_multi_socket_action(g->curl, CURL_SOCKET_TIMEOUT, 0, &k) != CURLM_OK)
119 [ # # ]: 0 : return log_debug_errno(SYNTHETIC_ERRNO(EINVAL),
120 : : "Failed to propagate timeout.");
121 : :
122 : 0 : curl_glue_check_finished(g);
123 : 0 : return 0;
124 : : }
125 : :
126 : 0 : static int curl_glue_timer_callback(CURLM *curl, long timeout_ms, void *userdata) {
127 : 0 : CurlGlue *g = userdata;
128 : : usec_t usec;
129 : :
130 [ # # ]: 0 : assert(curl);
131 [ # # ]: 0 : assert(g);
132 : :
133 [ # # ]: 0 : if (timeout_ms < 0) {
134 [ # # ]: 0 : if (g->timer) {
135 [ # # ]: 0 : if (sd_event_source_set_enabled(g->timer, SD_EVENT_OFF) < 0)
136 : 0 : return -1;
137 : : }
138 : :
139 : 0 : return 0;
140 : : }
141 : :
142 : 0 : usec = now(clock_boottime_or_monotonic()) + (usec_t) timeout_ms * USEC_PER_MSEC + USEC_PER_MSEC - 1;
143 : :
144 [ # # ]: 0 : if (g->timer) {
145 [ # # ]: 0 : if (sd_event_source_set_time(g->timer, usec) < 0)
146 : 0 : return -1;
147 : :
148 [ # # ]: 0 : if (sd_event_source_set_enabled(g->timer, SD_EVENT_ONESHOT) < 0)
149 : 0 : return -1;
150 : : } else {
151 [ # # ]: 0 : if (sd_event_add_time(g->event, &g->timer, clock_boottime_or_monotonic(), usec, 0, curl_glue_on_timer, g) < 0)
152 : 0 : return -1;
153 : :
154 : 0 : (void) sd_event_source_set_description(g->timer, "curl-timer");
155 : : }
156 : :
157 : 0 : return 0;
158 : : }
159 : :
160 : 0 : CurlGlue *curl_glue_unref(CurlGlue *g) {
161 : : sd_event_source *io;
162 : :
163 [ # # ]: 0 : if (!g)
164 : 0 : return NULL;
165 : :
166 [ # # ]: 0 : if (g->curl)
167 : 0 : curl_multi_cleanup(g->curl);
168 : :
169 [ # # ]: 0 : while ((io = hashmap_steal_first(g->ios))) {
170 : 0 : sd_event_source_unref(io);
171 : : }
172 : :
173 : 0 : hashmap_free(g->ios);
174 : :
175 : 0 : sd_event_source_unref(g->timer);
176 : 0 : sd_event_unref(g->event);
177 : 0 : return mfree(g);
178 : : }
179 : :
180 : 0 : int curl_glue_new(CurlGlue **glue, sd_event *event) {
181 : 0 : _cleanup_(curl_glue_unrefp) CurlGlue *g = NULL;
182 : 0 : _cleanup_(curl_multi_cleanupp) CURL *c = NULL;
183 : 0 : _cleanup_(sd_event_unrefp) sd_event *e = NULL;
184 : : int r;
185 : :
186 [ # # ]: 0 : if (event)
187 : 0 : e = sd_event_ref(event);
188 : : else {
189 : 0 : r = sd_event_default(&e);
190 [ # # ]: 0 : if (r < 0)
191 : 0 : return r;
192 : : }
193 : :
194 : 0 : c = curl_multi_init();
195 [ # # ]: 0 : if (!c)
196 : 0 : return -ENOMEM;
197 : :
198 : 0 : g = new(CurlGlue, 1);
199 [ # # ]: 0 : if (!g)
200 : 0 : return -ENOMEM;
201 : :
202 : 0 : *g = (CurlGlue) {
203 : 0 : .event = TAKE_PTR(e),
204 : 0 : .curl = TAKE_PTR(c),
205 : : };
206 : :
207 [ # # ]: 0 : if (curl_multi_setopt(g->curl, CURLMOPT_SOCKETDATA, g) != CURLM_OK)
208 : 0 : return -EINVAL;
209 : :
210 [ # # ]: 0 : if (curl_multi_setopt(g->curl, CURLMOPT_SOCKETFUNCTION, curl_glue_socket_callback) != CURLM_OK)
211 : 0 : return -EINVAL;
212 : :
213 [ # # ]: 0 : if (curl_multi_setopt(g->curl, CURLMOPT_TIMERDATA, g) != CURLM_OK)
214 : 0 : return -EINVAL;
215 : :
216 [ # # ]: 0 : if (curl_multi_setopt(g->curl, CURLMOPT_TIMERFUNCTION, curl_glue_timer_callback) != CURLM_OK)
217 : 0 : return -EINVAL;
218 : :
219 : 0 : *glue = TAKE_PTR(g);
220 : :
221 : 0 : return 0;
222 : : }
223 : :
224 : 0 : int curl_glue_make(CURL **ret, const char *url, void *userdata) {
225 : 0 : _cleanup_(curl_easy_cleanupp) CURL *c = NULL;
226 : : const char *useragent;
227 : :
228 [ # # ]: 0 : assert(ret);
229 [ # # ]: 0 : assert(url);
230 : :
231 : 0 : c = curl_easy_init();
232 [ # # ]: 0 : if (!c)
233 : 0 : return -ENOMEM;
234 : :
235 : : /* curl_easy_setopt(c, CURLOPT_VERBOSE, 1L); */
236 : :
237 [ # # ]: 0 : if (curl_easy_setopt(c, CURLOPT_URL, url) != CURLE_OK)
238 : 0 : return -EIO;
239 : :
240 [ # # ]: 0 : if (curl_easy_setopt(c, CURLOPT_PRIVATE, userdata) != CURLE_OK)
241 : 0 : return -EIO;
242 : :
243 [ # # # # : 0 : useragent = strjoina(program_invocation_short_name, "/" GIT_VERSION);
# # # # #
# # # ]
244 [ # # ]: 0 : if (curl_easy_setopt(c, CURLOPT_USERAGENT, useragent) != CURLE_OK)
245 : 0 : return -EIO;
246 : :
247 [ # # ]: 0 : if (curl_easy_setopt(c, CURLOPT_FOLLOWLOCATION, 1L) != CURLE_OK)
248 : 0 : return -EIO;
249 : :
250 : 0 : *ret = TAKE_PTR(c);
251 : 0 : return 0;
252 : : }
253 : :
254 : 0 : int curl_glue_add(CurlGlue *g, CURL *c) {
255 [ # # ]: 0 : assert(g);
256 [ # # ]: 0 : assert(c);
257 : :
258 [ # # ]: 0 : if (curl_multi_add_handle(g->curl, c) != CURLM_OK)
259 : 0 : return -EIO;
260 : :
261 : 0 : return 0;
262 : : }
263 : :
264 : 0 : void curl_glue_remove_and_free(CurlGlue *g, CURL *c) {
265 [ # # ]: 0 : assert(g);
266 : :
267 [ # # ]: 0 : if (!c)
268 : 0 : return;
269 : :
270 [ # # ]: 0 : if (g->curl)
271 : 0 : curl_multi_remove_handle(g->curl, c);
272 : :
273 : 0 : curl_easy_cleanup(c);
274 : : }
275 : :
276 : 0 : struct curl_slist *curl_slist_new(const char *first, ...) {
277 : : struct curl_slist *l;
278 : : va_list ap;
279 : :
280 [ # # ]: 0 : if (!first)
281 : 0 : return NULL;
282 : :
283 : 0 : l = curl_slist_append(NULL, first);
284 [ # # ]: 0 : if (!l)
285 : 0 : return NULL;
286 : :
287 : 0 : va_start(ap, first);
288 : :
289 : 0 : for (;;) {
290 : : struct curl_slist *n;
291 : : const char *i;
292 : :
293 : 0 : i = va_arg(ap, const char*);
294 [ # # ]: 0 : if (!i)
295 : 0 : break;
296 : :
297 : 0 : n = curl_slist_append(l, i);
298 [ # # ]: 0 : if (!n) {
299 : 0 : va_end(ap);
300 : 0 : curl_slist_free_all(l);
301 : 0 : return NULL;
302 : : }
303 : :
304 : 0 : l = n;
305 : : }
306 : :
307 : 0 : va_end(ap);
308 : 0 : return l;
309 : : }
310 : :
311 : 0 : int curl_header_strdup(const void *contents, size_t sz, const char *field, char **value) {
312 : : const char *p;
313 : : char *s;
314 : :
315 : 0 : p = memory_startswith_no_case(contents, sz, field);
316 [ # # ]: 0 : if (!p)
317 : 0 : return 0;
318 : :
319 : 0 : sz -= p - (const char*) contents;
320 : :
321 [ # # ]: 0 : if (memchr(p, 0, sz))
322 : 0 : return 0;
323 : :
324 : : /* Skip over preceding whitespace */
325 [ # # # # ]: 0 : while (sz > 0 && strchr(WHITESPACE, p[0])) {
326 : 0 : p++;
327 : 0 : sz--;
328 : : }
329 : :
330 : : /* Truncate trailing whitespace */
331 [ # # # # ]: 0 : while (sz > 0 && strchr(WHITESPACE, p[sz-1]))
332 : 0 : sz--;
333 : :
334 : 0 : s = strndup(p, sz);
335 [ # # ]: 0 : if (!s)
336 : 0 : return -ENOMEM;
337 : :
338 : 0 : *value = s;
339 : 0 : return 1;
340 : : }
341 : :
342 : 0 : int curl_parse_http_time(const char *t, usec_t *ret) {
343 : 0 : _cleanup_(freelocalep) locale_t loc = (locale_t) 0;
344 : : const char *e;
345 : : struct tm tm;
346 : : time_t v;
347 : :
348 [ # # ]: 0 : assert(t);
349 [ # # ]: 0 : assert(ret);
350 : :
351 : 0 : loc = newlocale(LC_TIME_MASK, "C", (locale_t) 0);
352 [ # # ]: 0 : if (loc == (locale_t) 0)
353 : 0 : return -errno;
354 : :
355 : : /* RFC822 */
356 : 0 : e = strptime_l(t, "%a, %d %b %Y %H:%M:%S %Z", &tm, loc);
357 [ # # # # ]: 0 : if (!e || *e != 0)
358 : : /* RFC 850 */
359 : 0 : e = strptime_l(t, "%A, %d-%b-%y %H:%M:%S %Z", &tm, loc);
360 [ # # # # ]: 0 : if (!e || *e != 0)
361 : : /* ANSI C */
362 : 0 : e = strptime_l(t, "%a %b %d %H:%M:%S %Y", &tm, loc);
363 [ # # # # ]: 0 : if (!e || *e != 0)
364 : 0 : return -EINVAL;
365 : :
366 : 0 : v = timegm(&tm);
367 [ # # ]: 0 : if (v == (time_t) -1)
368 : 0 : return -EINVAL;
369 : :
370 : 0 : *ret = (usec_t) v * USEC_PER_SEC;
371 : 0 : return 0;
372 : : }
|