6 #include <libubox/ustream.h>
7 #include <libubox/ustream-ssl.h>
8 #include <libubox/usock.h>
9 #include <libubox/blobmsg.h>
12 #include "uclient-utils.h"
13 #include "uclient-backend.h"
31 HTTP_STATE_HEADERS_SENT,
32 HTTP_STATE_REQUEST_DONE,
33 HTTP_STATE_RECV_HEADERS,
38 static const char * const request_types[__REQ_MAX] = {
47 struct ustream_ssl_ctx *ssl_ctx;
50 struct ustream_fd ufd;
51 struct ustream_ssl ussl;
55 bool connection_close;
56 enum request_type req_type;
57 enum http_state state;
59 enum auth_type auth_type;
67 struct blob_buf headers;
77 static const char * const uclient_http_prefix[] = {
78 [PREFIX_HTTP] = "http://",
79 [PREFIX_HTTPS] = "https://",
83 static int uclient_do_connect(struct uclient_http *uh, const char *port)
88 port = uh->uc.url->port;
90 fd = usock(USOCK_TCP | USOCK_NONBLOCK, uh->uc.url->host, port);
94 ustream_fd_init(&uh->ufd, fd);
98 static void uclient_http_disconnect(struct uclient_http *uh)
104 ustream_free(&uh->ussl.stream);
105 ustream_free(&uh->ufd.stream);
106 close(uh->ufd.fd.fd);
110 static void uclient_http_free_url_state(struct uclient *cl)
112 struct uclient_http *uh = container_of(cl, struct uclient_http, uc);
114 uh->auth_type = AUTH_TYPE_UNKNOWN;
117 uclient_http_disconnect(uh);
120 static void uclient_notify_eof(struct uclient_http *uh)
122 struct ustream *us = uh->us;
125 if (!us->eof && !us->write_error)
128 if (ustream_pending_data(us, false))
132 uclient_backend_set_eof(&uh->uc);
134 if (uh->connection_close)
135 uclient_http_disconnect(uh);
138 static void uclient_http_reset_state(struct uclient_http *uh)
140 uclient_backend_reset_state(&uh->uc);
141 uh->read_chunked = -1;
142 uh->content_length = -1;
144 uh->connection_close = false;
145 uh->state = HTTP_STATE_INIT;
147 if (uh->auth_type == AUTH_TYPE_UNKNOWN && !uh->uc.url->auth)
148 uh->auth_type = AUTH_TYPE_NONE;
151 static void uclient_http_init_request(struct uclient_http *uh)
153 uclient_http_reset_state(uh);
154 blob_buf_init(&uh->meta, 0);
157 static enum auth_type
158 uclient_http_update_auth_type(struct uclient_http *uh)
161 return AUTH_TYPE_NONE;
163 if (!strncasecmp(uh->auth_str, "basic", 5))
164 return AUTH_TYPE_BASIC;
166 if (!strncasecmp(uh->auth_str, "digest", 6))
167 return AUTH_TYPE_DIGEST;
169 return AUTH_TYPE_NONE;
172 static void uclient_http_process_headers(struct uclient_http *uh)
175 HTTP_HDR_TRANSFER_ENCODING,
177 HTTP_HDR_CONTENT_LENGTH,
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"),
189 struct blob_attr *tb[__HTTP_HDR_MAX];
190 struct blob_attr *cur;
192 blobmsg_parse(hdr_policy, __HTTP_HDR_MAX, tb, blob_data(uh->meta.head), blob_len(uh->meta.head));
194 cur = tb[HTTP_HDR_TRANSFER_ENCODING];
195 if (cur && strstr(blobmsg_data(cur), "chunked"))
196 uh->read_chunked = 0;
198 cur = tb[HTTP_HDR_CONNECTION];
199 if (cur && strstr(blobmsg_data(cur), "close"))
200 uh->connection_close = true;
202 cur = tb[HTTP_HDR_CONTENT_LENGTH];
204 uh->content_length = strtoul(blobmsg_data(cur), NULL, 10);
206 cur = tb[HTTP_HDR_AUTH];
209 uh->auth_str = strdup(blobmsg_data(cur));
212 uh->auth_type = uclient_http_update_auth_type(uh);
216 uclient_http_add_auth_basic(struct uclient_http *uh)
218 struct uclient_url *url = uh->uc.url;
219 int auth_len = strlen(url->auth);
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);
230 static char *digest_unquote_sep(char **str)
232 char *cur = *str + 1;
264 static bool strmatch(char **str, const char *prefix)
266 int len = strlen(prefix);
268 if (strncmp(*str, prefix, len) != 0 || (*str)[len] != '=')
276 get_cnonce(char *dest)
281 f = fopen("/dev/urandom", "r");
283 fread(&val, sizeof(val), 1, f);
287 bin_to_hex(dest, &val, sizeof(val));
290 static void add_field(char **buf, int *ofs, int *len, const char *name, const char *val)
292 int available = *len - *ofs;
300 required = strlen(name) + 4 + strlen(val) * 2;
301 if (required > available)
302 *len += required - available + 64;
304 *buf = realloc(*buf, *len);
309 cur += sprintf(cur, ", %s=\"", name);
311 while ((next = strchr(val, '"'))) {
313 memcpy(cur, val, next - val);
317 cur += sprintf(cur, "\\\"");
321 cur += sprintf(cur, "%s\"", val);
326 uclient_http_add_auth_digest(struct uclient_http *uh)
328 struct uclient_url *url = uh->uc.url;
329 const char *realm = NULL, *opaque = NULL;
330 const char *user, *password;
339 struct http_digest_data data = {
341 .cnonce = cnonce_str,
345 len = strlen(uh->auth_str) + 1;
350 strcpy(buf, uh->auth_str);
357 const char **dest = NULL;
359 while (isspace(*next))
362 if (strmatch(&next, "realm"))
364 else if (strmatch(&next, "qop"))
366 else if (strmatch(&next, "nonce"))
368 else if (strmatch(&next, "opaque"))
373 *dest = digest_unquote_sep(&next);
376 if (!realm || !data.qop || !data.nonce)
379 sprintf(nc_str, "%08x", uh->nc++);
380 get_cnonce(cnonce_str);
383 data.uri = url->location;
384 data.method = request_types[uh->req_type];
386 password = strchr(url->auth, ':');
390 len = password - url->auth;
394 user_buf = alloca(len + 1);
395 strncpy(user_buf, url->auth, len);
404 http_digest_calculate_auth_hash(ahash, user, realm, password);
405 http_digest_calculate_response(hash, &data);
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);
418 add_field(&buf, &ofs, &len, "opaque", opaque);
420 ustream_printf(uh->us, "Authorization: Digest nc=%s, qop=%s%s\r\n", data.nc, data.qop, buf);
425 uclient_http_add_auth_header(struct uclient_http *uh)
427 if (!uh->uc.url->auth)
430 switch (uh->auth_type) {
431 case AUTH_TYPE_UNKNOWN:
434 case AUTH_TYPE_BASIC:
435 uclient_http_add_auth_basic(uh);
437 case AUTH_TYPE_DIGEST:
438 uclient_http_add_auth_digest(uh);
444 uclient_http_send_headers(struct uclient_http *uh)
446 struct uclient_url *url = uh->uc.url;
447 struct blob_attr *cur;
448 enum request_type req_type = uh->req_type;
451 if (uh->state >= HTTP_STATE_HEADERS_SENT)
454 if (uh->auth_type == AUTH_TYPE_UNKNOWN)
457 ustream_printf(uh->us,
460 request_types[req_type],
461 url->location, url->host);
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));
466 if (uh->req_type == REQ_POST)
467 ustream_printf(uh->us, "Transfer-Encoding: chunked\r\n");
469 uclient_http_add_auth_header(uh);
471 ustream_printf(uh->us, "\r\n");
474 static void uclient_http_headers_complete(struct uclient_http *uh)
476 enum auth_type auth_type = uh->auth_type;
478 uh->state = HTTP_STATE_RECV_DATA;
479 uh->uc.meta = uh->meta.head;
480 uclient_http_process_headers(uh);
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;
489 if (uh->uc.cb->header_done)
490 uh->uc.cb->header_done(&uh->uc);
492 if (uh->req_type == REQ_HEAD) {
494 uclient_notify_eof(uh);
498 static void uclient_parse_http_line(struct uclient_http *uh, char *data)
503 if (uh->state == HTTP_STATE_REQUEST_DONE) {
509 code = strsep(&data, " ");
513 uh->uc.status_code = strtoul(code, &sep, 10);
517 uh->state = HTTP_STATE_RECV_HEADERS;
522 uclient_http_headers_complete(uh);
526 sep = strchr(data, ':');
532 for (name = data; *name; name++)
533 *name = tolower(*name);
536 while (isspace(*sep))
539 blobmsg_add_string(&uh->meta, name, sep);
543 uh->uc.status_code = 400;
545 uclient_notify_eof(uh);
548 static void __uclient_notify_read(struct uclient_http *uh)
550 struct uclient *uc = &uh->uc;
554 if (uh->state < HTTP_STATE_REQUEST_DONE)
557 data = ustream_get_read_buf(uh->us, &len);
561 if (uh->state < HTTP_STATE_RECV_DATA) {
566 sep = strstr(data, "\r\n");
570 /* Check for multi-line HTTP headers */
575 if (isspace(sep[2]) && sep[2] != '\r') {
583 cur_len = sep + 2 - data;
584 uclient_parse_http_line(uh, data);
585 ustream_consume(uh->us, cur_len);
588 data = ustream_get_read_buf(uh->us, &len);
589 } while (data && uh->state < HTTP_STATE_RECV_DATA);
595 if (uh->state == HTTP_STATE_RECV_DATA && uc->cb->data_read)
596 uc->cb->data_read(uc);
599 static void uclient_notify_read(struct ustream *us, int bytes)
601 struct uclient_http *uh = container_of(us, struct uclient_http, ufd.stream);
603 __uclient_notify_read(uh);
606 static void uclient_notify_state(struct ustream *us)
608 struct uclient_http *uh = container_of(us, struct uclient_http, ufd.stream);
610 uclient_notify_eof(uh);
613 static int uclient_setup_http(struct uclient_http *uh)
615 struct ustream *us = &uh->ufd.stream;
619 us->string_data = true;
620 us->notify_state = uclient_notify_state;
621 us->notify_read = uclient_notify_read;
623 ret = uclient_do_connect(uh, "80");
630 static void uclient_ssl_notify_read(struct ustream *us, int bytes)
632 struct uclient_http *uh = container_of(us, struct uclient_http, ussl.stream);
634 __uclient_notify_read(uh);
637 static void uclient_ssl_notify_state(struct ustream *us)
639 struct uclient_http *uh = container_of(us, struct uclient_http, ussl.stream);
641 uclient_notify_eof(uh);
644 static int uclient_setup_https(struct uclient_http *uh)
646 struct ustream *us = &uh->ussl.stream;
652 ret = uclient_do_connect(uh, "443");
657 uh->ssl_ctx = ustream_ssl_context_new(false);
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);
667 static int uclient_http_connect(struct uclient *cl)
669 struct uclient_http *uh = container_of(cl, struct uclient_http, uc);
671 uclient_http_init_request(uh);
676 uh->ssl = cl->url->prefix == PREFIX_HTTPS;
679 return uclient_setup_https(uh);
681 return uclient_setup_http(uh);
684 static struct uclient *uclient_http_alloc(void)
686 struct uclient_http *uh;
688 uh = calloc_a(sizeof(*uh));
689 blob_buf_init(&uh->headers, 0);
694 static void uclient_http_free(struct uclient *cl)
696 struct uclient_http *uh = container_of(cl, struct uclient_http, uc);
699 ustream_ssl_context_free(uh->ssl_ctx);
701 uclient_http_free_url_state(cl);
702 blob_buf_free(&uh->headers);
703 blob_buf_free(&uh->meta);
708 uclient_http_set_request_type(struct uclient *cl, const char *type)
710 struct uclient_http *uh = container_of(cl, struct uclient_http, uc);
713 if (cl->backend != &uclient_backend_http)
716 if (uh->state > HTTP_STATE_INIT)
719 for (i = 0; i < ARRAY_SIZE(request_types); i++) {
720 if (strcmp(request_types[i], type) != 0)
731 uclient_http_reset_headers(struct uclient *cl, const char *name, const char *value)
733 struct uclient_http *uh = container_of(cl, struct uclient_http, uc);
735 blob_buf_init(&uh->headers, 0);
741 uclient_http_set_header(struct uclient *cl, const char *name, const char *value)
743 struct uclient_http *uh = container_of(cl, struct uclient_http, uc);
745 if (cl->backend != &uclient_backend_http)
748 if (uh->state > HTTP_STATE_INIT)
751 blobmsg_add_string(&uh->headers, name, value);
756 uclient_http_send_data(struct uclient *cl, char *buf, unsigned int len)
758 struct uclient_http *uh = container_of(cl, struct uclient_http, uc);
760 if (uh->state >= HTTP_STATE_REQUEST_DONE)
763 uclient_http_send_headers(uh);
765 ustream_printf(uh->us, "%X\r\n", len);
767 ustream_write(uh->us, buf, len, false);
768 ustream_printf(uh->us, "\r\n");
774 uclient_http_request_done(struct uclient *cl)
776 struct uclient_http *uh = container_of(cl, struct uclient_http, uc);
778 if (uh->state >= HTTP_STATE_REQUEST_DONE)
781 uclient_http_send_headers(uh);
782 uh->state = HTTP_STATE_REQUEST_DONE;
788 uclient_http_read(struct uclient *cl, char *buf, unsigned int len)
790 struct uclient_http *uh = container_of(cl, struct uclient_http, uc);
792 char *data, *data_end;
794 if (uh->state < HTTP_STATE_RECV_DATA || !uh->us)
797 data = ustream_get_read_buf(uh->us, &read_len);
798 if (!data || !read_len)
801 data_end = data + read_len;
804 if (uh->read_chunked == 0) {
807 if (data[0] == '\r' && data[1] == '\n') {
812 sep = strstr(data, "\r\n");
817 uh->read_chunked = strtoul(data, NULL, 16);
819 read_len += sep + 2 - data;
822 if (!uh->read_chunked)
826 if (len > data_end - data)
827 len = data_end - data;
829 if (uh->read_chunked >= 0) {
830 if (len > uh->read_chunked)
831 len = uh->read_chunked;
833 uh->read_chunked -= len;
834 } else if (uh->content_length >= 0) {
835 if (len > uh->content_length)
836 len = uh->content_length;
838 uh->content_length -= len;
839 if (!uh->content_length)
845 memcpy(buf, data, len);
849 ustream_consume(uh->us, read_len);
851 uclient_notify_eof(uh);
856 bool uclient_http_redirect(struct uclient *cl)
858 struct uclient_http *uh = container_of(cl, struct uclient_http, uc);
859 struct blobmsg_policy location = {
861 .type = BLOBMSG_TYPE_STRING,
863 struct uclient_url *url = cl->url;
864 struct blob_attr *tb;
866 if (cl->backend != &uclient_backend_http)
869 switch (cl->status_code) {
878 blobmsg_parse(&location, 1, &tb, blob_data(uh->meta.head), blob_len(uh->meta.head));
882 url = uclient_get_url(blobmsg_data(tb), url->auth);
888 uclient_http_connect(cl);
889 uclient_http_request_done(cl);
894 const struct uclient_backend uclient_backend_http = {
895 .prefix = uclient_http_prefix,
897 .alloc = uclient_http_alloc,
898 .free = uclient_http_free,
899 .connect = uclient_http_connect,
900 .update_url = uclient_http_free_url_state,
902 .read = uclient_http_read,
903 .write = uclient_http_send_data,
904 .request = uclient_http_request_done,