5 #include <libubox/ustream.h>
6 #include <libubox/ustream-ssl.h>
7 #include <libubox/usock.h>
8 #include <libubox/blobmsg.h>
11 #include "uclient-utils.h"
12 #include "uclient-backend.h"
14 static struct ustream_ssl_ctx *ssl_ctx;
25 HTTP_STATE_HEADERS_SENT,
26 HTTP_STATE_REQUEST_DONE,
27 HTTP_STATE_RECV_HEADERS,
32 static const char * const request_types[__REQ_MAX] = {
43 struct ustream_fd ufd;
44 struct ustream_ssl ussl;
48 bool connection_close;
49 enum request_type req_type;
50 enum http_state state;
54 struct blob_buf headers;
64 static const char * const uclient_http_prefix[] = {
65 [PREFIX_HTTP] = "http://",
66 [PREFIX_HTTPS] = "https://",
70 static int uclient_do_connect(struct uclient_http *uh, const char *port)
75 port = uh->uc.url->port;
77 fd = usock(USOCK_TCP | USOCK_NONBLOCK, uh->uc.url->host, port);
81 ustream_fd_init(&uh->ufd, fd);
85 static void uclient_http_disconnect(struct uclient *cl)
87 struct uclient_http *uh = container_of(cl, struct uclient_http, uc);
93 ustream_free(&uh->ussl.stream);
94 ustream_free(&uh->ufd.stream);
99 static void uclient_notify_eof(struct uclient_http *uh)
101 struct ustream *us = uh->us;
104 if (!us->eof && !us->write_error)
107 if (ustream_pending_data(us, false))
111 uclient_backend_set_eof(&uh->uc);
113 if (uh->connection_close)
114 uclient_http_disconnect(&uh->uc);
117 static void uclient_http_process_headers(struct uclient_http *uh)
120 HTTP_HDR_TRANSFER_ENCODING,
124 static const struct blobmsg_policy hdr_policy[__HTTP_HDR_MAX] = {
125 #define hdr(_name) { .name = _name, .type = BLOBMSG_TYPE_STRING }
126 [HTTP_HDR_TRANSFER_ENCODING] = hdr("transfer-encoding"),
127 [HTTP_HDR_CONNECTION] = hdr("connection"),
130 struct blob_attr *tb[__HTTP_HDR_MAX];
131 struct blob_attr *cur;
133 blobmsg_parse(hdr_policy, __HTTP_HDR_MAX, tb, blob_data(uh->meta.head), blob_len(uh->meta.head));
135 cur = tb[HTTP_HDR_TRANSFER_ENCODING];
136 if (cur && strstr(blobmsg_data(cur), "chunked"))
137 uh->read_chunked = 0;
139 cur = tb[HTTP_HDR_CONNECTION];
140 if (cur && strstr(blobmsg_data(cur), "close"))
141 uh->connection_close = true;
144 static void uclient_parse_http_line(struct uclient_http *uh, char *data)
149 if (uh->state == HTTP_STATE_REQUEST_DONE) {
150 uh->state = HTTP_STATE_RECV_HEADERS;
155 uh->state = HTTP_STATE_RECV_DATA;
156 uh->uc.meta = uh->meta.head;
157 uclient_http_process_headers(uh);
158 if (uh->uc.cb->header_done)
159 uh->uc.cb->header_done(&uh->uc);
161 if (uh->req_type == REQ_HEAD) {
163 uclient_notify_eof(uh);
169 sep = strchr(data, ':');
175 for (name = data; *name; name++)
176 *name = tolower(*name);
179 while (isspace(*sep))
182 blobmsg_add_string(&uh->meta, name, sep);
185 static void __uclient_notify_read(struct uclient_http *uh)
187 struct uclient *uc = &uh->uc;
191 if (uh->state < HTTP_STATE_REQUEST_DONE)
194 data = ustream_get_read_buf(uh->us, &len);
198 if (uh->state < HTTP_STATE_RECV_DATA) {
203 sep = strstr(data, "\r\n");
207 /* Check for multi-line HTTP headers */
212 if (isspace(sep[2]) && sep[2] != '\r') {
220 cur_len = sep + 2 - data;
221 uclient_parse_http_line(uh, data);
222 ustream_consume(uh->us, cur_len);
225 data = ustream_get_read_buf(uh->us, &len);
226 } while (uh->state < HTTP_STATE_RECV_DATA);
232 if (uh->state == HTTP_STATE_RECV_DATA && uc->cb->data_read)
233 uc->cb->data_read(uc);
236 static void uclient_notify_read(struct ustream *us, int bytes)
238 struct uclient_http *uh = container_of(us, struct uclient_http, ufd.stream);
240 __uclient_notify_read(uh);
243 static void uclient_notify_state(struct ustream *us)
245 struct uclient_http *uh = container_of(us, struct uclient_http, ufd.stream);
247 uclient_notify_eof(uh);
250 static int uclient_setup_http(struct uclient_http *uh)
252 struct ustream *us = &uh->ufd.stream;
256 us->string_data = true;
257 us->notify_state = uclient_notify_state;
258 us->notify_read = uclient_notify_read;
260 ret = uclient_do_connect(uh, "80");
267 static void uclient_ssl_notify_read(struct ustream *us, int bytes)
269 struct uclient_http *uh = container_of(us, struct uclient_http, ussl.stream);
271 __uclient_notify_read(uh);
274 static void uclient_ssl_notify_state(struct ustream *us)
276 struct uclient_http *uh = container_of(us, struct uclient_http, ussl.stream);
278 uclient_notify_eof(uh);
281 static int uclient_setup_https(struct uclient_http *uh)
283 struct ustream *us = &uh->ussl.stream;
289 ret = uclient_do_connect(uh, "443");
294 ssl_ctx = ustream_ssl_context_new(false);
296 us->string_data = true;
297 us->notify_state = uclient_ssl_notify_state;
298 us->notify_read = uclient_ssl_notify_read;
299 ustream_ssl_init(&uh->ussl, &uh->ufd.stream, ssl_ctx, false);
304 static void uclient_http_reset_state(struct uclient_http *uh)
306 uclient_backend_reset_state(&uh->uc);
307 uh->read_chunked = -1;
309 uh->connection_close = false;
310 uh->state = HTTP_STATE_INIT;
313 static int uclient_http_connect(struct uclient *cl)
315 struct uclient_http *uh = container_of(cl, struct uclient_http, uc);
317 uclient_http_reset_state(uh);
318 blob_buf_init(&uh->meta, 0);
323 uh->ssl = cl->url->prefix == PREFIX_HTTPS;
326 return uclient_setup_https(uh);
328 return uclient_setup_http(uh);
331 static struct uclient *uclient_http_alloc(void)
333 struct uclient_http *uh;
335 uh = calloc_a(sizeof(*uh));
336 blob_buf_init(&uh->headers, 0);
341 static void uclient_http_free(struct uclient *cl)
343 struct uclient_http *uh = container_of(cl, struct uclient_http, uc);
345 uclient_http_disconnect(cl);
346 blob_buf_free(&uh->headers);
347 blob_buf_free(&uh->meta);
352 uclient_http_set_request_type(struct uclient *cl, const char *type)
354 struct uclient_http *uh = container_of(cl, struct uclient_http, uc);
357 if (cl->backend != &uclient_backend_http)
360 if (uh->state > HTTP_STATE_INIT)
363 for (i = 0; i < ARRAY_SIZE(request_types); i++) {
364 if (strcmp(request_types[i], type) != 0)
375 uclient_http_reset_headers(struct uclient *cl, const char *name, const char *value)
377 struct uclient_http *uh = container_of(cl, struct uclient_http, uc);
379 blob_buf_init(&uh->headers, 0);
385 uclient_http_set_header(struct uclient *cl, const char *name, const char *value)
387 struct uclient_http *uh = container_of(cl, struct uclient_http, uc);
389 if (cl->backend != &uclient_backend_http)
392 if (uh->state > HTTP_STATE_INIT)
395 blobmsg_add_string(&uh->headers, name, value);
400 uclient_http_send_headers(struct uclient_http *uh)
402 struct uclient_url *url = uh->uc.url;
403 struct blob_attr *cur;
406 if (uh->state >= HTTP_STATE_HEADERS_SENT)
409 ustream_printf(uh->us,
410 "%s /%s HTTP/1.1\r\n"
412 request_types[uh->req_type],
413 url->location, url->host);
415 blobmsg_for_each_attr(cur, uh->headers.head, rem)
416 ustream_printf(uh->us, "%s: %s\n", blobmsg_name(cur), (char *) blobmsg_data(cur));
419 int auth_len = strlen(url->auth);
425 auth_buf = alloca(base64_len(auth_len) + 1);
426 base64_encode(url->auth, auth_len, auth_buf);
427 ustream_printf(uh->us, "Authorization: Basic %s\r\n", auth_buf);
430 if (uh->req_type == REQ_POST)
431 ustream_printf(uh->us, "Transfer-Encoding: chunked\r\n");
433 ustream_printf(uh->us, "\r\n");
437 uclient_http_send_data(struct uclient *cl, char *buf, unsigned int len)
439 struct uclient_http *uh = container_of(cl, struct uclient_http, uc);
441 if (uh->state >= HTTP_STATE_REQUEST_DONE)
444 uclient_http_send_headers(uh);
446 ustream_printf(uh->us, "%X\r\n", len);
447 ustream_write(uh->us, buf, len, false);
448 ustream_printf(uh->us, "\r\n");
454 uclient_http_request_done(struct uclient *cl)
456 struct uclient_http *uh = container_of(cl, struct uclient_http, uc);
458 if (uh->state >= HTTP_STATE_REQUEST_DONE)
461 uclient_http_send_headers(uh);
462 uh->state = HTTP_STATE_REQUEST_DONE;
468 uclient_http_read(struct uclient *cl, char *buf, unsigned int len)
470 struct uclient_http *uh = container_of(cl, struct uclient_http, uc);
472 char *data, *data_end;
474 if (uh->state < HTTP_STATE_RECV_DATA || !uh->us)
477 data = ustream_get_read_buf(uh->us, &read_len);
478 if (!data || !read_len)
481 data_end = data + read_len;
484 if (uh->read_chunked == 0) {
487 if (data[0] == '\r' && data[1] == '\n') {
492 sep = strstr(data, "\r\n");
497 uh->read_chunked = strtoul(data, NULL, 16);
499 read_len += sep + 2 - data;
502 if (!uh->read_chunked)
506 if (len > data_end - data)
507 len = data_end - data;
509 if (uh->read_chunked >= 0) {
510 if (len > uh->read_chunked)
511 len = uh->read_chunked;
513 uh->read_chunked -= len;
518 memcpy(buf, data, len);
522 ustream_consume(uh->us, read_len);
524 uclient_notify_eof(uh);
529 const struct uclient_backend uclient_backend_http __hidden = {
530 .prefix = uclient_http_prefix,
532 .alloc = uclient_http_alloc,
533 .free = uclient_http_free,
534 .connect = uclient_http_connect,
535 .update_url = uclient_http_disconnect,
537 .read = uclient_http_read,
538 .write = uclient_http_send_data,
539 .request = uclient_http_request_done,