b6f28e1bbb9dae278f3c5318c9a731e33c5d501d
[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 static struct ustream_ssl_ctx *ssl_ctx;
16 static uint32_t nc;
17
18 enum auth_type {
19         AUTH_TYPE_UNKNOWN,
20         AUTH_TYPE_NONE,
21         AUTH_TYPE_BASIC,
22         AUTH_TYPE_DIGEST,
23 };
24
25 enum request_type {
26         REQ_GET,
27         REQ_HEAD,
28         REQ_POST,
29         __REQ_MAX
30 };
31
32 enum http_state {
33         HTTP_STATE_INIT,
34         HTTP_STATE_HEADERS_SENT,
35         HTTP_STATE_REQUEST_DONE,
36         HTTP_STATE_RECV_HEADERS,
37         HTTP_STATE_RECV_DATA,
38         HTTP_STATE_ERROR,
39 };
40
41 static const char * const request_types[__REQ_MAX] = {
42         [REQ_GET] = "GET",
43         [REQ_HEAD] = "HEAD",
44         [REQ_POST] = "POST",
45 };
46
47 struct uclient_http {
48         struct uclient uc;
49
50         struct ustream *us;
51
52         struct ustream_fd ufd;
53         struct ustream_ssl ussl;
54
55         bool ssl;
56         bool eof;
57         bool connection_close;
58         enum request_type req_type;
59         enum http_state state;
60
61         enum auth_type auth_type;
62         char *auth_str;
63
64         long read_chunked;
65         long content_length;
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 = nc;
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", 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 (!ssl_ctx)
657                 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, 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         uclient_http_free_url_state(cl);
699         blob_buf_free(&uh->headers);
700         blob_buf_free(&uh->meta);
701         free(uh);
702 }
703
704 int
705 uclient_http_set_request_type(struct uclient *cl, const char *type)
706 {
707         struct uclient_http *uh = container_of(cl, struct uclient_http, uc);
708         int i;
709
710         if (cl->backend != &uclient_backend_http)
711                 return -1;
712
713         if (uh->state > HTTP_STATE_INIT)
714                 return -1;
715
716         for (i = 0; i < ARRAY_SIZE(request_types); i++) {
717                 if (strcmp(request_types[i], type) != 0)
718                         continue;
719
720                 uh->req_type = i;
721                 return 0;
722         }
723
724         return -1;
725 }
726
727 int
728 uclient_http_reset_headers(struct uclient *cl, const char *name, const char *value)
729 {
730         struct uclient_http *uh = container_of(cl, struct uclient_http, uc);
731
732         blob_buf_init(&uh->headers, 0);
733
734         return 0;
735 }
736
737 int
738 uclient_http_set_header(struct uclient *cl, const char *name, const char *value)
739 {
740         struct uclient_http *uh = container_of(cl, struct uclient_http, uc);
741
742         if (cl->backend != &uclient_backend_http)
743                 return -1;
744
745         if (uh->state > HTTP_STATE_INIT)
746                 return -1;
747
748         blobmsg_add_string(&uh->headers, name, value);
749         return 0;
750 }
751
752 static int
753 uclient_http_send_data(struct uclient *cl, char *buf, unsigned int len)
754 {
755         struct uclient_http *uh = container_of(cl, struct uclient_http, uc);
756
757         if (uh->state >= HTTP_STATE_REQUEST_DONE)
758                 return -1;
759
760         uclient_http_send_headers(uh);
761
762         ustream_printf(uh->us, "%X\r\n", len);
763         if (len > 0)
764                 ustream_write(uh->us, buf, len, false);
765         ustream_printf(uh->us, "\r\n");
766
767         return len;
768 }
769
770 static int
771 uclient_http_request_done(struct uclient *cl)
772 {
773         struct uclient_http *uh = container_of(cl, struct uclient_http, uc);
774
775         if (uh->state >= HTTP_STATE_REQUEST_DONE)
776                 return -1;
777
778         uclient_http_send_headers(uh);
779         uh->state = HTTP_STATE_REQUEST_DONE;
780
781         return 0;
782 }
783
784 static int
785 uclient_http_read(struct uclient *cl, char *buf, unsigned int len)
786 {
787         struct uclient_http *uh = container_of(cl, struct uclient_http, uc);
788         int read_len = 0;
789         char *data, *data_end;
790
791         if (uh->state < HTTP_STATE_RECV_DATA || !uh->us)
792                 return 0;
793
794         data = ustream_get_read_buf(uh->us, &read_len);
795         if (!data || !read_len)
796                 return 0;
797
798         data_end = data + read_len;
799         read_len = 0;
800
801         if (uh->read_chunked == 0) {
802                 char *sep;
803
804                 if (data[0] == '\r' && data[1] == '\n') {
805                         data += 2;
806                         read_len += 2;
807                 }
808
809                 sep = strstr(data, "\r\n");
810                 if (!sep)
811                         return 0;
812
813                 *sep = 0;
814                 uh->read_chunked = strtoul(data, NULL, 16);
815
816                 read_len += sep + 2 - data;
817                 data = sep + 2;
818
819                 if (!uh->read_chunked)
820                         uh->eof = true;
821         }
822
823         if (len > data_end - data)
824                 len = data_end - data;
825
826         if (uh->read_chunked >= 0) {
827                 if (len > uh->read_chunked)
828                         len = uh->read_chunked;
829
830                 uh->read_chunked -= len;
831         } else if (uh->content_length >= 0) {
832                 if (len > uh->content_length)
833                         len = uh->content_length;
834
835                 uh->content_length -= len;
836                 if (!uh->content_length)
837                         uh->eof = true;
838         }
839
840         if (len > 0) {
841                 read_len += len;
842                 memcpy(buf, data, len);
843         }
844
845         if (read_len > 0)
846                 ustream_consume(uh->us, read_len);
847
848         uclient_notify_eof(uh);
849
850         return len;
851 }
852
853 const struct uclient_backend uclient_backend_http = {
854         .prefix = uclient_http_prefix,
855
856         .alloc = uclient_http_alloc,
857         .free = uclient_http_free,
858         .connect = uclient_http_connect,
859         .update_url = uclient_http_free_url_state,
860
861         .read = uclient_http_read,
862         .write = uclient_http_send_data,
863         .request = uclient_http_request_done,
864 };