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