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;
56 bool connection_close;
57 enum request_type req_type;
58 enum http_state state;
60 enum auth_type auth_type;
68 struct blob_buf headers;
78 static const char * const uclient_http_prefix[] = {
79 [PREFIX_HTTP] = "http://",
80 [PREFIX_HTTPS] = "https://",
84 static int uclient_do_connect(struct uclient_http *uh, const char *port)
89 port = uh->uc.url->port;
91 fd = usock(USOCK_TCP | USOCK_NONBLOCK, uh->uc.url->host, port);
95 ustream_fd_init(&uh->ufd, fd);
99 static void uclient_http_disconnect(struct uclient_http *uh)
105 ustream_free(&uh->ussl.stream);
106 ustream_free(&uh->ufd.stream);
107 close(uh->ufd.fd.fd);
111 static void uclient_http_free_url_state(struct uclient *cl)
113 struct uclient_http *uh = container_of(cl, struct uclient_http, uc);
115 uh->auth_type = AUTH_TYPE_UNKNOWN;
118 uclient_http_disconnect(uh);
121 static void uclient_notify_eof(struct uclient_http *uh)
123 struct ustream *us = uh->us;
126 if (!us->eof && !us->write_error)
129 if (ustream_pending_data(us, false))
133 uclient_backend_set_eof(&uh->uc);
135 if (uh->connection_close)
136 uclient_http_disconnect(uh);
139 static void uclient_http_reset_state(struct uclient_http *uh)
141 uclient_backend_reset_state(&uh->uc);
142 uh->read_chunked = -1;
143 uh->content_length = -1;
145 uh->connection_close = false;
146 uh->state = HTTP_STATE_INIT;
148 if (uh->auth_type == AUTH_TYPE_UNKNOWN && !uh->uc.url->auth)
149 uh->auth_type = AUTH_TYPE_NONE;
152 static void uclient_http_init_request(struct uclient_http *uh)
154 uclient_http_reset_state(uh);
155 blob_buf_init(&uh->meta, 0);
158 static enum auth_type
159 uclient_http_update_auth_type(struct uclient_http *uh)
162 return AUTH_TYPE_NONE;
164 if (!strncasecmp(uh->auth_str, "basic", 5))
165 return AUTH_TYPE_BASIC;
167 if (!strncasecmp(uh->auth_str, "digest", 6))
168 return AUTH_TYPE_DIGEST;
170 return AUTH_TYPE_NONE;
173 static void uclient_http_process_headers(struct uclient_http *uh)
176 HTTP_HDR_TRANSFER_ENCODING,
178 HTTP_HDR_CONTENT_LENGTH,
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"),
190 struct blob_attr *tb[__HTTP_HDR_MAX];
191 struct blob_attr *cur;
193 blobmsg_parse(hdr_policy, __HTTP_HDR_MAX, tb, blob_data(uh->meta.head), blob_len(uh->meta.head));
195 cur = tb[HTTP_HDR_TRANSFER_ENCODING];
196 if (cur && strstr(blobmsg_data(cur), "chunked"))
197 uh->read_chunked = 0;
199 cur = tb[HTTP_HDR_CONNECTION];
200 if (cur && strstr(blobmsg_data(cur), "close"))
201 uh->connection_close = true;
203 cur = tb[HTTP_HDR_CONTENT_LENGTH];
205 uh->content_length = strtoul(blobmsg_data(cur), NULL, 10);
207 cur = tb[HTTP_HDR_AUTH];
210 uh->auth_str = strdup(blobmsg_data(cur));
213 uh->auth_type = uclient_http_update_auth_type(uh);
217 uclient_http_add_auth_basic(struct uclient_http *uh)
219 struct uclient_url *url = uh->uc.url;
220 int auth_len = strlen(url->auth);
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);
231 static char *digest_unquote_sep(char **str)
233 char *cur = *str + 1;
265 static bool strmatch(char **str, const char *prefix)
267 int len = strlen(prefix);
269 if (strncmp(*str, prefix, len) != 0 || (*str)[len] != '=')
277 get_cnonce(char *dest)
282 f = fopen("/dev/urandom", "r");
284 fread(&val, sizeof(val), 1, f);
288 bin_to_hex(dest, &val, sizeof(val));
291 static void add_field(char **buf, int *ofs, int *len, const char *name, const char *val)
293 int available = *len - *ofs;
301 required = strlen(name) + 4 + strlen(val) * 2;
302 if (required > available)
303 *len += required - available + 64;
305 *buf = realloc(*buf, *len);
310 cur += sprintf(cur, ", %s=\"", name);
312 while ((next = strchr(val, '"'))) {
314 memcpy(cur, val, next - val);
318 cur += sprintf(cur, "\\\"");
322 cur += sprintf(cur, "%s\"", val);
327 uclient_http_add_auth_digest(struct uclient_http *uh)
329 struct uclient_url *url = uh->uc.url;
330 const char *realm = NULL, *opaque = NULL;
331 const char *user, *password;
340 struct http_digest_data data = {
342 .cnonce = cnonce_str,
346 len = strlen(uh->auth_str) + 1;
351 strcpy(buf, uh->auth_str);
358 const char **dest = NULL;
360 while (isspace(*next))
363 if (strmatch(&next, "realm"))
365 else if (strmatch(&next, "qop"))
367 else if (strmatch(&next, "nonce"))
369 else if (strmatch(&next, "opaque"))
374 *dest = digest_unquote_sep(&next);
377 if (!realm || !data.qop || !data.nonce)
380 sprintf(nc_str, "%08x", uh->nc++);
381 get_cnonce(cnonce_str);
384 data.uri = url->location;
385 data.method = request_types[uh->req_type];
387 password = strchr(url->auth, ':');
391 len = password - url->auth;
395 user_buf = alloca(len + 1);
396 strncpy(user_buf, url->auth, len);
405 http_digest_calculate_auth_hash(ahash, user, realm, password);
406 http_digest_calculate_response(hash, &data);
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);
419 add_field(&buf, &ofs, &len, "opaque", opaque);
421 ustream_printf(uh->us, "Authorization: Digest nc=%s, qop=%s%s\r\n", data.nc, data.qop, buf);
426 uclient_http_add_auth_header(struct uclient_http *uh)
428 if (!uh->uc.url->auth)
431 switch (uh->auth_type) {
432 case AUTH_TYPE_UNKNOWN:
435 case AUTH_TYPE_BASIC:
436 uclient_http_add_auth_basic(uh);
438 case AUTH_TYPE_DIGEST:
439 uclient_http_add_auth_digest(uh);
445 uclient_http_send_headers(struct uclient_http *uh)
447 struct uclient_url *url = uh->uc.url;
448 struct blob_attr *cur;
449 enum request_type req_type = uh->req_type;
452 if (uh->state >= HTTP_STATE_HEADERS_SENT)
455 if (uh->auth_type == AUTH_TYPE_UNKNOWN)
458 ustream_printf(uh->us,
461 request_types[req_type],
462 url->location, url->host);
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));
467 if (uh->req_type == REQ_POST)
468 ustream_printf(uh->us, "Transfer-Encoding: chunked\r\n");
470 uclient_http_add_auth_header(uh);
472 ustream_printf(uh->us, "\r\n");
475 static void uclient_http_headers_complete(struct uclient_http *uh)
477 enum auth_type auth_type = uh->auth_type;
479 uh->state = HTTP_STATE_RECV_DATA;
480 uh->uc.meta = uh->meta.head;
481 uclient_http_process_headers(uh);
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;
490 if (uh->uc.cb->header_done)
491 uh->uc.cb->header_done(&uh->uc);
493 if (uh->req_type == REQ_HEAD) {
495 uclient_notify_eof(uh);
499 static void uclient_parse_http_line(struct uclient_http *uh, char *data)
504 if (uh->state == HTTP_STATE_REQUEST_DONE) {
510 code = strsep(&data, " ");
514 uh->uc.status_code = strtoul(code, &sep, 10);
518 uh->state = HTTP_STATE_RECV_HEADERS;
523 uclient_http_headers_complete(uh);
527 sep = strchr(data, ':');
533 for (name = data; *name; name++)
534 *name = tolower(*name);
537 while (isspace(*sep))
540 blobmsg_add_string(&uh->meta, name, sep);
544 uh->uc.status_code = 400;
546 uclient_notify_eof(uh);
549 static void __uclient_notify_read(struct uclient_http *uh)
551 struct uclient *uc = &uh->uc;
555 if (uh->state < HTTP_STATE_REQUEST_DONE)
558 data = ustream_get_read_buf(uh->us, &len);
562 if (uh->state < HTTP_STATE_RECV_DATA) {
567 sep = strstr(data, "\r\n");
571 /* Check for multi-line HTTP headers */
576 if (isspace(sep[2]) && sep[2] != '\r') {
584 cur_len = sep + 2 - data;
585 uclient_parse_http_line(uh, data);
586 ustream_consume(uh->us, cur_len);
589 data = ustream_get_read_buf(uh->us, &len);
590 } while (data && uh->state < HTTP_STATE_RECV_DATA);
596 if (uh->state == HTTP_STATE_RECV_DATA && uc->cb->data_read)
597 uc->cb->data_read(uc);
600 static void uclient_notify_read(struct ustream *us, int bytes)
602 struct uclient_http *uh = container_of(us, struct uclient_http, ufd.stream);
604 __uclient_notify_read(uh);
607 static void uclient_notify_state(struct ustream *us)
609 struct uclient_http *uh = container_of(us, struct uclient_http, ufd.stream);
611 uclient_notify_eof(uh);
614 static int uclient_setup_http(struct uclient_http *uh)
616 struct ustream *us = &uh->ufd.stream;
620 us->string_data = true;
621 us->notify_state = uclient_notify_state;
622 us->notify_read = uclient_notify_read;
624 ret = uclient_do_connect(uh, "80");
631 static void uclient_ssl_notify_read(struct ustream *us, int bytes)
633 struct uclient_http *uh = container_of(us, struct uclient_http, ussl.stream);
635 __uclient_notify_read(uh);
638 static void uclient_ssl_notify_state(struct ustream *us)
640 struct uclient_http *uh = container_of(us, struct uclient_http, ussl.stream);
642 uclient_notify_eof(uh);
645 static int uclient_setup_https(struct uclient_http *uh)
647 struct ustream *us = &uh->ussl.stream;
653 ret = uclient_do_connect(uh, "443");
658 uh->ssl_ctx = ustream_ssl_context_new(false);
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);
668 static int uclient_http_connect(struct uclient *cl)
670 struct uclient_http *uh = container_of(cl, struct uclient_http, uc);
673 uclient_http_init_request(uh);
678 uh->ssl = cl->url->prefix == PREFIX_HTTPS;
681 ret = uclient_setup_https(uh);
683 ret = uclient_setup_http(uh);
686 uh->state = HTTP_STATE_ERROR;
691 static struct uclient *uclient_http_alloc(void)
693 struct uclient_http *uh;
695 uh = calloc_a(sizeof(*uh));
696 blob_buf_init(&uh->headers, 0);
701 static void uclient_http_free_ssl_ctx(struct uclient_http *uh)
703 if (uh->ssl_ctx && !uh->ssl_ctx_ext)
704 ustream_ssl_context_free(uh->ssl_ctx);
706 uh->ssl_ctx_ext = false;
709 static void uclient_http_free(struct uclient *cl)
711 struct uclient_http *uh = container_of(cl, struct uclient_http, uc);
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);
721 uclient_http_set_request_type(struct uclient *cl, const char *type)
723 struct uclient_http *uh = container_of(cl, struct uclient_http, uc);
726 if (cl->backend != &uclient_backend_http)
729 if (uh->state > HTTP_STATE_INIT)
732 for (i = 0; i < ARRAY_SIZE(request_types); i++) {
733 if (strcmp(request_types[i], type) != 0)
744 uclient_http_reset_headers(struct uclient *cl, const char *name, const char *value)
746 struct uclient_http *uh = container_of(cl, struct uclient_http, uc);
748 blob_buf_init(&uh->headers, 0);
754 uclient_http_set_header(struct uclient *cl, const char *name, const char *value)
756 struct uclient_http *uh = container_of(cl, struct uclient_http, uc);
758 if (cl->backend != &uclient_backend_http)
761 if (uh->state > HTTP_STATE_INIT)
764 blobmsg_add_string(&uh->headers, name, value);
769 uclient_http_send_data(struct uclient *cl, char *buf, unsigned int len)
771 struct uclient_http *uh = container_of(cl, struct uclient_http, uc);
773 if (uh->state >= HTTP_STATE_REQUEST_DONE)
776 uclient_http_send_headers(uh);
778 ustream_printf(uh->us, "%X\r\n", len);
780 ustream_write(uh->us, buf, len, false);
781 ustream_printf(uh->us, "\r\n");
787 uclient_http_request_done(struct uclient *cl)
789 struct uclient_http *uh = container_of(cl, struct uclient_http, uc);
791 if (uh->state >= HTTP_STATE_REQUEST_DONE)
794 uclient_http_send_headers(uh);
795 uh->state = HTTP_STATE_REQUEST_DONE;
801 uclient_http_read(struct uclient *cl, char *buf, unsigned int len)
803 struct uclient_http *uh = container_of(cl, struct uclient_http, uc);
805 char *data, *data_end;
807 if (uh->state < HTTP_STATE_RECV_DATA || !uh->us)
810 data = ustream_get_read_buf(uh->us, &read_len);
811 if (!data || !read_len)
814 data_end = data + read_len;
817 if (uh->read_chunked == 0) {
820 if (data[0] == '\r' && data[1] == '\n') {
825 sep = strstr(data, "\r\n");
830 uh->read_chunked = strtoul(data, NULL, 16);
832 read_len += sep + 2 - data;
835 if (!uh->read_chunked)
839 if (len > data_end - data)
840 len = data_end - data;
842 if (uh->read_chunked >= 0) {
843 if (len > uh->read_chunked)
844 len = uh->read_chunked;
846 uh->read_chunked -= len;
847 } else if (uh->content_length >= 0) {
848 if (len > uh->content_length)
849 len = uh->content_length;
851 uh->content_length -= len;
852 if (!uh->content_length)
858 memcpy(buf, data, len);
862 ustream_consume(uh->us, read_len);
864 uclient_notify_eof(uh);
869 bool uclient_http_redirect(struct uclient *cl)
871 struct uclient_http *uh = container_of(cl, struct uclient_http, uc);
872 struct blobmsg_policy location = {
874 .type = BLOBMSG_TYPE_STRING,
876 struct uclient_url *url = cl->url;
877 struct blob_attr *tb;
879 if (cl->backend != &uclient_backend_http)
882 switch (cl->status_code) {
891 blobmsg_parse(&location, 1, &tb, blob_data(uh->meta.head), blob_len(uh->meta.head));
895 url = uclient_get_url(blobmsg_data(tb), url->auth);
901 uclient_http_connect(cl);
902 uclient_http_request_done(cl);
907 int uclient_http_set_ssl_ctx(struct uclient *cl, struct ustream_ssl_ctx *ctx)
909 struct uclient_http *uh = container_of(cl, struct uclient_http, uc);
911 uclient_http_free_url_state(cl);
913 uclient_http_free_ssl_ctx(uh);
915 uh->ssl_ctx_ext = !!ctx;
920 const struct uclient_backend uclient_backend_http = {
921 .prefix = uclient_http_prefix,
923 .alloc = uclient_http_alloc,
924 .free = uclient_http_free,
925 .connect = uclient_http_connect,
926 .update_url = uclient_http_free_url_state,
928 .read = uclient_http_read,
929 .write = uclient_http_send_data,
930 .request = uclient_http_request_done,