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