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