fix connect error handling
[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         int ret;
672
673         uclient_http_init_request(uh);
674
675         if (uh->us)
676                 return 0;
677
678         uh->ssl = cl->url->prefix == PREFIX_HTTPS;
679
680         if (uh->ssl)
681                 ret = uclient_setup_https(uh);
682         else
683                 ret = uclient_setup_http(uh);
684
685         if (ret)
686                 uh->state = HTTP_STATE_ERROR;
687
688         return ret;
689 }
690
691 static struct uclient *uclient_http_alloc(void)
692 {
693         struct uclient_http *uh;
694
695         uh = calloc_a(sizeof(*uh));
696         blob_buf_init(&uh->headers, 0);
697
698         return &uh->uc;
699 }
700
701 static void uclient_http_free_ssl_ctx(struct uclient_http *uh)
702 {
703         if (uh->ssl_ctx && !uh->ssl_ctx_ext)
704                 ustream_ssl_context_free(uh->ssl_ctx);
705
706         uh->ssl_ctx_ext = false;
707 }
708
709 static void uclient_http_free(struct uclient *cl)
710 {
711         struct uclient_http *uh = container_of(cl, struct uclient_http, uc);
712
713         uclient_http_free_ssl_ctx(uh);
714         uclient_http_free_url_state(cl);
715         blob_buf_free(&uh->headers);
716         blob_buf_free(&uh->meta);
717         free(uh);
718 }
719
720 int
721 uclient_http_set_request_type(struct uclient *cl, const char *type)
722 {
723         struct uclient_http *uh = container_of(cl, struct uclient_http, uc);
724         int i;
725
726         if (cl->backend != &uclient_backend_http)
727                 return -1;
728
729         if (uh->state > HTTP_STATE_INIT)
730                 return -1;
731
732         for (i = 0; i < ARRAY_SIZE(request_types); i++) {
733                 if (strcmp(request_types[i], type) != 0)
734                         continue;
735
736                 uh->req_type = i;
737                 return 0;
738         }
739
740         return -1;
741 }
742
743 int
744 uclient_http_reset_headers(struct uclient *cl, const char *name, const char *value)
745 {
746         struct uclient_http *uh = container_of(cl, struct uclient_http, uc);
747
748         blob_buf_init(&uh->headers, 0);
749
750         return 0;
751 }
752
753 int
754 uclient_http_set_header(struct uclient *cl, const char *name, const char *value)
755 {
756         struct uclient_http *uh = container_of(cl, struct uclient_http, uc);
757
758         if (cl->backend != &uclient_backend_http)
759                 return -1;
760
761         if (uh->state > HTTP_STATE_INIT)
762                 return -1;
763
764         blobmsg_add_string(&uh->headers, name, value);
765         return 0;
766 }
767
768 static int
769 uclient_http_send_data(struct uclient *cl, char *buf, unsigned int len)
770 {
771         struct uclient_http *uh = container_of(cl, struct uclient_http, uc);
772
773         if (uh->state >= HTTP_STATE_REQUEST_DONE)
774                 return -1;
775
776         uclient_http_send_headers(uh);
777
778         ustream_printf(uh->us, "%X\r\n", len);
779         if (len > 0)
780                 ustream_write(uh->us, buf, len, false);
781         ustream_printf(uh->us, "\r\n");
782
783         return len;
784 }
785
786 static int
787 uclient_http_request_done(struct uclient *cl)
788 {
789         struct uclient_http *uh = container_of(cl, struct uclient_http, uc);
790
791         if (uh->state >= HTTP_STATE_REQUEST_DONE)
792                 return -1;
793
794         uclient_http_send_headers(uh);
795         uh->state = HTTP_STATE_REQUEST_DONE;
796
797         return 0;
798 }
799
800 static int
801 uclient_http_read(struct uclient *cl, char *buf, unsigned int len)
802 {
803         struct uclient_http *uh = container_of(cl, struct uclient_http, uc);
804         int read_len = 0;
805         char *data, *data_end;
806
807         if (uh->state < HTTP_STATE_RECV_DATA || !uh->us)
808                 return 0;
809
810         data = ustream_get_read_buf(uh->us, &read_len);
811         if (!data || !read_len)
812                 return 0;
813
814         data_end = data + read_len;
815         read_len = 0;
816
817         if (uh->read_chunked == 0) {
818                 char *sep;
819
820                 if (data[0] == '\r' && data[1] == '\n') {
821                         data += 2;
822                         read_len += 2;
823                 }
824
825                 sep = strstr(data, "\r\n");
826                 if (!sep)
827                         return 0;
828
829                 *sep = 0;
830                 uh->read_chunked = strtoul(data, NULL, 16);
831
832                 read_len += sep + 2 - data;
833                 data = sep + 2;
834
835                 if (!uh->read_chunked)
836                         uh->eof = true;
837         }
838
839         if (len > data_end - data)
840                 len = data_end - data;
841
842         if (uh->read_chunked >= 0) {
843                 if (len > uh->read_chunked)
844                         len = uh->read_chunked;
845
846                 uh->read_chunked -= len;
847         } else if (uh->content_length >= 0) {
848                 if (len > uh->content_length)
849                         len = uh->content_length;
850
851                 uh->content_length -= len;
852                 if (!uh->content_length)
853                         uh->eof = true;
854         }
855
856         if (len > 0) {
857                 read_len += len;
858                 memcpy(buf, data, len);
859         }
860
861         if (read_len > 0)
862                 ustream_consume(uh->us, read_len);
863
864         uclient_notify_eof(uh);
865
866         return len;
867 }
868
869 bool uclient_http_redirect(struct uclient *cl)
870 {
871         struct uclient_http *uh = container_of(cl, struct uclient_http, uc);
872         struct blobmsg_policy location = {
873                 .name = "location",
874                 .type = BLOBMSG_TYPE_STRING,
875         };
876         struct uclient_url *url = cl->url;
877         struct blob_attr *tb;
878
879         if (cl->backend != &uclient_backend_http)
880                 return false;
881
882         switch (cl->status_code) {
883         case 301:
884         case 302:
885         case 307:
886                 break;
887         default:
888                 return false;
889         }
890
891         blobmsg_parse(&location, 1, &tb, blob_data(uh->meta.head), blob_len(uh->meta.head));
892         if (!tb)
893                 return false;
894
895         url = uclient_get_url(blobmsg_data(tb), url->auth);
896         if (!url)
897                 return false;
898
899         free(cl->url);
900         cl->url = url;
901         uclient_http_connect(cl);
902         uclient_http_request_done(cl);
903
904         return true;
905 }
906
907 int uclient_http_set_ssl_ctx(struct uclient *cl, struct ustream_ssl_ctx *ctx)
908 {
909         struct uclient_http *uh = container_of(cl, struct uclient_http, uc);
910
911         uclient_http_free_url_state(cl);
912
913         uclient_http_free_ssl_ctx(uh);
914         uh->ssl_ctx = ctx;
915         uh->ssl_ctx_ext = !!ctx;
916
917         return 0;
918 }
919
920 const struct uclient_backend uclient_backend_http = {
921         .prefix = uclient_http_prefix,
922
923         .alloc = uclient_http_alloc,
924         .free = uclient_http_free,
925         .connect = uclient_http_connect,
926         .update_url = uclient_http_free_url_state,
927
928         .read = uclient_http_read,
929         .write = uclient_http_send_data,
930         .request = uclient_http_request_done,
931 };