1 /** @file
2 * @brief HTTP client API
3 *
4 * An API for applications to send HTTP requests
5 */
6
7 /*
8 * Copyright (c) 2019 Intel Corporation
9 *
10 * SPDX-License-Identifier: Apache-2.0
11 */
12
13 #include <zephyr/logging/log.h>
14 LOG_MODULE_REGISTER(net_http_client, CONFIG_NET_HTTP_LOG_LEVEL);
15
16 #include <zephyr/kernel.h>
17 #include <string.h>
18 #include <strings.h>
19 #include <errno.h>
20 #include <stdbool.h>
21 #include <stdlib.h>
22
23 #include <zephyr/net/net_ip.h>
24 #include <zephyr/net/socket.h>
25 #include <zephyr/net/http/client.h>
26
27 #include "net_private.h"
28
29 #define HTTP_CONTENT_LEN_SIZE 11
30 #define MAX_SEND_BUF_LEN 192
31
sendall(int sock,const void * buf,size_t len,const k_timepoint_t req_end_timepoint)32 static int sendall(int sock, const void *buf, size_t len,
33 const k_timepoint_t req_end_timepoint)
34 {
35 while (len) {
36 ssize_t out_len = zsock_send(sock, buf, len, 0);
37
38 if ((out_len == 0) || (out_len < 0 && errno == EAGAIN)) {
39 struct zsock_pollfd pfd;
40 int pollres;
41 k_ticks_t req_timeout_ticks =
42 sys_timepoint_timeout(req_end_timepoint).ticks;
43 int req_timeout_ms = k_ticks_to_ms_floor32(req_timeout_ticks);
44
45 pfd.fd = sock;
46 pfd.events = ZSOCK_POLLOUT;
47 pollres = zsock_poll(&pfd, 1, req_timeout_ms);
48 if (pollres == 0) {
49 return -ETIMEDOUT;
50 } else if (pollres > 0) {
51 continue;
52 } else {
53 return -errno;
54 }
55 } else if (out_len < 0) {
56 return -errno;
57 }
58
59 buf = (const char *)buf + out_len;
60 len -= out_len;
61 }
62
63 return 0;
64 }
65
http_send_data(int sock,char * send_buf,size_t send_buf_max_len,size_t * send_buf_pos,const k_timepoint_t req_end_timepoint,...)66 static int http_send_data(int sock, char *send_buf,
67 size_t send_buf_max_len, size_t *send_buf_pos,
68 const k_timepoint_t req_end_timepoint,
69 ...)
70 {
71 const char *data;
72 va_list va;
73 int ret, end_of_send = *send_buf_pos;
74 int end_of_data, remaining_len;
75 int sent = 0;
76
77 va_start(va, req_end_timepoint);
78
79 data = va_arg(va, const char *);
80
81 while (data) {
82 end_of_data = 0;
83
84 do {
85 int to_be_copied;
86
87 remaining_len = strlen(data + end_of_data);
88 to_be_copied = send_buf_max_len - end_of_send;
89
90 if (remaining_len > to_be_copied) {
91 strncpy(send_buf + end_of_send,
92 data + end_of_data,
93 to_be_copied);
94
95 end_of_send += to_be_copied;
96 end_of_data += to_be_copied;
97 remaining_len -= to_be_copied;
98
99 LOG_HEXDUMP_DBG(send_buf, end_of_send,
100 "Data to send");
101
102 ret = sendall(sock, send_buf, end_of_send, req_end_timepoint);
103 if (ret < 0) {
104 NET_DBG("Cannot send %d bytes (%d)",
105 end_of_send, ret);
106 goto err;
107 }
108 sent += end_of_send;
109 end_of_send = 0;
110 continue;
111 } else {
112 strncpy(send_buf + end_of_send,
113 data + end_of_data,
114 remaining_len);
115 end_of_send += remaining_len;
116 remaining_len = 0;
117 }
118 } while (remaining_len > 0);
119
120 data = va_arg(va, const char *);
121 }
122
123 va_end(va);
124
125 if (end_of_send > (int)send_buf_max_len) {
126 NET_ERR("Sending overflow (%d > %zd)", end_of_send,
127 send_buf_max_len);
128 return -EMSGSIZE;
129 }
130
131 *send_buf_pos = end_of_send;
132
133 return sent;
134
135 err:
136 va_end(va);
137
138 return ret;
139 }
140
http_flush_data(int sock,const char * send_buf,size_t send_buf_len,const k_timepoint_t req_end_timepoint)141 static int http_flush_data(int sock, const char *send_buf, size_t send_buf_len,
142 const k_timepoint_t req_end_timepoint)
143 {
144 int ret;
145
146 LOG_HEXDUMP_DBG(send_buf, send_buf_len, "Data to send");
147
148 ret = sendall(sock, send_buf, send_buf_len, req_end_timepoint);
149 if (ret < 0) {
150 return ret;
151 }
152
153 return (int)send_buf_len;
154 }
155
print_header_field(size_t len,const char * str)156 static void print_header_field(size_t len, const char *str)
157 {
158 if (IS_ENABLED(CONFIG_NET_HTTP_LOG_LEVEL_DBG)) {
159 #define MAX_OUTPUT_LEN 128
160 char output[MAX_OUTPUT_LEN];
161
162 /* The value of len does not count \0 so we need to increase it
163 * by one.
164 */
165 if ((len + 1) > sizeof(output)) {
166 len = sizeof(output) - 1;
167 }
168
169 snprintk(output, len + 1, "%s", str);
170
171 NET_DBG("[%zd] %s", len, output);
172 }
173 }
174
on_url(struct http_parser * parser,const char * at,size_t length)175 static int on_url(struct http_parser *parser, const char *at, size_t length)
176 {
177 struct http_request *req = CONTAINER_OF(parser,
178 struct http_request,
179 internal.parser);
180 print_header_field(length, at);
181
182 if (req->internal.response.http_cb &&
183 req->internal.response.http_cb->on_url) {
184 req->internal.response.http_cb->on_url(parser, at, length);
185 }
186
187 return 0;
188 }
189
on_status(struct http_parser * parser,const char * at,size_t length)190 static int on_status(struct http_parser *parser, const char *at, size_t length)
191 {
192 struct http_request *req = CONTAINER_OF(parser,
193 struct http_request,
194 internal.parser);
195 uint16_t len;
196
197 len = MIN(length, sizeof(req->internal.response.http_status) - 1);
198 memcpy(req->internal.response.http_status, at, len);
199 req->internal.response.http_status[len] = 0;
200 req->internal.response.http_status_code =
201 (uint16_t)parser->status_code;
202
203 NET_DBG("HTTP response status %d %s", parser->status_code,
204 req->internal.response.http_status);
205
206 if (req->internal.response.http_cb &&
207 req->internal.response.http_cb->on_status) {
208 req->internal.response.http_cb->on_status(parser, at, length);
209 }
210
211 return 0;
212 }
213
on_header_field(struct http_parser * parser,const char * at,size_t length)214 static int on_header_field(struct http_parser *parser, const char *at,
215 size_t length)
216 {
217 struct http_request *req = CONTAINER_OF(parser,
218 struct http_request,
219 internal.parser);
220 const char *content_len = "Content-Length";
221 uint16_t len;
222
223 len = strlen(content_len);
224 if (length >= len && strncasecmp(at, content_len, len) == 0) {
225 req->internal.response.cl_present = true;
226 }
227
228 print_header_field(length, at);
229
230 if (req->internal.response.http_cb &&
231 req->internal.response.http_cb->on_header_field) {
232 req->internal.response.http_cb->on_header_field(parser, at,
233 length);
234 }
235
236 return 0;
237 }
238
239 #define MAX_NUM_DIGITS 16
240
on_header_value(struct http_parser * parser,const char * at,size_t length)241 static int on_header_value(struct http_parser *parser, const char *at,
242 size_t length)
243 {
244 struct http_request *req = CONTAINER_OF(parser,
245 struct http_request,
246 internal.parser);
247 char str[MAX_NUM_DIGITS];
248
249 if (req->internal.response.cl_present) {
250 if (length <= MAX_NUM_DIGITS - 1) {
251 long int num;
252
253 memcpy(str, at, length);
254 str[length] = 0;
255
256 num = strtol(str, NULL, 10);
257 if (num == LONG_MIN || num == LONG_MAX) {
258 return -EINVAL;
259 }
260
261 req->internal.response.content_length = num;
262 }
263
264 req->internal.response.cl_present = false;
265 }
266
267 if (req->internal.response.http_cb &&
268 req->internal.response.http_cb->on_header_value) {
269 req->internal.response.http_cb->on_header_value(parser, at,
270 length);
271 }
272
273 print_header_field(length, at);
274
275 return 0;
276 }
277
on_body(struct http_parser * parser,const char * at,size_t length)278 static int on_body(struct http_parser *parser, const char *at, size_t length)
279 {
280 struct http_request *req = CONTAINER_OF(parser,
281 struct http_request,
282 internal.parser);
283
284 req->internal.response.body_found = 1;
285 req->internal.response.processed += length;
286
287 NET_DBG("Processed %zd length %zd", req->internal.response.processed,
288 length);
289
290 if (req->internal.response.http_cb &&
291 req->internal.response.http_cb->on_body) {
292 req->internal.response.http_cb->on_body(parser, at, length);
293 }
294
295 /* Reset the body_frag_start pointer for each fragment. */
296 if (!req->internal.response.body_frag_start) {
297 req->internal.response.body_frag_start = (uint8_t *)at;
298 }
299
300 /* Calculate the length of the body contained in the recv_buf */
301 req->internal.response.body_frag_len = req->internal.response.data_len -
302 (req->internal.response.body_frag_start - req->internal.response.recv_buf);
303
304 return 0;
305 }
306
on_headers_complete(struct http_parser * parser)307 static int on_headers_complete(struct http_parser *parser)
308 {
309 struct http_request *req = CONTAINER_OF(parser,
310 struct http_request,
311 internal.parser);
312
313 if (req->internal.response.http_cb &&
314 req->internal.response.http_cb->on_headers_complete) {
315 req->internal.response.http_cb->on_headers_complete(parser);
316 }
317
318 if (parser->status_code >= 500 && parser->status_code < 600) {
319 NET_DBG("Status %d, skipping body", parser->status_code);
320 return 1;
321 }
322
323 if ((req->method == HTTP_HEAD || req->method == HTTP_OPTIONS) &&
324 req->internal.response.content_length > 0) {
325 NET_DBG("No body expected");
326 return 1;
327 }
328
329 NET_DBG("Headers complete");
330
331 return 0;
332 }
333
on_message_begin(struct http_parser * parser)334 static int on_message_begin(struct http_parser *parser)
335 {
336 struct http_request *req = CONTAINER_OF(parser,
337 struct http_request,
338 internal.parser);
339
340 if (req->internal.response.http_cb &&
341 req->internal.response.http_cb->on_message_begin) {
342 req->internal.response.http_cb->on_message_begin(parser);
343 }
344
345 NET_DBG("-- HTTP %s response (headers) --",
346 http_method_str(req->method));
347
348 return 0;
349 }
350
on_message_complete(struct http_parser * parser)351 static int on_message_complete(struct http_parser *parser)
352 {
353 struct http_request *req = CONTAINER_OF(parser,
354 struct http_request,
355 internal.parser);
356
357 if (req->internal.response.http_cb &&
358 req->internal.response.http_cb->on_message_complete) {
359 req->internal.response.http_cb->on_message_complete(parser);
360 }
361
362 NET_DBG("-- HTTP %s response (complete) --",
363 http_method_str(req->method));
364
365 req->internal.response.message_complete = 1;
366
367 return 0;
368 }
369
on_chunk_header(struct http_parser * parser)370 static int on_chunk_header(struct http_parser *parser)
371 {
372 struct http_request *req = CONTAINER_OF(parser,
373 struct http_request,
374 internal.parser);
375
376 if (req->internal.response.http_cb &&
377 req->internal.response.http_cb->on_chunk_header) {
378 req->internal.response.http_cb->on_chunk_header(parser);
379 }
380
381 return 0;
382 }
383
on_chunk_complete(struct http_parser * parser)384 static int on_chunk_complete(struct http_parser *parser)
385 {
386 struct http_request *req = CONTAINER_OF(parser,
387 struct http_request,
388 internal.parser);
389
390 if (req->internal.response.http_cb &&
391 req->internal.response.http_cb->on_chunk_complete) {
392 req->internal.response.http_cb->on_chunk_complete(parser);
393 }
394
395 return 0;
396 }
397
http_client_init_parser(struct http_parser * parser,struct http_parser_settings * settings)398 static void http_client_init_parser(struct http_parser *parser,
399 struct http_parser_settings *settings)
400 {
401 http_parser_init(parser, HTTP_RESPONSE);
402
403 settings->on_body = on_body;
404 settings->on_chunk_complete = on_chunk_complete;
405 settings->on_chunk_header = on_chunk_header;
406 settings->on_headers_complete = on_headers_complete;
407 settings->on_header_field = on_header_field;
408 settings->on_header_value = on_header_value;
409 settings->on_message_begin = on_message_begin;
410 settings->on_message_complete = on_message_complete;
411 settings->on_status = on_status;
412 settings->on_url = on_url;
413 }
414
415 /* Report a NULL HTTP response to the caller.
416 * A NULL response is when the HTTP server intentionally closes the TLS socket (using FINACK)
417 * without sending any HTTP payload.
418 */
http_report_null(struct http_request * req)419 static void http_report_null(struct http_request *req)
420 {
421 if (req->internal.response.cb) {
422 NET_DBG("Calling callback for Final Data"
423 "(NULL HTTP response)");
424
425 /* Status code 0 representing a null response */
426 req->internal.response.http_status_code = 0;
427
428 /* Zero out related response metrics */
429 req->internal.response.processed = 0;
430 req->internal.response.data_len = 0;
431 req->internal.response.content_length = 0;
432 req->internal.response.body_frag_start = NULL;
433 memset(req->internal.response.http_status, 0, HTTP_STATUS_STR_SIZE);
434
435 req->internal.response.cb(&req->internal.response, HTTP_DATA_FINAL,
436 req->internal.user_data);
437 }
438 }
439
440 /* Report a completed HTTP transaction (with no error) to the caller */
http_report_complete(struct http_request * req)441 static void http_report_complete(struct http_request *req)
442 {
443 if (req->internal.response.cb) {
444 NET_DBG("Calling callback for %zd len data", req->internal.response.data_len);
445 req->internal.response.cb(&req->internal.response, HTTP_DATA_FINAL,
446 req->internal.user_data);
447 }
448 }
449
450 /* Report that some data has been received, but the HTTP transaction is still ongoing. */
http_report_progress(struct http_request * req)451 static void http_report_progress(struct http_request *req)
452 {
453 if (req->internal.response.cb) {
454 NET_DBG("Calling callback for partitioned %zd len data",
455 req->internal.response.data_len);
456
457 req->internal.response.cb(&req->internal.response, HTTP_DATA_MORE,
458 req->internal.user_data);
459 }
460 }
461
http_wait_data(int sock,struct http_request * req,const k_timepoint_t req_end_timepoint)462 static int http_wait_data(int sock, struct http_request *req, const k_timepoint_t req_end_timepoint)
463 {
464 int total_received = 0;
465 size_t offset = 0;
466 int received, ret;
467 struct zsock_pollfd fds[1];
468 int nfds = 1;
469
470 fds[0].fd = sock;
471 fds[0].events = ZSOCK_POLLIN;
472
473 do {
474 k_ticks_t req_timeout_ticks =
475 sys_timepoint_timeout(req_end_timepoint).ticks;
476 int req_timeout_ms = k_ticks_to_ms_floor32(req_timeout_ticks);
477
478 ret = zsock_poll(fds, nfds, req_timeout_ms);
479 if (ret == 0) {
480 LOG_DBG("Timeout");
481 ret = -ETIMEDOUT;
482 goto error;
483 } else if (ret < 0) {
484 ret = -errno;
485 goto error;
486 }
487 if (fds[0].revents & (ZSOCK_POLLERR | ZSOCK_POLLNVAL)) {
488 ret = -errno;
489 goto error;
490 } else if (fds[0].revents & ZSOCK_POLLHUP) {
491 /* Connection closed */
492 goto closed;
493 } else if (fds[0].revents & ZSOCK_POLLIN) {
494 received = zsock_recv(sock, req->internal.response.recv_buf + offset,
495 req->internal.response.recv_buf_len - offset, 0);
496 if (received == 0) {
497 /* Connection closed */
498 goto closed;
499 } else if (received < 0) {
500 ret = -errno;
501 goto error;
502 } else {
503 req->internal.response.data_len += received;
504
505 (void)http_parser_execute(
506 &req->internal.parser, &req->internal.parser_settings,
507 req->internal.response.recv_buf + offset, received);
508 }
509
510 total_received += received;
511 offset += received;
512
513 if (offset >= req->internal.response.recv_buf_len) {
514 offset = 0;
515 }
516
517 if (req->internal.response.message_complete) {
518 http_report_complete(req);
519 break;
520 } else if (offset == 0) {
521 http_report_progress(req);
522
523 /* Re-use the result buffer and start to fill it again */
524 req->internal.response.data_len = 0;
525 req->internal.response.body_frag_start = NULL;
526 req->internal.response.body_frag_len = 0;
527 }
528 }
529
530 } while (true);
531
532 return total_received;
533
534 closed:
535 LOG_DBG("Connection closed");
536
537 /* If connection was closed with no data sent, this is a NULL response, and is a special
538 * case valid response.
539 */
540 if (total_received == 0) {
541 http_report_null(req);
542 return total_received;
543 }
544
545 /* Otherwise, connection was closed mid-way through response, and this should be
546 * considered an error.
547 */
548 ret = -ECONNRESET;
549
550 error:
551 LOG_DBG("Connection error (%d)", ret);
552 return ret;
553 }
554
http_client_req(int sock,struct http_request * req,int32_t timeout,void * user_data)555 int http_client_req(int sock, struct http_request *req,
556 int32_t timeout, void *user_data)
557 {
558 /* Utilize the network usage by sending data in bigger blocks */
559 char send_buf[MAX_SEND_BUF_LEN];
560 const size_t send_buf_max_len = sizeof(send_buf);
561 size_t send_buf_pos = 0;
562 int total_sent = 0;
563 int ret, total_recv, i;
564 const char *method;
565 k_timeout_t req_timeout = K_MSEC(timeout);
566 k_timepoint_t req_end_timepoint = sys_timepoint_calc(req_timeout);
567
568 if (sock < 0 || req == NULL || req->response == NULL ||
569 req->recv_buf == NULL || req->recv_buf_len == 0) {
570 return -EINVAL;
571 }
572
573 memset(&req->internal.response, 0, sizeof(req->internal.response));
574
575 req->internal.response.http_cb = req->http_cb;
576 req->internal.response.cb = req->response;
577 req->internal.response.recv_buf = req->recv_buf;
578 req->internal.response.recv_buf_len = req->recv_buf_len;
579 req->internal.user_data = user_data;
580 req->internal.sock = sock;
581
582 method = http_method_str(req->method);
583
584 ret = http_send_data(sock, send_buf, send_buf_max_len, &send_buf_pos,
585 req_end_timepoint, method,
586 " ", req->url, " ", req->protocol,
587 HTTP_CRLF, NULL);
588 if (ret < 0) {
589 goto out;
590 }
591
592 total_sent += ret;
593
594 if (req->port) {
595 ret = http_send_data(sock, send_buf, send_buf_max_len,
596 &send_buf_pos, req_end_timepoint, "Host", ": ", req->host,
597 ":", req->port, HTTP_CRLF, NULL);
598
599 if (ret < 0) {
600 goto out;
601 }
602
603 total_sent += ret;
604 } else {
605 ret = http_send_data(sock, send_buf, send_buf_max_len,
606 &send_buf_pos, req_end_timepoint, "Host", ": ", req->host,
607 HTTP_CRLF, NULL);
608
609 if (ret < 0) {
610 goto out;
611 }
612
613 total_sent += ret;
614 }
615
616 if (req->optional_headers_cb) {
617 ret = http_flush_data(sock, send_buf, send_buf_pos, req_end_timepoint);
618 if (ret < 0) {
619 goto out;
620 }
621
622 send_buf_pos = 0;
623 total_sent += ret;
624
625 ret = req->optional_headers_cb(sock, req, user_data);
626 if (ret < 0) {
627 goto out;
628 }
629
630 total_sent += ret;
631 } else {
632 for (i = 0; req->optional_headers && req->optional_headers[i];
633 i++) {
634 ret = http_send_data(sock, send_buf, send_buf_max_len,
635 &send_buf_pos, req_end_timepoint,
636 req->optional_headers[i], NULL);
637 if (ret < 0) {
638 goto out;
639 }
640
641 total_sent += ret;
642 }
643 }
644
645 for (i = 0; req->header_fields && req->header_fields[i]; i++) {
646 ret = http_send_data(sock, send_buf, send_buf_max_len,
647 &send_buf_pos, req_end_timepoint, req->header_fields[i],
648 NULL);
649 if (ret < 0) {
650 goto out;
651 }
652
653 total_sent += ret;
654 }
655
656 if (req->content_type_value) {
657 ret = http_send_data(sock, send_buf, send_buf_max_len,
658 &send_buf_pos, req_end_timepoint, "Content-Type", ": ",
659 req->content_type_value, HTTP_CRLF, NULL);
660 if (ret < 0) {
661 goto out;
662 }
663
664 total_sent += ret;
665 }
666
667 if (req->payload || req->payload_cb) {
668 if (req->payload_len) {
669 char content_len_str[HTTP_CONTENT_LEN_SIZE];
670
671 ret = snprintk(content_len_str, HTTP_CONTENT_LEN_SIZE,
672 "%zd", req->payload_len);
673 if (ret <= 0 || ret >= HTTP_CONTENT_LEN_SIZE) {
674 ret = -ENOMEM;
675 goto out;
676 }
677
678 ret = http_send_data(sock, send_buf, send_buf_max_len,
679 &send_buf_pos, req_end_timepoint,
680 "Content-Length", ": ",
681 content_len_str, HTTP_CRLF,
682 HTTP_CRLF, NULL);
683 } else {
684 ret = http_send_data(sock, send_buf, send_buf_max_len,
685 &send_buf_pos, req_end_timepoint, HTTP_CRLF, NULL);
686 }
687
688 if (ret < 0) {
689 goto out;
690 }
691
692 total_sent += ret;
693
694 ret = http_flush_data(sock, send_buf, send_buf_pos, req_end_timepoint);
695 if (ret < 0) {
696 goto out;
697 }
698
699 send_buf_pos = 0;
700 total_sent += ret;
701
702 if (req->payload_cb) {
703 ret = req->payload_cb(sock, req, user_data);
704 if (ret < 0) {
705 goto out;
706 }
707
708 total_sent += ret;
709 } else {
710 uint32_t length;
711
712 if (req->payload_len == 0) {
713 length = strlen(req->payload);
714 } else {
715 length = req->payload_len;
716 }
717
718 ret = sendall(sock, req->payload, length, req_end_timepoint);
719 if (ret < 0) {
720 goto out;
721 }
722
723 total_sent += length;
724 }
725 } else {
726 ret = http_send_data(sock, send_buf, send_buf_max_len,
727 &send_buf_pos, req_end_timepoint, HTTP_CRLF, NULL);
728 if (ret < 0) {
729 goto out;
730 }
731
732 total_sent += ret;
733 }
734
735 if (send_buf_pos > 0) {
736 ret = http_flush_data(sock, send_buf, send_buf_pos, req_end_timepoint);
737 if (ret < 0) {
738 goto out;
739 }
740
741 total_sent += ret;
742 }
743
744 NET_DBG("Sent %d bytes", total_sent);
745
746 http_client_init_parser(&req->internal.parser,
747 &req->internal.parser_settings);
748
749 /* Request is sent, now wait data to be received */
750 total_recv = http_wait_data(sock, req, req_end_timepoint);
751 if (total_recv < 0) {
752 NET_DBG("Wait data failure (%d)", total_recv);
753 ret = total_recv;
754 goto out;
755 }
756
757 NET_DBG("Received %d bytes", total_recv);
758
759 return total_sent;
760
761 out:
762 return ret;
763 }
764