implement digest support
[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 uh->state = HTTP_STATE_RECV_HEADERS;
505 return;
506 }
507
508 if (!*data) {
509 uclient_http_headers_complete(uh);
510 return;
511 }
512
513 sep = strchr(data, ':');
514 if (!sep)
515 return;
516
517 *(sep++) = 0;
518
519 for (name = data; *name; name++)
520 *name = tolower(*name);
521
522 name = data;
523 while (isspace(*sep))
524 sep++;
525
526 blobmsg_add_string(&uh->meta, name, sep);
527 }
528
529 static void __uclient_notify_read(struct uclient_http *uh)
530 {
531 struct uclient *uc = &uh->uc;
532 char *data;
533 int len;
534
535 if (uh->state < HTTP_STATE_REQUEST_DONE)
536 return;
537
538 data = ustream_get_read_buf(uh->us, &len);
539 if (!data || !len)
540 return;
541
542 if (uh->state < HTTP_STATE_RECV_DATA) {
543 char *sep;
544 int cur_len;
545
546 do {
547 sep = strstr(data, "\r\n");
548 if (!sep)
549 break;
550
551 /* Check for multi-line HTTP headers */
552 if (sep > data) {
553 if (!sep[2])
554 return;
555
556 if (isspace(sep[2]) && sep[2] != '\r') {
557 sep[0] = ' ';
558 sep[1] = ' ';
559 continue;
560 }
561 }
562
563 *sep = 0;
564 cur_len = sep + 2 - data;
565 uclient_parse_http_line(uh, data);
566 ustream_consume(uh->us, cur_len);
567 len -= cur_len;
568
569 data = ustream_get_read_buf(uh->us, &len);
570 } while (data && uh->state < HTTP_STATE_RECV_DATA);
571
572 if (!len)
573 return;
574 }
575
576 if (uh->state == HTTP_STATE_RECV_DATA && uc->cb->data_read)
577 uc->cb->data_read(uc);
578 }
579
580 static void uclient_notify_read(struct ustream *us, int bytes)
581 {
582 struct uclient_http *uh = container_of(us, struct uclient_http, ufd.stream);
583
584 __uclient_notify_read(uh);
585 }
586
587 static void uclient_notify_state(struct ustream *us)
588 {
589 struct uclient_http *uh = container_of(us, struct uclient_http, ufd.stream);
590
591 uclient_notify_eof(uh);
592 }
593
594 static int uclient_setup_http(struct uclient_http *uh)
595 {
596 struct ustream *us = &uh->ufd.stream;
597 int ret;
598
599 uh->us = us;
600 us->string_data = true;
601 us->notify_state = uclient_notify_state;
602 us->notify_read = uclient_notify_read;
603
604 ret = uclient_do_connect(uh, "80");
605 if (ret)
606 return ret;
607
608 return 0;
609 }
610
611 static void uclient_ssl_notify_read(struct ustream *us, int bytes)
612 {
613 struct uclient_http *uh = container_of(us, struct uclient_http, ussl.stream);
614
615 __uclient_notify_read(uh);
616 }
617
618 static void uclient_ssl_notify_state(struct ustream *us)
619 {
620 struct uclient_http *uh = container_of(us, struct uclient_http, ussl.stream);
621
622 uclient_notify_eof(uh);
623 }
624
625 static int uclient_setup_https(struct uclient_http *uh)
626 {
627 struct ustream *us = &uh->ussl.stream;
628 int ret;
629
630 uh->ssl = true;
631 uh->us = us;
632
633 ret = uclient_do_connect(uh, "443");
634 if (ret)
635 return ret;
636
637 if (!ssl_ctx)
638 ssl_ctx = ustream_ssl_context_new(false);
639
640 us->string_data = true;
641 us->notify_state = uclient_ssl_notify_state;
642 us->notify_read = uclient_ssl_notify_read;
643 ustream_ssl_init(&uh->ussl, &uh->ufd.stream, ssl_ctx, false);
644
645 return 0;
646 }
647
648 static int uclient_http_connect(struct uclient *cl)
649 {
650 struct uclient_http *uh = container_of(cl, struct uclient_http, uc);
651
652 uclient_http_init_request(uh);
653
654 if (uh->us)
655 return 0;
656
657 uh->ssl = cl->url->prefix == PREFIX_HTTPS;
658
659 if (uh->ssl)
660 return uclient_setup_https(uh);
661 else
662 return uclient_setup_http(uh);
663 }
664
665 static struct uclient *uclient_http_alloc(void)
666 {
667 struct uclient_http *uh;
668
669 uh = calloc_a(sizeof(*uh));
670 blob_buf_init(&uh->headers, 0);
671
672 return &uh->uc;
673 }
674
675 static void uclient_http_free(struct uclient *cl)
676 {
677 struct uclient_http *uh = container_of(cl, struct uclient_http, uc);
678
679 uclient_http_free_url_state(cl);
680 blob_buf_free(&uh->headers);
681 blob_buf_free(&uh->meta);
682 free(uh);
683 }
684
685 int
686 uclient_http_set_request_type(struct uclient *cl, const char *type)
687 {
688 struct uclient_http *uh = container_of(cl, struct uclient_http, uc);
689 int i;
690
691 if (cl->backend != &uclient_backend_http)
692 return -1;
693
694 if (uh->state > HTTP_STATE_INIT)
695 return -1;
696
697 for (i = 0; i < ARRAY_SIZE(request_types); i++) {
698 if (strcmp(request_types[i], type) != 0)
699 continue;
700
701 uh->req_type = i;
702 return 0;
703 }
704
705 return -1;
706 }
707
708 int
709 uclient_http_reset_headers(struct uclient *cl, const char *name, const char *value)
710 {
711 struct uclient_http *uh = container_of(cl, struct uclient_http, uc);
712
713 blob_buf_init(&uh->headers, 0);
714
715 return 0;
716 }
717
718 int
719 uclient_http_set_header(struct uclient *cl, const char *name, const char *value)
720 {
721 struct uclient_http *uh = container_of(cl, struct uclient_http, uc);
722
723 if (cl->backend != &uclient_backend_http)
724 return -1;
725
726 if (uh->state > HTTP_STATE_INIT)
727 return -1;
728
729 blobmsg_add_string(&uh->headers, name, value);
730 return 0;
731 }
732
733 static int
734 uclient_http_send_data(struct uclient *cl, char *buf, unsigned int len)
735 {
736 struct uclient_http *uh = container_of(cl, struct uclient_http, uc);
737
738 if (uh->state >= HTTP_STATE_REQUEST_DONE)
739 return -1;
740
741 uclient_http_send_headers(uh);
742
743 ustream_printf(uh->us, "%X\r\n", len);
744 ustream_write(uh->us, buf, len, false);
745 ustream_printf(uh->us, "\r\n");
746
747 return len;
748 }
749
750 static int
751 uclient_http_request_done(struct uclient *cl)
752 {
753 struct uclient_http *uh = container_of(cl, struct uclient_http, uc);
754
755 if (uh->state >= HTTP_STATE_REQUEST_DONE)
756 return -1;
757
758 uclient_http_send_headers(uh);
759 uh->state = HTTP_STATE_REQUEST_DONE;
760
761 return 0;
762 }
763
764 static int
765 uclient_http_read(struct uclient *cl, char *buf, unsigned int len)
766 {
767 struct uclient_http *uh = container_of(cl, struct uclient_http, uc);
768 int read_len = 0;
769 char *data, *data_end;
770
771 if (uh->state < HTTP_STATE_RECV_DATA || !uh->us)
772 return 0;
773
774 data = ustream_get_read_buf(uh->us, &read_len);
775 if (!data || !read_len)
776 return 0;
777
778 data_end = data + read_len;
779 read_len = 0;
780
781 if (uh->read_chunked == 0) {
782 char *sep;
783
784 if (data[0] == '\r' && data[1] == '\n') {
785 data += 2;
786 read_len += 2;
787 }
788
789 sep = strstr(data, "\r\n");
790 if (!sep)
791 return 0;
792
793 *sep = 0;
794 uh->read_chunked = strtoul(data, NULL, 16);
795
796 read_len += sep + 2 - data;
797 data = sep + 2;
798
799 if (!uh->read_chunked)
800 uh->eof = true;
801 }
802
803 if (len > data_end - data)
804 len = data_end - data;
805
806 if (uh->read_chunked >= 0) {
807 if (len > uh->read_chunked)
808 len = uh->read_chunked;
809
810 uh->read_chunked -= len;
811 } else if (uh->content_length >= 0) {
812 if (len > uh->content_length)
813 len = uh->content_length;
814
815 uh->content_length -= len;
816 if (!uh->content_length)
817 uh->eof = true;
818 }
819
820 if (len > 0) {
821 read_len += len;
822 memcpy(buf, data, len);
823 }
824
825 if (read_len > 0)
826 ustream_consume(uh->us, read_len);
827
828 uclient_notify_eof(uh);
829
830 return len;
831 }
832
833 const struct uclient_backend uclient_backend_http __hidden = {
834 .prefix = uclient_http_prefix,
835
836 .alloc = uclient_http_alloc,
837 .free = uclient_http_free,
838 .connect = uclient_http_connect,
839 .update_url = uclient_http_free_url_state,
840
841 .read = uclient_http_read,
842 .write = uclient_http_send_data,
843 .request = uclient_http_request_done,
844 };