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;
47 enum request_type req_type;
48 enum http_state state;
50 struct blob_buf headers;
60 static const char * const uclient_http_prefix[] = {
61 [PREFIX_HTTP] = "http://",
62 [PREFIX_HTTPS] = "https://",
66 static int uclient_do_connect(struct uclient_http *uh, const char *port)
71 port = uh->uc.url->port;
73 fd = usock(USOCK_TCP | USOCK_NONBLOCK, uh->uc.url->host, port);
77 ustream_fd_init(&uh->ufd, fd);
81 static void uclient_notify_eof(struct uclient_http *uh)
83 struct ustream *us = uh->us;
85 if (!us->eof && !us->write_error)
88 if (ustream_pending_data(us, false))
91 uclient_backend_set_eof(&uh->uc);
94 static void uclient_parse_http_line(struct uclient_http *uh, char *data)
99 if (uh->state == HTTP_STATE_REQUEST_DONE) {
100 uh->state = HTTP_STATE_RECV_HEADERS;
105 uh->state = HTTP_STATE_RECV_DATA;
106 uh->uc.meta = uh->meta.head;
107 if (uh->uc.cb->header_done)
108 uh->uc.cb->header_done(&uh->uc);
112 sep = strchr(data, ':');
118 for (name = data; *name; name++)
119 *name = tolower(*name);
122 while (isspace(*sep))
125 blobmsg_add_string(&uh->meta, name, sep);
128 static void __uclient_notify_read(struct uclient_http *uh)
130 struct uclient *uc = &uh->uc;
134 if (uh->state < HTTP_STATE_REQUEST_DONE)
137 data = ustream_get_read_buf(uh->us, &len);
141 if (uh->state < HTTP_STATE_RECV_DATA) {
146 sep = strstr(data, "\r\n");
150 /* Check for multi-line HTTP headers */
155 if (isspace(sep[2]) && sep[2] != '\r') {
163 cur_len = sep + 2 - data;
164 uclient_parse_http_line(uh, data);
165 ustream_consume(uh->us, cur_len);
168 data = ustream_get_read_buf(uh->us, &len);
169 } while (uh->state < HTTP_STATE_RECV_DATA);
175 if (uh->state == HTTP_STATE_RECV_DATA && uc->cb->data_read)
176 uc->cb->data_read(uc);
179 static void uclient_notify_read(struct ustream *us, int bytes)
181 struct uclient_http *uh = container_of(us, struct uclient_http, ufd.stream);
183 __uclient_notify_read(uh);
186 static void uclient_notify_state(struct ustream *us)
188 struct uclient_http *uh = container_of(us, struct uclient_http, ufd.stream);
190 uclient_notify_eof(uh);
193 static int uclient_setup_http(struct uclient_http *uh)
195 struct ustream *us = &uh->ufd.stream;
199 us->string_data = true;
200 us->notify_state = uclient_notify_state;
201 us->notify_read = uclient_notify_read;
203 ret = uclient_do_connect(uh, "80");
210 static void uclient_ssl_notify_read(struct ustream *us, int bytes)
212 struct uclient_http *uh = container_of(us, struct uclient_http, ussl.stream);
214 __uclient_notify_read(uh);
217 static void uclient_ssl_notify_state(struct ustream *us)
219 struct uclient_http *uh = container_of(us, struct uclient_http, ussl.stream);
221 uclient_notify_eof(uh);
224 static int uclient_setup_https(struct uclient_http *uh)
226 struct ustream *us = &uh->ussl.stream;
232 ret = uclient_do_connect(uh, "443");
237 ssl_ctx = ustream_ssl_context_new(false);
239 us->string_data = true;
240 us->notify_state = uclient_ssl_notify_state;
241 us->notify_read = uclient_ssl_notify_read;
242 ustream_ssl_init(&uh->ussl, &uh->ufd.stream, ssl_ctx, false);
247 static void uclient_http_disconnect(struct uclient_http *uh)
249 uclient_backend_reset_state(&uh->uc);
255 ustream_free(&uh->ussl.stream);
256 ustream_free(&uh->ufd.stream);
257 close(uh->ufd.fd.fd);
261 static int uclient_http_connect(struct uclient *cl)
263 struct uclient_http *uh = container_of(cl, struct uclient_http, uc);
265 uclient_http_disconnect(uh);
266 blob_buf_init(&uh->meta, 0);
268 uh->ssl = cl->url->prefix == PREFIX_HTTPS;
269 uh->state = HTTP_STATE_INIT;
272 return uclient_setup_https(uh);
274 return uclient_setup_http(uh);
277 static struct uclient *uclient_http_alloc(void)
279 struct uclient_http *uh;
281 uh = calloc_a(sizeof(*uh));
282 blob_buf_init(&uh->headers, 0);
287 static void uclient_http_free(struct uclient *cl)
289 struct uclient_http *uh = container_of(cl, struct uclient_http, uc);
291 uclient_http_disconnect(uh);
292 blob_buf_free(&uh->headers);
293 blob_buf_free(&uh->meta);
298 uclient_http_set_request_type(struct uclient *cl, const char *type)
300 struct uclient_http *uh = container_of(cl, struct uclient_http, uc);
303 if (cl->backend != &uclient_backend_http)
306 if (uh->state > HTTP_STATE_INIT)
309 for (i = 0; i < ARRAY_SIZE(request_types); i++) {
310 if (strcmp(request_types[i], type) != 0)
321 uclient_http_reset_headers(struct uclient *cl, const char *name, const char *value)
323 struct uclient_http *uh = container_of(cl, struct uclient_http, uc);
325 blob_buf_init(&uh->headers, 0);
331 uclient_http_set_header(struct uclient *cl, const char *name, const char *value)
333 struct uclient_http *uh = container_of(cl, struct uclient_http, uc);
335 if (cl->backend != &uclient_backend_http)
338 if (uh->state > HTTP_STATE_INIT)
341 blobmsg_add_string(&uh->headers, name, value);
345 #define ustream_printf(us, ...) do { \
346 fprintf(stderr, "send: " __VA_ARGS__); \
347 ustream_printf(us, __VA_ARGS__); \
352 uclient_http_send_headers(struct uclient_http *uh)
354 struct uclient_url *url = uh->uc.url;
355 struct blob_attr *cur;
358 if (uh->state >= HTTP_STATE_HEADERS_SENT)
361 ustream_printf(uh->us,
362 "%s /%s HTTP/1.1\r\n"
364 "Connection: close\r\n",
365 request_types[uh->req_type],
366 url->location, url->host);
368 blobmsg_for_each_attr(cur, uh->headers.head, rem)
369 ustream_printf(uh->us, "%s: %s\n", blobmsg_name(cur), (char *) blobmsg_data(cur));
372 int auth_len = strlen(url->auth);
378 auth_buf = alloca(base64_len(auth_len) + 1);
379 base64_encode(url->auth, auth_len, auth_buf);
380 ustream_printf(uh->us, "Authorization: Basic %s\r\n", auth_buf);
383 if (uh->req_type == REQ_POST)
384 ustream_printf(uh->us, "Transfer-Encoding: chunked\r\n");
386 ustream_printf(uh->us, "\r\n");
390 uclient_http_send_data(struct uclient *cl, char *buf, unsigned int len)
392 struct uclient_http *uh = container_of(cl, struct uclient_http, uc);
394 if (uh->state >= HTTP_STATE_REQUEST_DONE)
397 uclient_http_send_headers(uh);
399 ustream_printf(uh->us, "%X\r\n", len);
400 ustream_write(uh->us, buf, len, false);
401 ustream_printf(uh->us, "\r\n");
407 uclient_http_request_done(struct uclient *cl)
409 struct uclient_http *uh = container_of(cl, struct uclient_http, uc);
411 if (uh->state >= HTTP_STATE_REQUEST_DONE)
414 uclient_http_send_headers(uh);
415 uh->state = HTTP_STATE_REQUEST_DONE;
421 uclient_http_read(struct uclient *cl, char *buf, unsigned int len)
423 struct uclient_http *uh = container_of(cl, struct uclient_http, uc);
427 if (uh->state < HTTP_STATE_RECV_DATA)
430 data = ustream_get_read_buf(uh->us, &data_len);
431 if (!data || !data_len)
437 memcpy(buf, data, len);
438 ustream_consume(uh->us, len);
439 uclient_notify_eof(uh);
444 const struct uclient_backend uclient_backend_http __hidden = {
445 .prefix = uclient_http_prefix,
447 .alloc = uclient_http_alloc,
448 .free = uclient_http_free,
449 .connect = uclient_http_connect,
451 .read = uclient_http_read,
452 .write = uclient_http_send_data,
453 .request = uclient_http_request_done,