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 unsigned int send_len;
52 struct blob_buf headers;
62 static const char * const uclient_http_prefix[] = {
63 [PREFIX_HTTP] = "http://",
64 [PREFIX_HTTPS] = "https://",
68 static int uclient_do_connect(struct uclient_http *uh, const char *port)
73 port = uh->uc.url->port;
75 fd = usock(USOCK_TCP | USOCK_NONBLOCK, uh->uc.url->host, port);
79 ustream_fd_init(&uh->ufd, fd);
83 static void uclient_notify_eof(struct uclient_http *uh)
85 struct ustream *us = uh->us;
87 if (!us->eof && !us->write_error)
90 if (ustream_pending_data(us, false))
93 uclient_backend_set_eof(&uh->uc);
96 static void uclient_parse_http_line(struct uclient_http *uh, char *data)
101 if (uh->state == HTTP_STATE_REQUEST_DONE) {
102 uh->state = HTTP_STATE_RECV_HEADERS;
107 uh->state = HTTP_STATE_RECV_DATA;
108 uh->uc.meta = uh->meta.head;
109 if (uh->uc.cb->header_done)
110 uh->uc.cb->header_done(&uh->uc);
114 sep = strchr(data, ':');
120 for (name = data; *name; name++)
121 *name = tolower(*name);
124 while (isspace(*sep))
127 blobmsg_add_string(&uh->meta, name, sep);
130 static void __uclient_notify_read(struct uclient_http *uh)
132 struct uclient *uc = &uh->uc;
136 if (uh->state < HTTP_STATE_REQUEST_DONE)
139 data = ustream_get_read_buf(uh->us, &len);
143 if (uh->state < HTTP_STATE_RECV_DATA) {
148 sep = strstr(data, "\r\n");
152 /* Check for multi-line HTTP headers */
157 if (isspace(sep[2]) && sep[2] != '\r') {
165 cur_len = sep + 2 - data;
166 uclient_parse_http_line(uh, data);
167 ustream_consume(uh->us, cur_len);
170 data = ustream_get_read_buf(uh->us, &len);
171 } while (uh->state < HTTP_STATE_RECV_DATA);
177 if (uh->state == HTTP_STATE_RECV_DATA && uc->cb->data_read)
178 uc->cb->data_read(uc);
181 static void uclient_notify_read(struct ustream *us, int bytes)
183 struct uclient_http *uh = container_of(us, struct uclient_http, ufd.stream);
185 __uclient_notify_read(uh);
188 static void uclient_notify_state(struct ustream *us)
190 struct uclient_http *uh = container_of(us, struct uclient_http, ufd.stream);
192 uclient_notify_eof(uh);
195 static int uclient_setup_http(struct uclient_http *uh)
197 struct ustream *us = &uh->ufd.stream;
201 us->string_data = true;
202 us->notify_state = uclient_notify_state;
203 us->notify_read = uclient_notify_read;
205 ret = uclient_do_connect(uh, "80");
212 static void uclient_ssl_notify_read(struct ustream *us, int bytes)
214 struct uclient_http *uh = container_of(us, struct uclient_http, ussl.stream);
216 __uclient_notify_read(uh);
219 static void uclient_ssl_notify_state(struct ustream *us)
221 struct uclient_http *uh = container_of(us, struct uclient_http, ussl.stream);
223 uclient_notify_eof(uh);
226 static int uclient_setup_https(struct uclient_http *uh)
228 struct ustream *us = &uh->ussl.stream;
234 ret = uclient_do_connect(uh, "443");
239 ssl_ctx = ustream_ssl_context_new(false);
241 us->string_data = true;
242 us->notify_state = uclient_ssl_notify_state;
243 us->notify_read = uclient_ssl_notify_read;
244 ustream_ssl_init(&uh->ussl, &uh->ufd.stream, ssl_ctx, false);
249 static void uclient_http_disconnect(struct uclient_http *uh)
251 uclient_backend_reset_state(&uh->uc);
257 ustream_free(&uh->ussl.stream);
258 ustream_free(&uh->ufd.stream);
259 close(uh->ufd.fd.fd);
263 static int uclient_http_connect(struct uclient *cl)
265 struct uclient_http *uh = container_of(cl, struct uclient_http, uc);
267 uclient_http_disconnect(uh);
268 blob_buf_init(&uh->meta, 0);
270 uh->ssl = cl->url->prefix == PREFIX_HTTPS;
271 uh->state = HTTP_STATE_INIT;
274 return uclient_setup_https(uh);
276 return uclient_setup_http(uh);
279 static struct uclient *uclient_http_alloc(void)
281 struct uclient_http *uh;
283 uh = calloc_a(sizeof(*uh));
284 blob_buf_init(&uh->headers, 0);
289 static void uclient_http_free(struct uclient *cl)
291 struct uclient_http *uh = container_of(cl, struct uclient_http, uc);
293 uclient_http_disconnect(uh);
294 blob_buf_free(&uh->headers);
295 blob_buf_free(&uh->meta);
300 uclient_http_set_request_type(struct uclient *cl, const char *type)
302 struct uclient_http *uh = container_of(cl, struct uclient_http, uc);
305 if (cl->backend != &uclient_backend_http)
308 if (uh->state > HTTP_STATE_INIT)
311 for (i = 0; i < ARRAY_SIZE(request_types); i++) {
312 if (strcmp(request_types[i], type) != 0)
323 uclient_http_reset_headers(struct uclient *cl, const char *name, const char *value)
325 struct uclient_http *uh = container_of(cl, struct uclient_http, uc);
327 blob_buf_init(&uh->headers, 0);
333 uclient_http_set_header(struct uclient *cl, const char *name, const char *value)
335 struct uclient_http *uh = container_of(cl, struct uclient_http, uc);
337 if (cl->backend != &uclient_backend_http)
340 if (uh->state > HTTP_STATE_INIT)
343 blobmsg_add_string(&uh->headers, name, value);
347 #define ustream_printf(us, ...) do { \
348 fprintf(stderr, "send: " __VA_ARGS__); \
349 ustream_printf(us, __VA_ARGS__); \
354 uclient_http_send_headers(struct uclient_http *uh)
356 struct uclient_url *url = uh->uc.url;
357 struct blob_attr *cur;
360 if (uh->state >= HTTP_STATE_HEADERS_SENT)
363 ustream_printf(uh->us,
364 "%s /%s HTTP/1.0\r\n"
366 request_types[uh->req_type],
367 url->location, url->host);
369 blobmsg_for_each_attr(cur, uh->headers.head, rem)
370 ustream_printf(uh->us, "%s: %s\n", blobmsg_name(cur), (char *) blobmsg_data(cur));
373 int auth_len = strlen(url->auth);
379 auth_buf = alloca(base64_len(auth_len) + 1);
380 base64_encode(url->auth, auth_len, auth_buf);
381 ustream_printf(uh->us, "Authorization: Basic %s\r\n", auth_buf);
384 if (uh->send_len > 0)
385 ustream_printf(uh->us, "Content-Length: %d", uh->send_len);
387 ustream_printf(uh->us, "\r\n");
391 uclient_http_set_write_len(struct uclient *cl, unsigned int len)
393 struct uclient_http *uh = container_of(cl, struct uclient_http, uc);
395 if (uh->state >= HTTP_STATE_HEADERS_SENT)
398 if (uh->req_type == REQ_GET || uh->req_type == REQ_HEAD) {
399 fprintf(stderr, "Sending data is not supported for %s requests\n",
400 request_types[uh->req_type]);
409 uclient_http_send_data(struct uclient *cl, char *buf, unsigned int len)
411 struct uclient_http *uh = container_of(cl, struct uclient_http, uc);
413 if (uh->state >= HTTP_STATE_REQUEST_DONE)
416 uclient_http_send_headers(uh);
418 if (len > uh->send_len) {
419 fprintf(stderr, "%s: ignoring %d extra data bytes\n", __func__, uh->send_len - len);
423 ustream_write(uh->us, buf, len, false);
429 uclient_http_request_done(struct uclient *cl)
431 struct uclient_http *uh = container_of(cl, struct uclient_http, uc);
433 if (uh->state >= HTTP_STATE_REQUEST_DONE)
436 if (uh->send_len > 0)
437 fprintf(stderr, "%s: missing %d POST data bytes\n", __func__, uh->send_len);
439 uclient_http_send_headers(uh);
440 uh->state = HTTP_STATE_REQUEST_DONE;
446 uclient_http_read(struct uclient *cl, char *buf, unsigned int len)
448 struct uclient_http *uh = container_of(cl, struct uclient_http, uc);
452 if (uh->state < HTTP_STATE_RECV_DATA)
455 data = ustream_get_read_buf(uh->us, &data_len);
456 if (!data || !data_len)
462 memcpy(buf, data, len);
463 ustream_consume(uh->us, len);
464 uclient_notify_eof(uh);
469 const struct uclient_backend uclient_backend_http __hidden = {
470 .prefix = uclient_http_prefix,
472 .alloc = uclient_http_alloc,
473 .free = uclient_http_free,
474 .connect = uclient_http_connect,
476 .read = uclient_http_read,
477 .write = uclient_http_send_data,
478 .request = uclient_http_request_done,
480 .set_write_len = uclient_http_set_write_len,