045a77296a5b74b2cf5ccaab2b6a2e23481a09ca
[project/uclient.git] / uclient-http.c
1 #include <stdio.h>
2 #include <ctype.h>
3 #include <unistd.h>
4 #include <stdint.h>
5
6 #include <libubox/ustream.h>
7 #include <libubox/ustream-ssl.h>
8 #include <libubox/usock.h>
9 #include <libubox/blobmsg.h>
10
11 #include "uclient.h"
12 #include "uclient-utils.h"
13 #include "uclient-backend.h"
14
15 enum auth_type {
16         AUTH_TYPE_UNKNOWN,
17         AUTH_TYPE_NONE,
18         AUTH_TYPE_BASIC,
19         AUTH_TYPE_DIGEST,
20 };
21
22 enum request_type {
23         REQ_GET,
24         REQ_HEAD,
25         REQ_POST,
26         __REQ_MAX
27 };
28
29 enum http_state {
30         HTTP_STATE_INIT,
31         HTTP_STATE_HEADERS_SENT,
32         HTTP_STATE_REQUEST_DONE,
33         HTTP_STATE_RECV_HEADERS,
34         HTTP_STATE_RECV_DATA,
35         HTTP_STATE_ERROR,
36 };
37
38 static const char * const request_types[__REQ_MAX] = {
39         [REQ_GET] = "GET",
40         [REQ_HEAD] = "HEAD",
41         [REQ_POST] = "POST",
42 };
43
44 struct uclient_http {
45         struct uclient uc;
46
47         struct ustream_ssl_ctx *ssl_ctx;
48         struct ustream *us;
49
50         struct ustream_fd ufd;
51         struct ustream_ssl ussl;
52
53         bool ssl_ctx_ext;
54         bool ssl;
55         bool eof;
56         bool connection_close;
57         enum request_type req_type;
58         enum http_state state;
59
60         enum auth_type auth_type;
61         char *auth_str;
62
63         long read_chunked;
64         long content_length;
65
66         uint32_t nc;
67
68         struct blob_buf headers;
69         struct blob_buf meta;
70 };
71
72 enum {
73         PREFIX_HTTP,
74         PREFIX_HTTPS,
75         __PREFIX_MAX,
76 };
77
78 static const char * const uclient_http_prefix[] = {
79         [PREFIX_HTTP] = "http://",
80         [PREFIX_HTTPS] = "https://",
81         [__PREFIX_MAX] = NULL
82 };
83
84 static int uclient_do_connect(struct uclient_http *uh, const char *port)
85 {
86         int fd;
87
88         if (uh->uc.url->port)
89                 port = uh->uc.url->port;
90
91         fd = usock(USOCK_TCP | USOCK_NONBLOCK, uh->uc.url->host, port);
92         if (fd < 0)
93                 return -1;
94
95         ustream_fd_init(&uh->ufd, fd);
96         return 0;
97 }
98
99 static void uclient_http_disconnect(struct uclient_http *uh)
100 {
101         if (!uh->us)
102                 return;
103
104         if (uh->ssl)
105                 ustream_free(&uh->ussl.stream);
106         ustream_free(&uh->ufd.stream);
107         close(uh->ufd.fd.fd);
108         uh->us = NULL;
109 }
110
111 static void uclient_http_free_url_state(struct uclient *cl)
112 {
113         struct uclient_http *uh = container_of(cl, struct uclient_http, uc);
114
115         uh->auth_type = AUTH_TYPE_UNKNOWN;
116         free(uh->auth_str);
117         uh->auth_str = NULL;
118         uclient_http_disconnect(uh);
119 }
120
121 static void uclient_notify_eof(struct uclient_http *uh)
122 {
123         struct ustream *us = uh->us;
124
125         if (!uh->eof) {
126                 if (!us->eof && !us->write_error)
127                         return;
128
129                 if (ustream_pending_data(us, false))
130                         return;
131         }
132
133         uclient_backend_set_eof(&uh->uc);
134
135         if (uh->connection_close)
136                 uclient_http_disconnect(uh);
137 }
138
139 static void uclient_http_reset_state(struct uclient_http *uh)
140 {
141         uclient_backend_reset_state(&uh->uc);
142         uh->read_chunked = -1;
143         uh->content_length = -1;
144         uh->eof = false;
145         uh->connection_close = false;
146         uh->state = HTTP_STATE_INIT;
147
148         if (uh->auth_type == AUTH_TYPE_UNKNOWN && !uh->uc.url->auth)
149                 uh->auth_type = AUTH_TYPE_NONE;
150 }
151
152 static void uclient_http_init_request(struct uclient_http *uh)
153 {
154         uclient_http_reset_state(uh);
155         blob_buf_init(&uh->meta, 0);
156 }
157
158 static enum auth_type
159 uclient_http_update_auth_type(struct uclient_http *uh)
160 {
161         if (!uh->auth_str)
162                 return AUTH_TYPE_NONE;
163
164         if (!strncasecmp(uh->auth_str, "basic", 5))
165                 return AUTH_TYPE_BASIC;
166
167         if (!strncasecmp(uh->auth_str, "digest", 6))
168                 return AUTH_TYPE_DIGEST;
169
170         return AUTH_TYPE_NONE;
171 }
172
173 static void uclient_http_process_headers(struct uclient_http *uh)
174 {
175         enum {
176                 HTTP_HDR_TRANSFER_ENCODING,
177                 HTTP_HDR_CONNECTION,
178                 HTTP_HDR_CONTENT_LENGTH,
179                 HTTP_HDR_AUTH,
180                 __HTTP_HDR_MAX,
181         };
182         static const struct blobmsg_policy hdr_policy[__HTTP_HDR_MAX] = {
183 #define hdr(_name) { .name = _name, .type = BLOBMSG_TYPE_STRING }
184                 [HTTP_HDR_TRANSFER_ENCODING] = hdr("transfer-encoding"),
185                 [HTTP_HDR_CONNECTION] = hdr("connection"),
186                 [HTTP_HDR_CONTENT_LENGTH] = hdr("content-length"),
187                 [HTTP_HDR_AUTH] = hdr("www-authenticate"),
188 #undef hdr
189         };
190         struct blob_attr *tb[__HTTP_HDR_MAX];
191         struct blob_attr *cur;
192
193         blobmsg_parse(hdr_policy, __HTTP_HDR_MAX, tb, blob_data(uh->meta.head), blob_len(uh->meta.head));
194
195         cur = tb[HTTP_HDR_TRANSFER_ENCODING];
196         if (cur && strstr(blobmsg_data(cur), "chunked"))
197                 uh->read_chunked = 0;
198
199         cur = tb[HTTP_HDR_CONNECTION];
200         if (cur && strstr(blobmsg_data(cur), "close"))
201                 uh->connection_close = true;
202
203         cur = tb[HTTP_HDR_CONTENT_LENGTH];
204         if (cur)
205                 uh->content_length = strtoul(blobmsg_data(cur), NULL, 10);
206
207         cur = tb[HTTP_HDR_AUTH];
208         if (cur) {
209                 free(uh->auth_str);
210                 uh->auth_str = strdup(blobmsg_data(cur));
211         }
212
213         uh->auth_type = uclient_http_update_auth_type(uh);
214 }
215
216 static void
217 uclient_http_add_auth_basic(struct uclient_http *uh)
218 {
219         struct uclient_url *url = uh->uc.url;
220         int auth_len = strlen(url->auth);
221         char *auth_buf;
222
223         if (auth_len > 512)
224                 return;
225
226         auth_buf = alloca(base64_len(auth_len) + 1);
227         base64_encode(url->auth, auth_len, auth_buf);
228         ustream_printf(uh->us, "Authorization: Basic %s\r\n", auth_buf);
229 }
230
231 static char *digest_unquote_sep(char **str)
232 {
233         char *cur = *str + 1;
234         char *start = cur;
235         char *out;
236
237         if (**str != '"')
238                 return NULL;
239
240         out = cur;
241         while (1) {
242                 if (!*cur)
243                         return NULL;
244
245                 if (*cur == '"') {
246                         cur++;
247                         break;
248                 }
249
250                 if (*cur == '\\')
251                         cur++;
252
253                 *(out++) = *(cur++);
254         }
255
256         if (*cur == ',')
257                 cur++;
258
259         *out = 0;
260         *str = cur;
261
262         return start;
263 }
264
265 static bool strmatch(char **str, const char *prefix)
266 {
267         int len = strlen(prefix);
268
269         if (strncmp(*str, prefix, len) != 0 || (*str)[len] != '=')
270                 return false;
271
272         *str += len + 1;
273         return true;
274 }
275
276 static void
277 get_cnonce(char *dest)
278 {
279         uint32_t val = 0;
280         FILE *f;
281
282         f = fopen("/dev/urandom", "r");
283         if (f) {
284                 fread(&val, sizeof(val), 1, f);
285                 fclose(f);
286         }
287
288         bin_to_hex(dest, &val, sizeof(val));
289 }
290
291 static void add_field(char **buf, int *ofs, int *len, const char *name, const char *val)
292 {
293         int available = *len - *ofs;
294         int required;
295         const char *next;
296         char *cur;
297
298         if (*len && !*buf)
299                 return;
300
301         required = strlen(name) + 4 + strlen(val) * 2;
302         if (required > available)
303                 *len += required - available + 64;
304
305         *buf = realloc(*buf, *len);
306         if (!*buf)
307                 return;
308
309         cur = *buf + *ofs;
310         cur += sprintf(cur, ", %s=\"", name);
311
312         while ((next = strchr(val, '"'))) {
313                 if (next > val) {
314                         memcpy(cur, val, next - val);
315                         cur += next - val;
316                 }
317
318                 cur += sprintf(cur, "\\\"");
319                 val = next + 1;
320         }
321
322         cur += sprintf(cur, "%s\"", val);
323         *ofs = cur - *buf;
324 }
325
326 static void
327 uclient_http_add_auth_digest(struct uclient_http *uh)
328 {
329         struct uclient_url *url = uh->uc.url;
330         const char *realm = NULL, *opaque = NULL;
331         const char *user, *password;
332         char *buf, *next;
333         int len, ofs;
334
335         char cnonce_str[9];
336         char nc_str[9];
337         char ahash[33];
338         char hash[33];
339
340         struct http_digest_data data = {
341                 .nc = nc_str,
342                 .cnonce = cnonce_str,
343                 .auth_hash = ahash,
344         };
345
346         len = strlen(uh->auth_str) + 1;
347         if (len > 512)
348                 return;
349
350         buf = alloca(len);
351         strcpy(buf, uh->auth_str);
352
353         /* skip auth type */
354         strsep(&buf, " ");
355
356         next = buf;
357         while (*next) {
358                 const char **dest = NULL;
359
360                 while (isspace(*next))
361                         next++;
362
363                 if (strmatch(&next, "realm"))
364                         dest = &realm;
365                 else if (strmatch(&next, "qop"))
366                         dest = &data.qop;
367                 else if (strmatch(&next, "nonce"))
368                         dest = &data.nonce;
369                 else if (strmatch(&next, "opaque"))
370                         dest = &opaque;
371                 else
372                         return;
373
374                 *dest = digest_unquote_sep(&next);
375         }
376
377         if (!realm || !data.qop || !data.nonce)
378                 return;
379
380         sprintf(nc_str, "%08x", uh->nc++);
381         get_cnonce(cnonce_str);
382
383         data.qop = "auth";
384         data.uri = url->location;
385         data.method = request_types[uh->req_type];
386
387         password = strchr(url->auth, ':');
388         if (password) {
389                 char *user_buf;
390
391                 len = password - url->auth;
392                 if (len > 256)
393                         return;
394
395                 user_buf = alloca(len + 1);
396                 strncpy(user_buf, url->auth, len);
397                 user_buf[len] = 0;
398                 user = user_buf;
399                 password++;
400         } else {
401                 user = url->auth;
402                 password = "";
403         }
404
405         http_digest_calculate_auth_hash(ahash, user, realm, password);
406         http_digest_calculate_response(hash, &data);
407
408         buf = NULL;
409         len = 0;
410         ofs = 0;
411
412         add_field(&buf, &ofs, &len, "username", user);
413         add_field(&buf, &ofs, &len, "realm", realm);
414         add_field(&buf, &ofs, &len, "nonce", data.nonce);
415         add_field(&buf, &ofs, &len, "uri", data.uri);
416         add_field(&buf, &ofs, &len, "cnonce", data.cnonce);
417         add_field(&buf, &ofs, &len, "response", hash);
418         if (opaque)
419                 add_field(&buf, &ofs, &len, "opaque", opaque);
420
421         ustream_printf(uh->us, "Authorization: Digest nc=%s, qop=%s%s\r\n", data.nc, data.qop, buf);
422         free(buf);
423 }
424
425 static void
426 uclient_http_add_auth_header(struct uclient_http *uh)
427 {
428         if (!uh->uc.url->auth)
429                 return;
430
431         switch (uh->auth_type) {
432         case AUTH_TYPE_UNKNOWN:
433         case AUTH_TYPE_NONE:
434                 break;
435         case AUTH_TYPE_BASIC:
436                 uclient_http_add_auth_basic(uh);
437                 break;
438         case AUTH_TYPE_DIGEST:
439                 uclient_http_add_auth_digest(uh);
440                 break;
441         }
442 }
443
444 static void
445 uclient_http_send_headers(struct uclient_http *uh)
446 {
447         struct uclient_url *url = uh->uc.url;
448         struct blob_attr *cur;
449         enum request_type req_type = uh->req_type;
450         int rem;
451
452         if (uh->state >= HTTP_STATE_HEADERS_SENT)
453                 return;
454
455         if (uh->auth_type == AUTH_TYPE_UNKNOWN)
456                 req_type = REQ_HEAD;
457
458         ustream_printf(uh->us,
459                 "%s %s HTTP/1.1\r\n"
460                 "Host: %s\r\n",
461                 request_types[req_type],
462                 url->location, url->host);
463
464         blobmsg_for_each_attr(cur, uh->headers.head, rem)
465                 ustream_printf(uh->us, "%s: %s\n", blobmsg_name(cur), (char *) blobmsg_data(cur));
466
467         if (uh->req_type == REQ_POST)
468                 ustream_printf(uh->us, "Transfer-Encoding: chunked\r\n");
469
470         uclient_http_add_auth_header(uh);
471
472         ustream_printf(uh->us, "\r\n");
473 }
474
475 static void uclient_http_headers_complete(struct uclient_http *uh)
476 {
477         enum auth_type auth_type = uh->auth_type;
478
479         uh->state = HTTP_STATE_RECV_DATA;
480         uh->uc.meta = uh->meta.head;
481         uclient_http_process_headers(uh);
482
483         if (auth_type == AUTH_TYPE_UNKNOWN) {
484                 uclient_http_init_request(uh);
485                 uclient_http_send_headers(uh);
486                 uh->state = HTTP_STATE_REQUEST_DONE;
487                 return;
488         }
489
490         if (uh->uc.cb->header_done)
491                 uh->uc.cb->header_done(&uh->uc);
492
493         if (uh->req_type == REQ_HEAD) {
494                 uh->eof = true;
495                 uclient_notify_eof(uh);
496         }
497 }
498
499 static void uclient_parse_http_line(struct uclient_http *uh, char *data)
500 {
501         char *name;
502         char *sep;
503
504         if (uh->state == HTTP_STATE_REQUEST_DONE) {
505                 char *code;
506
507                 /* HTTP/1.1 */
508                 strsep(&data, " ");
509
510                 code = strsep(&data, " ");
511                 if (!code)
512                         goto error;
513
514                 uh->uc.status_code = strtoul(code, &sep, 10);
515                 if (sep && *sep)
516                         goto error;
517
518                 uh->state = HTTP_STATE_RECV_HEADERS;
519                 return;
520         }
521
522         if (!*data) {
523                 uclient_http_headers_complete(uh);
524                 return;
525         }
526
527         sep = strchr(data, ':');
528         if (!sep)
529                 return;
530
531         *(sep++) = 0;
532
533         for (name = data; *name; name++)
534                 *name = tolower(*name);
535
536         name = data;
537         while (isspace(*sep))
538                 sep++;
539
540         blobmsg_add_string(&uh->meta, name, sep);
541         return;
542
543 error:
544         uh->uc.status_code = 400;
545         uh->eof = true;
546         uclient_notify_eof(uh);
547 }
548
549 static void __uclient_notify_read(struct uclient_http *uh)
550 {
551         struct uclient *uc = &uh->uc;
552         char *data;
553         int len;
554
555         if (uh->state < HTTP_STATE_REQUEST_DONE)
556                 return;
557
558         data = ustream_get_read_buf(uh->us, &len);
559         if (!data || !len)
560                 return;
561
562         if (uh->state < HTTP_STATE_RECV_DATA) {
563                 char *sep;
564                 int cur_len;
565
566                 do {
567                         sep = strstr(data, "\r\n");
568                         if (!sep)
569                                 break;
570
571                         /* Check for multi-line HTTP headers */
572                         if (sep > data) {
573                                 if (!sep[2])
574                                         return;
575
576                                 if (isspace(sep[2]) && sep[2] != '\r') {
577                                         sep[0] = ' ';
578                                         sep[1] = ' ';
579                                         continue;
580                                 }
581                         }
582
583                         *sep = 0;
584                         cur_len = sep + 2 - data;
585                         uclient_parse_http_line(uh, data);
586                         ustream_consume(uh->us, cur_len);
587                         len -= cur_len;
588
589                         data = ustream_get_read_buf(uh->us, &len);
590                 } while (data && uh->state < HTTP_STATE_RECV_DATA);
591
592                 if (!len)
593                         return;
594         }
595
596         if (uh->state == HTTP_STATE_RECV_DATA && uc->cb->data_read)
597                 uc->cb->data_read(uc);
598 }
599
600 static void uclient_notify_read(struct ustream *us, int bytes)
601 {
602         struct uclient_http *uh = container_of(us, struct uclient_http, ufd.stream);
603
604         __uclient_notify_read(uh);
605 }
606
607 static void uclient_notify_state(struct ustream *us)
608 {
609         struct uclient_http *uh = container_of(us, struct uclient_http, ufd.stream);
610
611         uclient_notify_eof(uh);
612 }
613
614 static int uclient_setup_http(struct uclient_http *uh)
615 {
616         struct ustream *us = &uh->ufd.stream;
617         int ret;
618
619         uh->us = us;
620         us->string_data = true;
621         us->notify_state = uclient_notify_state;
622         us->notify_read = uclient_notify_read;
623
624         ret = uclient_do_connect(uh, "80");
625         if (ret)
626                 return ret;
627
628         return 0;
629 }
630
631 static void uclient_ssl_notify_read(struct ustream *us, int bytes)
632 {
633         struct uclient_http *uh = container_of(us, struct uclient_http, ussl.stream);
634
635         __uclient_notify_read(uh);
636 }
637
638 static void uclient_ssl_notify_state(struct ustream *us)
639 {
640         struct uclient_http *uh = container_of(us, struct uclient_http, ussl.stream);
641
642         uclient_notify_eof(uh);
643 }
644
645 static int uclient_setup_https(struct uclient_http *uh)
646 {
647         struct ustream *us = &uh->ussl.stream;
648         int ret;
649
650         uh->ssl = true;
651         uh->us = us;
652
653         ret = uclient_do_connect(uh, "443");
654         if (ret)
655                 return ret;
656
657         if (!uh->ssl_ctx)
658                 uh->ssl_ctx = ustream_ssl_context_new(false);
659
660         us->string_data = true;
661         us->notify_state = uclient_ssl_notify_state;
662         us->notify_read = uclient_ssl_notify_read;
663         ustream_ssl_init(&uh->ussl, &uh->ufd.stream, uh->ssl_ctx, false);
664
665         return 0;
666 }
667
668 static int uclient_http_connect(struct uclient *cl)
669 {
670         struct uclient_http *uh = container_of(cl, struct uclient_http, uc);
671
672         uclient_http_init_request(uh);
673
674         if (uh->us)
675                 return 0;
676
677         uh->ssl = cl->url->prefix == PREFIX_HTTPS;
678
679         if (uh->ssl)
680                 return uclient_setup_https(uh);
681         else
682                 return uclient_setup_http(uh);
683 }
684
685 static struct uclient *uclient_http_alloc(void)
686 {
687         struct uclient_http *uh;
688
689         uh = calloc_a(sizeof(*uh));
690         blob_buf_init(&uh->headers, 0);
691
692         return &uh->uc;
693 }
694
695 static void uclient_http_free_ssl_ctx(struct uclient_http *uh)
696 {
697         if (uh->ssl_ctx && !uh->ssl_ctx_ext)
698                 ustream_ssl_context_free(uh->ssl_ctx);
699
700         uh->ssl_ctx_ext = false;
701 }
702
703 static void uclient_http_free(struct uclient *cl)
704 {
705         struct uclient_http *uh = container_of(cl, struct uclient_http, uc);
706
707         uclient_http_free_ssl_ctx(uh);
708         uclient_http_free_url_state(cl);
709         blob_buf_free(&uh->headers);
710         blob_buf_free(&uh->meta);
711         free(uh);
712 }
713
714 int
715 uclient_http_set_request_type(struct uclient *cl, const char *type)
716 {
717         struct uclient_http *uh = container_of(cl, struct uclient_http, uc);
718         int i;
719
720         if (cl->backend != &uclient_backend_http)
721                 return -1;
722
723         if (uh->state > HTTP_STATE_INIT)
724                 return -1;
725
726         for (i = 0; i < ARRAY_SIZE(request_types); i++) {
727                 if (strcmp(request_types[i], type) != 0)
728                         continue;
729
730                 uh->req_type = i;
731                 return 0;
732         }
733
734         return -1;
735 }
736
737 int
738 uclient_http_reset_headers(struct uclient *cl, const char *name, const char *value)
739 {
740         struct uclient_http *uh = container_of(cl, struct uclient_http, uc);
741
742         blob_buf_init(&uh->headers, 0);
743
744         return 0;
745 }
746
747 int
748 uclient_http_set_header(struct uclient *cl, const char *name, const char *value)
749 {
750         struct uclient_http *uh = container_of(cl, struct uclient_http, uc);
751
752         if (cl->backend != &uclient_backend_http)
753                 return -1;
754
755         if (uh->state > HTTP_STATE_INIT)
756                 return -1;
757
758         blobmsg_add_string(&uh->headers, name, value);
759         return 0;
760 }
761
762 static int
763 uclient_http_send_data(struct uclient *cl, char *buf, unsigned int len)
764 {
765         struct uclient_http *uh = container_of(cl, struct uclient_http, uc);
766
767         if (uh->state >= HTTP_STATE_REQUEST_DONE)
768                 return -1;
769
770         uclient_http_send_headers(uh);
771
772         ustream_printf(uh->us, "%X\r\n", len);
773         if (len > 0)
774                 ustream_write(uh->us, buf, len, false);
775         ustream_printf(uh->us, "\r\n");
776
777         return len;
778 }
779
780 static int
781 uclient_http_request_done(struct uclient *cl)
782 {
783         struct uclient_http *uh = container_of(cl, struct uclient_http, uc);
784
785         if (uh->state >= HTTP_STATE_REQUEST_DONE)
786                 return -1;
787
788         uclient_http_send_headers(uh);
789         uh->state = HTTP_STATE_REQUEST_DONE;
790
791         return 0;
792 }
793
794 static int
795 uclient_http_read(struct uclient *cl, char *buf, unsigned int len)
796 {
797         struct uclient_http *uh = container_of(cl, struct uclient_http, uc);
798         int read_len = 0;
799         char *data, *data_end;
800
801         if (uh->state < HTTP_STATE_RECV_DATA || !uh->us)
802                 return 0;
803
804         data = ustream_get_read_buf(uh->us, &read_len);
805         if (!data || !read_len)
806                 return 0;
807
808         data_end = data + read_len;
809         read_len = 0;
810
811         if (uh->read_chunked == 0) {
812                 char *sep;
813
814                 if (data[0] == '\r' && data[1] == '\n') {
815                         data += 2;
816                         read_len += 2;
817                 }
818
819                 sep = strstr(data, "\r\n");
820                 if (!sep)
821                         return 0;
822
823                 *sep = 0;
824                 uh->read_chunked = strtoul(data, NULL, 16);
825
826                 read_len += sep + 2 - data;
827                 data = sep + 2;
828
829                 if (!uh->read_chunked)
830                         uh->eof = true;
831         }
832
833         if (len > data_end - data)
834                 len = data_end - data;
835
836         if (uh->read_chunked >= 0) {
837                 if (len > uh->read_chunked)
838                         len = uh->read_chunked;
839
840                 uh->read_chunked -= len;
841         } else if (uh->content_length >= 0) {
842                 if (len > uh->content_length)
843                         len = uh->content_length;
844
845                 uh->content_length -= len;
846                 if (!uh->content_length)
847                         uh->eof = true;
848         }
849
850         if (len > 0) {
851                 read_len += len;
852                 memcpy(buf, data, len);
853         }
854
855         if (read_len > 0)
856                 ustream_consume(uh->us, read_len);
857
858         uclient_notify_eof(uh);
859
860         return len;
861 }
862
863 bool uclient_http_redirect(struct uclient *cl)
864 {
865         struct uclient_http *uh = container_of(cl, struct uclient_http, uc);
866         struct blobmsg_policy location = {
867                 .name = "location",
868                 .type = BLOBMSG_TYPE_STRING,
869         };
870         struct uclient_url *url = cl->url;
871         struct blob_attr *tb;
872
873         if (cl->backend != &uclient_backend_http)
874                 return false;
875
876         switch (cl->status_code) {
877         case 301:
878         case 302:
879         case 307:
880                 break;
881         default:
882                 return false;
883         }
884
885         blobmsg_parse(&location, 1, &tb, blob_data(uh->meta.head), blob_len(uh->meta.head));
886         if (!tb)
887                 return false;
888
889         url = uclient_get_url(blobmsg_data(tb), url->auth);
890         if (!url)
891                 return false;
892
893         free(cl->url);
894         cl->url = url;
895         uclient_http_connect(cl);
896         uclient_http_request_done(cl);
897
898         return true;
899 }
900
901 int uclient_http_set_ssl_ctx(struct uclient *cl, struct ustream_ssl_ctx *ctx)
902 {
903         struct uclient_http *uh = container_of(cl, struct uclient_http, uc);
904
905         uclient_http_free_url_state(cl);
906
907         uclient_http_free_ssl_ctx(uh);
908         uh->ssl_ctx = ctx;
909         uh->ssl_ctx_ext = !!ctx;
910
911         return 0;
912 }
913
914 const struct uclient_backend uclient_backend_http = {
915         .prefix = uclient_http_prefix,
916
917         .alloc = uclient_http_alloc,
918         .free = uclient_http_free,
919         .connect = uclient_http_connect,
920         .update_url = uclient_http_free_url_state,
921
922         .read = uclient_http_read,
923         .write = uclient_http_send_data,
924         .request = uclient_http_request_done,
925 };