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