uclient-fetch: add support for setting output directory
[project/uclient.git] / uclient-http.c
1 /*
2 * uclient - ustream based protocol client library
3 *
4 * Copyright (C) 2014 Felix Fietkau <nbd@openwrt.org>
5 *
6 * Permission to use, copy, modify, and/or distribute this software for any
7 * purpose with or without fee is hereby granted, provided that the above
8 * copyright notice and this permission notice appear in all copies.
9 *
10 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
11 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
12 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
13 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
14 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
15 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
16 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
17 */
18 #include <stdio.h>
19 #include <ctype.h>
20 #include <unistd.h>
21 #include <stdint.h>
22 #include <fcntl.h>
23
24 #include <libubox/ustream.h>
25 #include <libubox/ustream-ssl.h>
26 #include <libubox/usock.h>
27 #include <libubox/blobmsg.h>
28
29 #include "uclient.h"
30 #include "uclient-utils.h"
31 #include "uclient-backend.h"
32
33 enum auth_type {
34 AUTH_TYPE_UNKNOWN,
35 AUTH_TYPE_NONE,
36 AUTH_TYPE_BASIC,
37 AUTH_TYPE_DIGEST,
38 };
39
40 enum request_type {
41 REQ_GET,
42 REQ_HEAD,
43 REQ_POST,
44 REQ_PUT,
45 REQ_DELETE,
46 __REQ_MAX
47 };
48
49 enum http_state {
50 HTTP_STATE_INIT,
51 HTTP_STATE_HEADERS_SENT,
52 HTTP_STATE_REQUEST_DONE,
53 HTTP_STATE_RECV_HEADERS,
54 HTTP_STATE_RECV_DATA,
55 HTTP_STATE_ERROR,
56 };
57
58 static const char * const request_types[__REQ_MAX] = {
59 [REQ_GET] = "GET",
60 [REQ_HEAD] = "HEAD",
61 [REQ_POST] = "POST",
62 [REQ_PUT] = "PUT",
63 [REQ_DELETE] = "DELETE",
64 };
65
66 struct uclient_http {
67 struct uclient uc;
68
69 const struct ustream_ssl_ops *ssl_ops;
70 struct ustream_ssl_ctx *ssl_ctx;
71 struct ustream *us;
72
73 struct ustream_fd ufd;
74 struct ustream_ssl ussl;
75
76 struct uloop_timeout disconnect_t;
77 unsigned int seq;
78
79 bool ssl_require_validation;
80 bool ssl;
81 bool eof;
82 bool connection_close;
83 bool disconnect;
84 enum request_type req_type;
85 enum http_state state;
86
87 enum auth_type auth_type;
88 char *auth_str;
89
90 long read_chunked;
91 long content_length;
92
93 uint32_t nc;
94
95 struct blob_buf headers;
96 struct blob_buf meta;
97 };
98
99 enum {
100 PREFIX_HTTP,
101 PREFIX_HTTPS,
102 __PREFIX_MAX,
103 };
104
105 static const char * const uclient_http_prefix[] = {
106 [PREFIX_HTTP] = "http://",
107 [PREFIX_HTTPS] = "https://",
108 [__PREFIX_MAX] = NULL
109 };
110
111 static int uclient_do_connect(struct uclient_http *uh, const char *port)
112 {
113 socklen_t sl;
114 int fd;
115
116 if (uh->uc.url->port)
117 port = uh->uc.url->port;
118
119 memset(&uh->uc.remote_addr, 0, sizeof(uh->uc.remote_addr));
120
121 fd = usock_inet(USOCK_TCP, uh->uc.url->host, port, &uh->uc.remote_addr);
122 if (fd < 0)
123 return -1;
124
125 fcntl(fd, F_SETFL, fcntl(fd, F_GETFL) | O_NONBLOCK);
126 ustream_fd_init(&uh->ufd, fd);
127
128 sl = sizeof(uh->uc.local_addr);
129 memset(&uh->uc.local_addr, 0, sl);
130 getsockname(fd, &uh->uc.local_addr.sa, &sl);
131
132 return 0;
133 }
134
135 static void uclient_http_disconnect(struct uclient_http *uh)
136 {
137 uloop_timeout_cancel(&uh->disconnect_t);
138 if (!uh->us)
139 return;
140
141 if (uh->ssl)
142 ustream_free(&uh->ussl.stream);
143 ustream_free(&uh->ufd.stream);
144 close(uh->ufd.fd.fd);
145 uh->us = NULL;
146 }
147
148 static void uclient_http_free_url_state(struct uclient *cl)
149 {
150 struct uclient_http *uh = container_of(cl, struct uclient_http, uc);
151
152 uh->auth_type = AUTH_TYPE_UNKNOWN;
153 free(uh->auth_str);
154 uh->auth_str = NULL;
155 uclient_http_disconnect(uh);
156 }
157
158 static void uclient_http_error(struct uclient_http *uh, int code)
159 {
160 uh->state = HTTP_STATE_ERROR;
161 uh->us->eof = true;
162 ustream_state_change(uh->us);
163 uclient_backend_set_error(&uh->uc, code);
164 }
165
166 static void uclient_http_request_disconnect(struct uclient *cl)
167 {
168 struct uclient_http *uh = container_of(cl, struct uclient_http, uc);
169
170 if (!uh->us)
171 return;
172
173 uh->eof = true;
174 uh->disconnect = true;
175 uloop_timeout_set(&uh->disconnect_t, 1);
176 }
177
178 static void uclient_notify_eof(struct uclient_http *uh)
179 {
180 struct ustream *us = uh->us;
181
182 if (uh->disconnect)
183 return;
184
185 if (!uh->eof) {
186 if (!us->eof && !us->write_error)
187 return;
188
189 if (ustream_pending_data(us, false))
190 return;
191 }
192
193 uclient_backend_set_eof(&uh->uc);
194
195 if (uh->connection_close)
196 uclient_http_request_disconnect(&uh->uc);
197 }
198
199 static void uclient_http_reset_state(struct uclient_http *uh)
200 {
201 uh->seq++;
202 uclient_backend_reset_state(&uh->uc);
203 uh->read_chunked = -1;
204 uh->content_length = -1;
205 uh->eof = false;
206 uh->disconnect = false;
207 uh->connection_close = false;
208 uh->state = HTTP_STATE_INIT;
209
210 if (uh->auth_type == AUTH_TYPE_UNKNOWN && !uh->uc.url->auth)
211 uh->auth_type = AUTH_TYPE_NONE;
212 }
213
214 static void uclient_http_init_request(struct uclient_http *uh)
215 {
216 uh->seq++;
217 uclient_http_reset_state(uh);
218 blob_buf_init(&uh->meta, 0);
219 }
220
221 static enum auth_type
222 uclient_http_update_auth_type(struct uclient_http *uh)
223 {
224 if (!uh->auth_str)
225 return AUTH_TYPE_NONE;
226
227 if (!strncasecmp(uh->auth_str, "basic", 5))
228 return AUTH_TYPE_BASIC;
229
230 if (!strncasecmp(uh->auth_str, "digest", 6))
231 return AUTH_TYPE_DIGEST;
232
233 return AUTH_TYPE_NONE;
234 }
235
236 static void uclient_http_process_headers(struct uclient_http *uh)
237 {
238 enum {
239 HTTP_HDR_TRANSFER_ENCODING,
240 HTTP_HDR_CONNECTION,
241 HTTP_HDR_CONTENT_LENGTH,
242 HTTP_HDR_AUTH,
243 __HTTP_HDR_MAX,
244 };
245 static const struct blobmsg_policy hdr_policy[__HTTP_HDR_MAX] = {
246 #define hdr(_name) { .name = _name, .type = BLOBMSG_TYPE_STRING }
247 [HTTP_HDR_TRANSFER_ENCODING] = hdr("transfer-encoding"),
248 [HTTP_HDR_CONNECTION] = hdr("connection"),
249 [HTTP_HDR_CONTENT_LENGTH] = hdr("content-length"),
250 [HTTP_HDR_AUTH] = hdr("www-authenticate"),
251 #undef hdr
252 };
253 struct blob_attr *tb[__HTTP_HDR_MAX];
254 struct blob_attr *cur;
255
256 blobmsg_parse(hdr_policy, __HTTP_HDR_MAX, tb, blob_data(uh->meta.head), blob_len(uh->meta.head));
257
258 cur = tb[HTTP_HDR_TRANSFER_ENCODING];
259 if (cur && strstr(blobmsg_data(cur), "chunked"))
260 uh->read_chunked = 0;
261
262 cur = tb[HTTP_HDR_CONNECTION];
263 if (cur && strstr(blobmsg_data(cur), "close"))
264 uh->connection_close = true;
265
266 cur = tb[HTTP_HDR_CONTENT_LENGTH];
267 if (cur)
268 uh->content_length = strtoul(blobmsg_data(cur), NULL, 10);
269
270 cur = tb[HTTP_HDR_AUTH];
271 if (cur) {
272 free(uh->auth_str);
273 uh->auth_str = strdup(blobmsg_data(cur));
274 }
275
276 uh->auth_type = uclient_http_update_auth_type(uh);
277 }
278
279 static void
280 uclient_http_add_auth_basic(struct uclient_http *uh)
281 {
282 struct uclient_url *url = uh->uc.url;
283 int auth_len = strlen(url->auth);
284 char *auth_buf;
285
286 if (auth_len > 512)
287 return;
288
289 auth_buf = alloca(base64_len(auth_len) + 1);
290 base64_encode(url->auth, auth_len, auth_buf);
291 ustream_printf(uh->us, "Authorization: Basic %s\r\n", auth_buf);
292 }
293
294 static char *digest_unquote_sep(char **str)
295 {
296 char *cur = *str + 1;
297 char *start = cur;
298 char *out;
299
300 if (**str != '"')
301 return NULL;
302
303 out = cur;
304 while (1) {
305 if (!*cur)
306 return NULL;
307
308 if (*cur == '"') {
309 cur++;
310 break;
311 }
312
313 if (*cur == '\\')
314 cur++;
315
316 *(out++) = *(cur++);
317 }
318
319 if (*cur == ',')
320 cur++;
321
322 *out = 0;
323 *str = cur;
324
325 return start;
326 }
327
328 static char *digest_sep(char **str)
329 {
330 char *cur, *next;
331
332 cur = *str;
333 next = strchr(*str, ',');
334 if (next) {
335 *str = next + 1;
336 *next = 0;
337 } else {
338 *str += strlen(*str);
339 }
340
341 return cur;
342 }
343
344 static bool strmatch(char **str, const char *prefix)
345 {
346 int len = strlen(prefix);
347
348 if (strncmp(*str, prefix, len) != 0 || (*str)[len] != '=')
349 return false;
350
351 *str += len + 1;
352 return true;
353 }
354
355 static void
356 get_cnonce(char *dest)
357 {
358 uint32_t val = 0;
359 FILE *f;
360
361 f = fopen("/dev/urandom", "r");
362 if (f) {
363 fread(&val, sizeof(val), 1, f);
364 fclose(f);
365 }
366
367 bin_to_hex(dest, &val, sizeof(val));
368 }
369
370 static void add_field(char **buf, int *ofs, int *len, const char *name, const char *val)
371 {
372 int available = *len - *ofs;
373 int required;
374 const char *next;
375 char *cur;
376
377 if (*len && !*buf)
378 return;
379
380 required = strlen(name) + 4 + strlen(val) * 2;
381 if (required > available)
382 *len += required - available + 64;
383
384 *buf = realloc(*buf, *len);
385 if (!*buf)
386 return;
387
388 cur = *buf + *ofs;
389 cur += sprintf(cur, ", %s=\"", name);
390
391 while ((next = strchr(val, '"'))) {
392 if (next > val) {
393 memcpy(cur, val, next - val);
394 cur += next - val;
395 }
396
397 cur += sprintf(cur, "\\\"");
398 val = next + 1;
399 }
400
401 cur += sprintf(cur, "%s\"", val);
402 *ofs = cur - *buf;
403 }
404
405 static void
406 uclient_http_add_auth_digest(struct uclient_http *uh)
407 {
408 struct uclient_url *url = uh->uc.url;
409 const char *realm = NULL, *opaque = NULL;
410 const char *user, *password;
411 char *buf, *next;
412 int len, ofs;
413
414 char cnonce_str[9];
415 char nc_str[9];
416 char ahash[33];
417 char hash[33];
418
419 struct http_digest_data data = {
420 .nc = nc_str,
421 .cnonce = cnonce_str,
422 .auth_hash = ahash,
423 };
424
425 len = strlen(uh->auth_str) + 1;
426 if (len > 512)
427 return;
428
429 buf = alloca(len);
430 strcpy(buf, uh->auth_str);
431
432 /* skip auth type */
433 strsep(&buf, " ");
434
435 next = buf;
436 while (*next) {
437 const char **dest = NULL;
438 const char *tmp;
439
440 while (*next && isspace(*next))
441 next++;
442
443 if (strmatch(&next, "realm"))
444 dest = &realm;
445 else if (strmatch(&next, "qop"))
446 dest = &data.qop;
447 else if (strmatch(&next, "nonce"))
448 dest = &data.nonce;
449 else if (strmatch(&next, "opaque"))
450 dest = &opaque;
451 else if (strmatch(&next, "stale") ||
452 strmatch(&next, "algorithm") ||
453 strmatch(&next, "auth-param")) {
454 digest_sep(&next);
455 continue;
456 } else if (strmatch(&next, "domain") ||
457 strmatch(&next, "qop-options"))
458 dest = &tmp;
459 else {
460 digest_sep(&next);
461 continue;
462 }
463
464 *dest = digest_unquote_sep(&next);
465 }
466
467 if (!realm || !data.qop || !data.nonce)
468 return;
469
470 sprintf(nc_str, "%08x", uh->nc++);
471 get_cnonce(cnonce_str);
472
473 data.qop = "auth";
474 data.uri = url->location;
475 data.method = request_types[uh->req_type];
476
477 password = strchr(url->auth, ':');
478 if (password) {
479 char *user_buf;
480
481 len = password - url->auth;
482 if (len > 256)
483 return;
484
485 user_buf = alloca(len + 1);
486 strncpy(user_buf, url->auth, len);
487 user_buf[len] = 0;
488 user = user_buf;
489 password++;
490 } else {
491 user = url->auth;
492 password = "";
493 }
494
495 http_digest_calculate_auth_hash(ahash, user, realm, password);
496 http_digest_calculate_response(hash, &data);
497
498 buf = NULL;
499 len = 0;
500 ofs = 0;
501
502 add_field(&buf, &ofs, &len, "username", user);
503 add_field(&buf, &ofs, &len, "realm", realm);
504 add_field(&buf, &ofs, &len, "nonce", data.nonce);
505 add_field(&buf, &ofs, &len, "uri", data.uri);
506 add_field(&buf, &ofs, &len, "cnonce", data.cnonce);
507 add_field(&buf, &ofs, &len, "response", hash);
508 if (opaque)
509 add_field(&buf, &ofs, &len, "opaque", opaque);
510
511 ustream_printf(uh->us, "Authorization: Digest nc=%s, qop=%s%s\r\n", data.nc, data.qop, buf);
512 free(buf);
513 }
514
515 static void
516 uclient_http_add_auth_header(struct uclient_http *uh)
517 {
518 if (!uh->uc.url->auth)
519 return;
520
521 switch (uh->auth_type) {
522 case AUTH_TYPE_UNKNOWN:
523 case AUTH_TYPE_NONE:
524 break;
525 case AUTH_TYPE_BASIC:
526 uclient_http_add_auth_basic(uh);
527 break;
528 case AUTH_TYPE_DIGEST:
529 uclient_http_add_auth_digest(uh);
530 break;
531 }
532 }
533
534 static void
535 uclient_http_send_headers(struct uclient_http *uh)
536 {
537 struct uclient_url *url = uh->uc.url;
538 struct blob_attr *cur;
539 enum request_type req_type = uh->req_type;
540 int rem;
541
542 if (uh->state >= HTTP_STATE_HEADERS_SENT)
543 return;
544
545 if (uh->uc.proxy_url)
546 url = uh->uc.proxy_url;
547
548 ustream_printf(uh->us,
549 "%s %s HTTP/1.1\r\n"
550 "Host: %s\r\n",
551 request_types[req_type],
552 url->location, url->host);
553
554 blobmsg_for_each_attr(cur, uh->headers.head, rem)
555 ustream_printf(uh->us, "%s: %s\r\n", blobmsg_name(cur), (char *) blobmsg_data(cur));
556
557 if (uh->req_type == REQ_POST || uh->req_type == REQ_PUT)
558 ustream_printf(uh->us, "Transfer-Encoding: chunked\r\n");
559
560 uclient_http_add_auth_header(uh);
561
562 ustream_printf(uh->us, "\r\n");
563
564 uh->state = HTTP_STATE_HEADERS_SENT;
565 }
566
567 static void uclient_http_headers_complete(struct uclient_http *uh)
568 {
569 enum auth_type auth_type = uh->auth_type;
570 int seq = uh->uc.seq;
571
572 uh->state = HTTP_STATE_RECV_DATA;
573 uh->uc.meta = uh->meta.head;
574 uclient_http_process_headers(uh);
575
576 if (auth_type == AUTH_TYPE_UNKNOWN && uh->uc.status_code == 401 &&
577 (uh->req_type == REQ_HEAD || uh->req_type == REQ_GET)) {
578 uclient_http_init_request(uh);
579 uclient_http_send_headers(uh);
580 uh->state = HTTP_STATE_REQUEST_DONE;
581 return;
582 }
583
584 if (uh->uc.cb->header_done)
585 uh->uc.cb->header_done(&uh->uc);
586
587 if (uh->eof || seq != uh->uc.seq)
588 return;
589
590 if (uh->req_type == REQ_HEAD || uh->uc.status_code == 204) {
591 uh->eof = true;
592 uclient_notify_eof(uh);
593 }
594 }
595
596 static void uclient_parse_http_line(struct uclient_http *uh, char *data)
597 {
598 char *name;
599 char *sep;
600
601 if (uh->state == HTTP_STATE_REQUEST_DONE) {
602 char *code;
603
604 if (!strlen(data))
605 return;
606
607 /* HTTP/1.1 */
608 strsep(&data, " ");
609
610 code = strsep(&data, " ");
611 if (!code)
612 goto error;
613
614 uh->uc.status_code = strtoul(code, &sep, 10);
615 if (sep && *sep)
616 goto error;
617
618 uh->state = HTTP_STATE_RECV_HEADERS;
619 return;
620 }
621
622 if (!*data) {
623 uclient_http_headers_complete(uh);
624 return;
625 }
626
627 sep = strchr(data, ':');
628 if (!sep)
629 return;
630
631 *(sep++) = 0;
632
633 for (name = data; *name; name++)
634 *name = tolower(*name);
635
636 name = data;
637 while (isspace(*sep))
638 sep++;
639
640 blobmsg_add_string(&uh->meta, name, sep);
641 return;
642
643 error:
644 uh->uc.status_code = 400;
645 uh->eof = true;
646 uclient_notify_eof(uh);
647 }
648
649 static void __uclient_notify_read(struct uclient_http *uh)
650 {
651 struct uclient *uc = &uh->uc;
652 unsigned int seq = uh->seq;
653 char *data;
654 int len;
655
656 if (uh->state < HTTP_STATE_REQUEST_DONE || uh->state == HTTP_STATE_ERROR)
657 return;
658
659 data = ustream_get_read_buf(uh->us, &len);
660 if (!data || !len)
661 return;
662
663 if (uh->state < HTTP_STATE_RECV_DATA) {
664 char *sep;
665 int cur_len;
666
667 do {
668 sep = strstr(data, "\r\n");
669 if (!sep)
670 break;
671
672 /* Check for multi-line HTTP headers */
673 if (sep > data) {
674 if (!sep[2])
675 return;
676
677 if (isspace(sep[2]) && sep[2] != '\r') {
678 sep[0] = ' ';
679 sep[1] = ' ';
680 continue;
681 }
682 }
683
684 *sep = 0;
685 cur_len = sep + 2 - data;
686 uclient_parse_http_line(uh, data);
687 if (seq != uh->seq)
688 return;
689
690 ustream_consume(uh->us, cur_len);
691 len -= cur_len;
692
693 if (uh->eof)
694 return;
695
696 data = ustream_get_read_buf(uh->us, &len);
697 } while (data && uh->state < HTTP_STATE_RECV_DATA);
698
699 if (!len)
700 return;
701 }
702
703 if (uh->eof)
704 return;
705
706 if (uh->state == HTTP_STATE_RECV_DATA) {
707 /* Now it's uclient user turn to read some data */
708 uloop_timeout_cancel(&uc->connection_timeout);
709
710 if (uc->cb->data_read)
711 uc->cb->data_read(uc);
712 }
713 }
714
715 static void __uclient_notify_write(struct uclient_http *uh)
716 {
717 struct uclient *uc = &uh->uc;
718
719 if (uc->cb->data_sent)
720 uc->cb->data_sent(uc);
721 }
722
723 static void uclient_notify_read(struct ustream *us, int bytes)
724 {
725 struct uclient_http *uh = container_of(us, struct uclient_http, ufd.stream);
726
727 __uclient_notify_read(uh);
728 }
729
730 static void uclient_notify_write(struct ustream *us, int bytes)
731 {
732 struct uclient_http *uh = container_of(us, struct uclient_http, ufd.stream);
733
734 __uclient_notify_write(uh);
735 }
736
737 static void uclient_notify_state(struct ustream *us)
738 {
739 struct uclient_http *uh = container_of(us, struct uclient_http, ufd.stream);
740
741 if (uh->ufd.stream.write_error) {
742 uclient_http_error(uh, UCLIENT_ERROR_CONNECT);
743 return;
744 }
745 uclient_notify_eof(uh);
746 }
747
748 static int uclient_setup_http(struct uclient_http *uh)
749 {
750 struct ustream *us = &uh->ufd.stream;
751 int ret;
752
753 uh->us = us;
754 uh->ssl = false;
755
756 us->string_data = true;
757 us->notify_state = uclient_notify_state;
758 us->notify_read = uclient_notify_read;
759 us->notify_write = uclient_notify_write;
760
761 ret = uclient_do_connect(uh, "80");
762 if (ret)
763 return UCLIENT_ERROR_CONNECT;
764
765 return 0;
766 }
767
768 static void uclient_ssl_notify_read(struct ustream *us, int bytes)
769 {
770 struct uclient_http *uh = container_of(us, struct uclient_http, ussl.stream);
771
772 __uclient_notify_read(uh);
773 }
774
775 static void uclient_ssl_notify_write(struct ustream *us, int bytes)
776 {
777 struct uclient_http *uh = container_of(us, struct uclient_http, ussl.stream);
778
779 __uclient_notify_write(uh);
780 }
781
782 static void uclient_ssl_notify_state(struct ustream *us)
783 {
784 struct uclient_http *uh = container_of(us, struct uclient_http, ussl.stream);
785
786 uclient_notify_eof(uh);
787 }
788
789 static void uclient_ssl_notify_error(struct ustream_ssl *ssl, int error, const char *str)
790 {
791 struct uclient_http *uh = container_of(ssl, struct uclient_http, ussl);
792
793 uclient_http_error(uh, UCLIENT_ERROR_CONNECT);
794 }
795
796 static void uclient_ssl_notify_verify_error(struct ustream_ssl *ssl, int error, const char *str)
797 {
798 struct uclient_http *uh = container_of(ssl, struct uclient_http, ussl);
799
800 if (!uh->ssl_require_validation)
801 return;
802
803 uclient_http_error(uh, UCLIENT_ERROR_SSL_INVALID_CERT);
804 }
805
806 static void uclient_ssl_notify_connected(struct ustream_ssl *ssl)
807 {
808 struct uclient_http *uh = container_of(ssl, struct uclient_http, ussl);
809
810 if (!uh->ssl_require_validation)
811 return;
812
813 if (!uh->ussl.valid_cn)
814 uclient_http_error(uh, UCLIENT_ERROR_SSL_CN_MISMATCH);
815 }
816
817 static int uclient_setup_https(struct uclient_http *uh)
818 {
819 struct ustream *us = &uh->ussl.stream;
820 int ret;
821
822 uh->ssl = true;
823 uh->us = us;
824
825 if (!uh->ssl_ctx)
826 return UCLIENT_ERROR_MISSING_SSL_CONTEXT;
827
828 ret = uclient_do_connect(uh, "443");
829 if (ret)
830 return UCLIENT_ERROR_CONNECT;
831
832 us->string_data = true;
833 us->notify_state = uclient_ssl_notify_state;
834 us->notify_read = uclient_ssl_notify_read;
835 us->notify_write = uclient_ssl_notify_write;
836 uh->ussl.notify_error = uclient_ssl_notify_error;
837 uh->ussl.notify_verify_error = uclient_ssl_notify_verify_error;
838 uh->ussl.notify_connected = uclient_ssl_notify_connected;
839 uh->ussl.server_name = uh->uc.url->host;
840 uh->ssl_ops->init(&uh->ussl, &uh->ufd.stream, uh->ssl_ctx, false);
841 uh->ssl_ops->set_peer_cn(&uh->ussl, uh->uc.url->host);
842
843 return 0;
844 }
845
846 static int uclient_http_connect(struct uclient *cl)
847 {
848 struct uclient_http *uh = container_of(cl, struct uclient_http, uc);
849 int ret;
850
851 if (!cl->eof || uh->disconnect)
852 uclient_http_disconnect(uh);
853
854 uclient_http_init_request(uh);
855
856 if (uh->us)
857 return 0;
858
859 uh->ssl = cl->url->prefix == PREFIX_HTTPS;
860
861 if (uh->ssl)
862 ret = uclient_setup_https(uh);
863 else
864 ret = uclient_setup_http(uh);
865
866 return ret;
867 }
868
869 static void uclient_http_disconnect_cb(struct uloop_timeout *timeout)
870 {
871 struct uclient_http *uh = container_of(timeout, struct uclient_http, disconnect_t);
872
873 uclient_http_disconnect(uh);
874 }
875
876 static struct uclient *uclient_http_alloc(void)
877 {
878 struct uclient_http *uh;
879
880 uh = calloc_a(sizeof(*uh));
881 uh->disconnect_t.cb = uclient_http_disconnect_cb;
882 blob_buf_init(&uh->headers, 0);
883
884 return &uh->uc;
885 }
886
887 static void uclient_http_free_ssl_ctx(struct uclient_http *uh)
888 {
889 uh->ssl_ops = NULL;
890 uh->ssl_ctx = NULL;
891 }
892
893 static void uclient_http_free(struct uclient *cl)
894 {
895 struct uclient_http *uh = container_of(cl, struct uclient_http, uc);
896
897 uclient_http_free_url_state(cl);
898 uclient_http_free_ssl_ctx(uh);
899 blob_buf_free(&uh->headers);
900 blob_buf_free(&uh->meta);
901 free(uh);
902 }
903
904 int
905 uclient_http_set_request_type(struct uclient *cl, const char *type)
906 {
907 struct uclient_http *uh = container_of(cl, struct uclient_http, uc);
908 int i;
909
910 if (cl->backend != &uclient_backend_http)
911 return -1;
912
913 if (uh->state > HTTP_STATE_INIT)
914 return -1;
915
916 for (i = 0; i < ARRAY_SIZE(request_types); i++) {
917 if (strcmp(request_types[i], type) != 0)
918 continue;
919
920 uh->req_type = i;
921 return 0;
922 }
923
924 return -1;
925 }
926
927 int
928 uclient_http_reset_headers(struct uclient *cl)
929 {
930 struct uclient_http *uh = container_of(cl, struct uclient_http, uc);
931
932 blob_buf_init(&uh->headers, 0);
933
934 return 0;
935 }
936
937 int
938 uclient_http_set_header(struct uclient *cl, const char *name, const char *value)
939 {
940 struct uclient_http *uh = container_of(cl, struct uclient_http, uc);
941
942 if (cl->backend != &uclient_backend_http)
943 return -1;
944
945 if (uh->state > HTTP_STATE_INIT)
946 return -1;
947
948 blobmsg_add_string(&uh->headers, name, value);
949 return 0;
950 }
951
952 static int
953 uclient_http_send_data(struct uclient *cl, const char *buf, unsigned int len)
954 {
955 struct uclient_http *uh = container_of(cl, struct uclient_http, uc);
956
957 if (uh->state >= HTTP_STATE_REQUEST_DONE)
958 return -1;
959
960 uclient_http_send_headers(uh);
961
962 if (len > 0) {
963 ustream_printf(uh->us, "%X\r\n", len);
964 ustream_write(uh->us, buf, len, false);
965 ustream_printf(uh->us, "\r\n");
966 }
967
968 return len;
969 }
970
971 static int
972 uclient_http_request_done(struct uclient *cl)
973 {
974 struct uclient_http *uh = container_of(cl, struct uclient_http, uc);
975
976 if (uh->state >= HTTP_STATE_REQUEST_DONE)
977 return -1;
978
979 uclient_http_send_headers(uh);
980 if (uh->req_type == REQ_POST || uh->req_type == REQ_PUT)
981 ustream_printf(uh->us, "0\r\n\r\n");
982 uh->state = HTTP_STATE_REQUEST_DONE;
983
984 return 0;
985 }
986
987 static int
988 uclient_http_read(struct uclient *cl, char *buf, unsigned int len)
989 {
990 struct uclient_http *uh = container_of(cl, struct uclient_http, uc);
991 int read_len = 0;
992 char *data, *data_end;
993
994 if (uh->state < HTTP_STATE_RECV_DATA || !uh->us)
995 return 0;
996
997 data = ustream_get_read_buf(uh->us, &read_len);
998 if (!data || !read_len)
999 return 0;
1000
1001 data_end = data + read_len;
1002 read_len = 0;
1003
1004 if (uh->read_chunked == 0) {
1005 char *sep;
1006
1007 if (data[0] == '\r' && data[1] == '\n') {
1008 data += 2;
1009 read_len += 2;
1010 }
1011
1012 sep = strstr(data, "\r\n");
1013 if (!sep)
1014 return 0;
1015
1016 *sep = 0;
1017 uh->read_chunked = strtoul(data, NULL, 16);
1018
1019 read_len += sep + 2 - data;
1020 data = sep + 2;
1021
1022 if (!uh->read_chunked) {
1023 uh->eof = true;
1024 uh->uc.data_eof = true;
1025 }
1026 }
1027
1028 if (len > data_end - data)
1029 len = data_end - data;
1030
1031 if (uh->read_chunked >= 0) {
1032 if (len > uh->read_chunked)
1033 len = uh->read_chunked;
1034
1035 uh->read_chunked -= len;
1036 } else if (uh->content_length >= 0) {
1037 if (len > uh->content_length)
1038 len = uh->content_length;
1039
1040 uh->content_length -= len;
1041 if (!uh->content_length) {
1042 uh->eof = true;
1043 uh->uc.data_eof = true;
1044 }
1045 }
1046
1047 if (len > 0) {
1048 read_len += len;
1049 memcpy(buf, data, len);
1050 }
1051
1052 if (read_len > 0)
1053 ustream_consume(uh->us, read_len);
1054
1055 uclient_notify_eof(uh);
1056
1057 /* Now that we consumed something and if this isn't EOF, start timer again */
1058 if (!uh->uc.eof && !cl->connection_timeout.pending)
1059 uloop_timeout_set(&cl->connection_timeout, cl->timeout_msecs);
1060
1061 return len;
1062 }
1063
1064 bool uclient_http_redirect(struct uclient *cl)
1065 {
1066 struct uclient_http *uh = container_of(cl, struct uclient_http, uc);
1067 struct blobmsg_policy location = {
1068 .name = "location",
1069 .type = BLOBMSG_TYPE_STRING,
1070 };
1071 struct uclient_url *url = cl->url;
1072 struct blob_attr *tb;
1073
1074 if (cl->backend != &uclient_backend_http)
1075 return false;
1076
1077 switch (cl->status_code) {
1078 case 301:
1079 case 302:
1080 case 307:
1081 break;
1082 default:
1083 return false;
1084 }
1085
1086 blobmsg_parse(&location, 1, &tb, blob_data(uh->meta.head), blob_len(uh->meta.head));
1087 if (!tb)
1088 return false;
1089
1090 url = uclient_get_url(blobmsg_data(tb), url->auth);
1091 if (!url)
1092 return false;
1093
1094 free(cl->url);
1095 cl->url = url;
1096 uclient_http_connect(cl);
1097 uclient_http_request_done(cl);
1098
1099 return true;
1100 }
1101
1102 int uclient_http_set_ssl_ctx(struct uclient *cl, const struct ustream_ssl_ops *ops,
1103 struct ustream_ssl_ctx *ctx, bool require_validation)
1104 {
1105 struct uclient_http *uh = container_of(cl, struct uclient_http, uc);
1106
1107 if (cl->backend != &uclient_backend_http)
1108 return -1;
1109
1110 uclient_http_free_url_state(cl);
1111
1112 uclient_http_free_ssl_ctx(uh);
1113 uh->ssl_ops = ops;
1114 uh->ssl_ctx = ctx;
1115 uh->ssl_require_validation = !!ctx && require_validation;
1116
1117 return 0;
1118 }
1119
1120 const struct uclient_backend uclient_backend_http = {
1121 .prefix = uclient_http_prefix,
1122
1123 .alloc = uclient_http_alloc,
1124 .free = uclient_http_free,
1125 .connect = uclient_http_connect,
1126 .disconnect = uclient_http_request_disconnect,
1127 .update_url = uclient_http_free_url_state,
1128 .update_proxy_url = uclient_http_free_url_state,
1129
1130 .read = uclient_http_read,
1131 .write = uclient_http_send_data,
1132 .request = uclient_http_request_done,
1133 };