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