1 /*
2 * Copyright (C) 2015-2018 Alibaba Group Holding Limited
3 */
4 #include "linkkit/infra/infra_config.h"
5
6 #ifdef INFRA_HTTPC
7
8 #include <string.h>
9 #include <stddef.h>
10 #include <stdlib.h>
11
12 #include "linkkit/infra/infra_types.h"
13 #include "linkkit/infra/infra_defs.h"
14 #include "linkkit/infra/infra_httpc.h"
15 #include "linkkit/infra/infra_net.h"
16 #include "linkkit/infra/infra_timer.h"
17 #include "linkkit/wrappers/wrappers.h"
18
19 #ifdef INFRA_LOG
20 #include "linkkit/infra/infra_log.h"
21 #define httpc_err(...) log_err("httpc", __VA_ARGS__)
22 #define httpc_info(...) log_info("httpc", __VA_ARGS__)
23 #define httpc_debug(...) log_debug("httpc", __VA_ARGS__)
24 #else
25 #define httpc_err(...)
26 #define httpc_info(...)
27 #define httpc_debug(...)
28 #endif
29
30 #define HTTPCLIENT_MIN(x, y) (((x) < (y)) ? (x) : (y))
31 #define HTTPCLIENT_MAX(x, y) (((x) > (y)) ? (x) : (y))
32
33 #define HTTPCLIENT_READ_BUF_SIZE (1024) /* read payload */
34 #define HTTPCLIENT_RAED_HEAD_SIZE (32) /* read header */
35 #define HTTPCLIENT_SEND_BUF_SIZE (1024) /* send */
36
37 #define HTTPCLIENT_MAX_URL_LEN (256)
38
39 #define HTTP_RETRIEVE_MORE_DATA (1) /**< More data needs to be retrieved. */
40
41 #if defined(MBEDTLS_DEBUG_C)
42 #define DEBUG_LEVEL 2
43 #endif
44 #define HTTPCLIENT_CHUNK_SIZE (1024)
45
46 static int _utils_parse_url(const char *url, char *host, char *path);
47 static int _http_recv(httpclient_t *client, char *buf, int max_len,
48 int *p_read_len, uint32_t timeout);
49 static int _http_get_response_body(httpclient_t *client, char *data, int len,
50 uint32_t timeout,
51 httpclient_data_t *client_data);
52 static int _http_parse_response_header(httpclient_t *client, char *data,
53 int len, uint32_t timeout,
54 httpclient_data_t *client_data);
55
_utils_parse_url(const char * url,char * host,char * path)56 static int _utils_parse_url(const char *url, char *host, char *path)
57 {
58 char *host_ptr = (char *)strstr(url, "://");
59 uint32_t host_len = 0;
60 uint32_t path_len;
61 /* char *port_ptr; */
62 char *path_ptr;
63 char *fragment_ptr;
64
65 if (host_ptr == NULL) {
66 return -1; /* URL is invalid */
67 }
68 host_ptr += 3;
69
70 path_ptr = strchr(host_ptr, '/');
71 if (NULL == path_ptr) {
72 return -2;
73 }
74
75 if (host_len == 0) {
76 host_len = path_ptr - host_ptr;
77 }
78
79 memcpy(host, host_ptr, host_len);
80 host[host_len] = '\0';
81 fragment_ptr = strchr(host_ptr, '#');
82 if (fragment_ptr != NULL) {
83 path_len = fragment_ptr - path_ptr;
84 } else {
85 path_len = strlen(path_ptr);
86 }
87
88 memcpy(path, path_ptr, path_len);
89 path[path_len] = '\0';
90
91 return SUCCESS_RETURN;
92 }
93
_utils_fill_tx_buffer(httpclient_t * client,char * send_buf,int * send_idx,char * buf,uint32_t len)94 static int _utils_fill_tx_buffer(
95 httpclient_t *client, char *send_buf, int *send_idx, char *buf,
96 uint32_t len) /* 0 on success, err code on failure */
97 {
98 int ret;
99 int cp_len;
100 int idx = *send_idx;
101
102 if (len == 0) {
103 len = strlen(buf);
104 }
105 do {
106 if ((HTTPCLIENT_SEND_BUF_SIZE - idx) >= len) {
107 cp_len = len;
108 } else {
109 cp_len = HTTPCLIENT_SEND_BUF_SIZE - idx;
110 }
111
112 memcpy(send_buf + idx, buf, cp_len);
113 idx += cp_len;
114 len -= cp_len;
115
116 if (idx == HTTPCLIENT_SEND_BUF_SIZE) {
117 ret = client->net.write(&client->net, send_buf,
118 HTTPCLIENT_SEND_BUF_SIZE, 5000);
119 if (ret) {
120 return ret;
121 }
122 }
123 } while (len);
124
125 *send_idx = idx;
126 return SUCCESS_RETURN;
127 }
128
_http_send_header(httpclient_t * client,const char * host,const char * path,int method,httpclient_data_t * client_data)129 static int _http_send_header(httpclient_t *client, const char *host,
130 const char *path, int method,
131 httpclient_data_t *client_data)
132 {
133 int len;
134 char send_buf[HTTPCLIENT_SEND_BUF_SIZE] = { 0 };
135 char buf[HTTPCLIENT_SEND_BUF_SIZE] = { 0 };
136 char *meth = (method == HTTPCLIENT_GET) ? "GET"
137 : (method == HTTPCLIENT_POST) ? "POST"
138 : (method == HTTPCLIENT_PUT) ? "PUT"
139 : (method == HTTPCLIENT_DELETE) ? "DELETE"
140 : (method == HTTPCLIENT_HEAD) ? "HEAD"
141 : "";
142 int ret;
143
144 /* Send request */
145 memset(send_buf, 0, HTTPCLIENT_SEND_BUF_SIZE);
146 len = 0; /* Reset send buffer */
147
148 HAL_Snprintf(buf, sizeof(buf), "%s %s HTTP/1.1\r\nHost: %s\r\n", meth, path,
149 host); /* Write request */
150
151 ret = _utils_fill_tx_buffer(client, send_buf, &len, buf, strlen(buf));
152 if (ret) {
153 /* httpc_err("Could not write request"); */
154 return ERROR_HTTP_CONN;
155 }
156
157 /* Add user header information */
158 if (client->header) {
159 _utils_fill_tx_buffer(client, send_buf, &len, (char *)client->header,
160 strlen(client->header));
161 }
162
163 if (client_data->post_buf != NULL) {
164 HAL_Snprintf(buf, sizeof(buf), "Content-Length: %d\r\n",
165 client_data->post_buf_len);
166 _utils_fill_tx_buffer(client, send_buf, &len, buf, strlen(buf));
167
168 if (client_data->post_content_type != NULL) {
169 HAL_Snprintf(buf, sizeof(buf), "Content-Type: %s\r\n",
170 client_data->post_content_type);
171 _utils_fill_tx_buffer(client, send_buf, &len, buf, strlen(buf));
172 }
173 }
174
175 /* Close headers */
176 _utils_fill_tx_buffer(client, send_buf, &len, "\r\n", 0);
177
178 #ifdef INFRA_LOG
179 log_multi_line(LOG_DEBUG_LEVEL, "REQUEST", "%s", send_buf, ">");
180 #endif
181
182 /* ret = httpclient_tcp_send_all(client->net.handle, send_buf, len); */
183 ret = client->net.write(&client->net, send_buf, len, 5000);
184 if (ret <= 0) {
185 httpc_err("ret = client->net.write() = %d", ret);
186 return (ret == 0) ? ERROR_HTTP_CLOSED : ERROR_HTTP_CONN;
187 }
188
189 return SUCCESS_RETURN;
190 }
191
_http_send_userdata(httpclient_t * client,httpclient_data_t * client_data)192 int _http_send_userdata(httpclient_t *client, httpclient_data_t *client_data)
193 {
194 int ret = 0;
195
196 if (client_data->post_buf && client_data->post_buf_len) {
197 /* ret = httpclient_tcp_send_all(client->handle, (char
198 * *)client_data->post_buf, client_data->post_buf_len); */
199 ret = client->net.write(&client->net, (char *)client_data->post_buf,
200 client_data->post_buf_len, 5000);
201 httpc_debug("client_data->post_buf: %s, ret is %d",
202 client_data->post_buf, ret);
203 if (ret <= 0) {
204 return (ret == 0)
205 ? ERROR_HTTP_CLOSED
206 : ERROR_HTTP_CONN; /* Connection was closed by server */
207 }
208 }
209
210 return SUCCESS_RETURN;
211 }
212
213 /* 0 on success, err code on failure */
_http_recv(httpclient_t * client,char * buf,int max_len,int * p_read_len,uint32_t timeout_ms)214 static int _http_recv(httpclient_t *client, char *buf, int max_len,
215 int *p_read_len, uint32_t timeout_ms)
216 {
217 int ret = 0;
218 iotx_time_t timer;
219
220 iotx_time_init(&timer);
221 utils_time_countdown_ms(&timer, timeout_ms);
222
223 *p_read_len = 0;
224
225 ret = client->net.read(&client->net, buf, max_len, iotx_time_left(&timer));
226 /* httpc_debug("Recv: | %s", buf); */
227 httpc_info("ret of _http_recv is %d", ret);
228
229 if (ret > 0) {
230 *p_read_len = ret;
231 return 0;
232 } else if (ret == 0) {
233 /* timeout */
234 return FAIL_RETURN;
235 } else {
236 return ERROR_HTTP_CONN;
237 }
238 }
239
240 #define MIN_TIMEOUT (100)
241 #define MAX_RETRY_COUNT (600)
242
_utils_check_deadloop(int len,iotx_time_t * timer,int ret,unsigned int * dead_loop_count,unsigned int * extend_count)243 static int _utils_check_deadloop(int len, iotx_time_t *timer, int ret,
244 unsigned int *dead_loop_count,
245 unsigned int *extend_count)
246 {
247 /* if timeout reduce to zero, it will be translated into NULL for select
248 * function in TLS lib */
249 /* it would lead to indenfinite behavior, so we avoid it */
250 if (iotx_time_left(timer) < MIN_TIMEOUT) {
251 (*extend_count)++;
252 utils_time_countdown_ms(timer, MIN_TIMEOUT);
253 }
254
255 /* if it falls into deadloop before reconnected to internet, we just quit*/
256 if ((0 == len) && (0 == iotx_time_left(timer)) && (FAIL_RETURN == ret)) {
257 (*dead_loop_count)++;
258 if (*dead_loop_count > MAX_RETRY_COUNT) {
259 httpc_err("deadloop detected, exit");
260 return ERROR_HTTP_CONN;
261 }
262 } else {
263 *dead_loop_count = 0;
264 }
265
266 /*if the internet connection is fixed during the loop, the download stream
267 * might be disconnected. we have to quit */
268 if ((0 == len) && (*extend_count > 2 * MAX_RETRY_COUNT) &&
269 (FAIL_RETURN == ret)) {
270 httpc_err("extend timer for too many times, exit");
271 return ERROR_HTTP_CONN;
272 }
273 return SUCCESS_RETURN;
274 }
275
_utils_fill_rx_buf(int * recv_count,int len_to_write_to_respons_buf,httpclient_data_t * client_data,char * data)276 static int _utils_fill_rx_buf(int *recv_count, int len_to_write_to_respons_buf,
277 httpclient_data_t *client_data, char *data)
278 {
279 int count = *recv_count;
280 if (count + len_to_write_to_respons_buf <
281 client_data->response_buf_len - 1) {
282 memcpy(client_data->response_buf + count, data,
283 len_to_write_to_respons_buf);
284 count += len_to_write_to_respons_buf;
285 client_data->response_buf[count] = '\0';
286 client_data->retrieve_len -= len_to_write_to_respons_buf;
287 *recv_count = count;
288 return SUCCESS_RETURN;
289 } else {
290 memcpy(client_data->response_buf + count, data,
291 client_data->response_buf_len - 1 - count);
292 client_data->response_buf[client_data->response_buf_len - 1] = '\0';
293 client_data->retrieve_len -=
294 (client_data->response_buf_len - 1 - count);
295 return HTTP_RETRIEVE_MORE_DATA;
296 }
297 }
298
_http_get_response_body(httpclient_t * client,char * data,int data_len_actually_received,uint32_t timeout_ms,httpclient_data_t * client_data)299 static int _http_get_response_body(httpclient_t *client, char *data,
300 int data_len_actually_received,
301 uint32_t timeout_ms,
302 httpclient_data_t *client_data)
303 {
304 int written_response_buf_len = 0;
305 int len_to_write_to_respons_buf = 0;
306 iotx_time_t timer;
307
308 iotx_time_init(&timer);
309 utils_time_countdown_ms(&timer, timeout_ms);
310
311 /* Receive data */
312 /* httpc_debug("Current data: %s", data); */
313
314 client_data->is_more = IOT_TRUE;
315
316 /* the header is not received finished */
317 if (client_data->response_content_len == -1 &&
318 client_data->is_chunked == IOT_FALSE) {
319 /* can not enter this if */
320 /* TODO check the way to go into this branch */
321 httpc_err("header is not received yet");
322 return ERROR_HTTP_CONN;
323 }
324
325 while (1) {
326 unsigned int dead_loop_count = 0;
327 unsigned int extend_count = 0;
328 do {
329 int res;
330 /* move previous fetched data into response_buf */
331 len_to_write_to_respons_buf = HTTPCLIENT_MIN(
332 data_len_actually_received, client_data->retrieve_len);
333 res = _utils_fill_rx_buf(&written_response_buf_len,
334 len_to_write_to_respons_buf, client_data,
335 data);
336 if (HTTP_RETRIEVE_MORE_DATA == res) {
337 return HTTP_RETRIEVE_MORE_DATA;
338 }
339
340 /* get data from internet and put into "data" buf temporary */
341 if (client_data->retrieve_len) {
342 int ret;
343 int max_len_to_receive =
344 HTTPCLIENT_MIN(HTTPCLIENT_CHUNK_SIZE - 1,
345 client_data->response_buf_len - 1 -
346 written_response_buf_len);
347 max_len_to_receive = HTTPCLIENT_MIN(max_len_to_receive,
348 client_data->retrieve_len);
349
350 ret = _http_recv(client, data, max_len_to_receive,
351 &data_len_actually_received,
352 iotx_time_left(&timer));
353 if (ret == ERROR_HTTP_CONN) {
354 return ret;
355 }
356 httpc_debug(
357 "Total- remaind Payload: %d Bytes; currently Read: %d "
358 "Bytes",
359 client_data->retrieve_len, data_len_actually_received);
360
361 /* TODO add deadloop processing*/
362 ret =
363 _utils_check_deadloop(data_len_actually_received, &timer,
364 ret, &dead_loop_count, &extend_count);
365 if (ERROR_HTTP_CONN == ret) {
366 return ret;
367 }
368 }
369 } while (client_data->retrieve_len);
370 client_data->is_more = IOT_FALSE;
371 break;
372 }
373
374 return SUCCESS_RETURN;
375 }
376
_http_parse_response_header(httpclient_t * client,char * data,int len,uint32_t timeout_ms,httpclient_data_t * client_data)377 static int _http_parse_response_header(httpclient_t *client, char *data,
378 int len, uint32_t timeout_ms,
379 httpclient_data_t *client_data)
380 {
381 int crlf_pos;
382 iotx_time_t timer;
383 char *tmp_ptr, *ptr_body_end;
384 int new_trf_len, ret;
385 char *crlf_ptr;
386
387 iotx_time_init(&timer);
388 utils_time_countdown_ms(&timer, timeout_ms);
389
390 client_data->response_content_len = -1;
391
392 /* http client response */
393 /* <status-line> HTTP/1.1 200 OK(CRLF)
394
395 <headers> ...(CRLF)
396
397 <blank line> (CRLF)
398
399 [<response-body>] */
400 crlf_ptr = strstr(data, "\r\n");
401 if (crlf_ptr == NULL) {
402 httpc_err("\r\n not found");
403 return ERROR_HTTP_UNRESOLVED_DNS;
404 }
405
406 crlf_pos = crlf_ptr - data;
407 data[crlf_pos] = '\0';
408 client->response_code = atoi(data + 9);
409 httpc_debug("Reading headers: %s", data);
410 memmove(data, &data[crlf_pos + 2],
411 len - (crlf_pos + 2) +
412 1); /* Be sure to move NULL-terminating char as well */
413 len -= (crlf_pos + 2); /* remove status_line length */
414 client_data->is_chunked = IOT_FALSE;
415
416 /*If not ending of response body*/
417 /* try to read more header again until find response head ending "\r\n\r\n"
418 */
419 while (NULL == (ptr_body_end = strstr(data, "\r\n\r\n"))) {
420 /* try to read more header */
421 int max_remain_len = HTTPCLIENT_READ_BUF_SIZE - len - 1;
422 if (max_remain_len <= 0) {
423 httpc_debug("buffer exceeded max\n");
424 return ERROR_HTTP_PARSE;
425 }
426 max_remain_len = max_remain_len > HTTPCLIENT_RAED_HEAD_SIZE
427 ? HTTPCLIENT_RAED_HEAD_SIZE
428 : max_remain_len;
429 ret = _http_recv(client, data + len, max_remain_len, &new_trf_len,
430 iotx_time_left(&timer));
431
432 if (ret == ERROR_HTTP_CONN) {
433 return ret;
434 }
435 len += new_trf_len;
436 data[len] = '\0';
437 }
438
439 /* parse response_content_len */
440 tmp_ptr = strstr(data, "Content-Length");
441 if (tmp_ptr != NULL) {
442 client_data->response_content_len =
443 atoi(tmp_ptr + strlen("Content-Length: "));
444 client_data->retrieve_len = client_data->response_content_len;
445 } else {
446 httpc_err("Could not parse header");
447 return ERROR_HTTP;
448 }
449
450 /* remove header length */
451 /* len is Had read body's length */
452 /* if client_data->response_content_len != 0, it is know response length */
453 /* the remain length is client_data->response_content_len - len */
454 len = len - (ptr_body_end + 4 - data);
455 memmove(data, ptr_body_end + 4, len + 1);
456 client_data->response_received_len += len;
457 return _http_get_response_body(client, data, len, iotx_time_left(&timer),
458 client_data);
459 }
460
httpclient_connect(httpclient_t * client)461 int httpclient_connect(httpclient_t *client)
462 {
463 int retry_max = 3;
464 int retry_cnt = 1;
465 int retry_interval = 1000;
466 int rc = -1;
467
468 do {
469 client->net.handle = 0;
470 httpc_debug("calling TCP or TLS connect HAL for [%d/%d] iteration",
471 retry_cnt, retry_max);
472
473 rc = client->net.connect(&client->net);
474 if (0 != rc) {
475 client->net.disconnect(&client->net);
476 httpc_err("TCP or TLS connect failed, rc = %d", rc);
477 HAL_SleepMs(retry_interval);
478 continue;
479 } else {
480 httpc_debug(
481 "rc = client->net.connect() = %d, success @ [%d/%d] iteration",
482 rc, retry_cnt, retry_max);
483 break;
484 }
485 } while (++retry_cnt <= retry_max);
486
487 return SUCCESS_RETURN;
488 }
489
_http_send_request(httpclient_t * client,const char * host,const char * path,HTTPCLIENT_REQUEST_TYPE method,httpclient_data_t * client_data)490 int _http_send_request(httpclient_t *client, const char *host, const char *path,
491 HTTPCLIENT_REQUEST_TYPE method,
492 httpclient_data_t *client_data)
493 {
494 int ret = ERROR_HTTP_CONN;
495
496 if (0 == client->net.handle) {
497 return -1;
498 }
499
500 ret = _http_send_header(client, host, path, method, client_data);
501 if (ret != 0) {
502 return ret;
503 }
504
505 if (method == HTTPCLIENT_POST || method == HTTPCLIENT_PUT) {
506 ret = _http_send_userdata(client, client_data);
507 if (ret < 0) {
508 ret = ret;
509 }
510 }
511
512 return ret;
513 }
514
httpclient_recv_response(httpclient_t * client,uint32_t timeout_ms,httpclient_data_t * client_data)515 int httpclient_recv_response(httpclient_t *client, uint32_t timeout_ms,
516 httpclient_data_t *client_data)
517 {
518 int reclen = 0, ret = ERROR_HTTP_CONN;
519 char buf[HTTPCLIENT_READ_BUF_SIZE] = { 0 };
520 iotx_time_t timer;
521
522 iotx_time_init(&timer);
523 utils_time_countdown_ms(&timer, timeout_ms);
524
525 if (0 == client->net.handle) {
526 httpc_err("not connection have been established");
527 return ret;
528 }
529
530 if (client_data->is_more) {
531 client_data->response_buf[0] = '\0';
532 ret = _http_get_response_body(client, buf, reclen,
533 iotx_time_left(&timer), client_data);
534 } else {
535 client_data->is_more = 1;
536 /* try to read header */
537 ret = _http_recv(client, buf, HTTPCLIENT_RAED_HEAD_SIZE, &reclen,
538 iotx_time_left(&timer));
539 if (ret != 0) {
540 return ret;
541 }
542
543 buf[reclen] = '\0';
544
545 if (reclen) {
546 #ifdef INFRA_LOG
547 log_multi_line(LOG_DEBUG_LEVEL, "RESPONSE", "%s", buf, "<");
548 #endif
549 ret = _http_parse_response_header(
550 client, buf, reclen, iotx_time_left(&timer), client_data);
551 }
552 }
553
554 return ret;
555 }
556
httpclient_close(httpclient_t * client)557 void httpclient_close(httpclient_t *client)
558 {
559 if (client->net.handle > 0) {
560 client->net.disconnect(&client->net);
561 }
562 client->net.handle = 0;
563 httpc_info("client disconnected");
564 }
565
_http_send(httpclient_t * client,const char * url,int port,const char * ca_crt,HTTPCLIENT_REQUEST_TYPE method,httpclient_data_t * client_data)566 static int _http_send(httpclient_t *client, const char *url, int port,
567 const char *ca_crt, HTTPCLIENT_REQUEST_TYPE method,
568 httpclient_data_t *client_data)
569 {
570 int ret;
571 char host[HTTPCLIENT_MAX_URL_LEN] = { 0 };
572 char path[HTTPCLIENT_MAX_URL_LEN] = { 0 };
573
574 /* First we need to parse the url (http[s]://host[:port][/[path]]) */
575 ret = _utils_parse_url(url, host, path);
576 if (ret != SUCCESS_RETURN) {
577 httpc_err("_utils_parse_url fail returned %d", ret);
578 return ret;
579 }
580
581 if (0 == client->net.handle) {
582 /* Establish connection if no. */
583 ret = iotx_net_init(&client->net, host, port, ca_crt);
584 if (0 != ret) {
585 return ret;
586 }
587
588 ret = httpclient_connect(client);
589 if (0 != ret) {
590 httpclient_close(client);
591 return ret;
592 }
593
594 ret = _http_send_request(client, host, path, method, client_data);
595 if (0 != ret) {
596 httpc_err("_http_send_request is error, ret = %d", ret);
597 return ret;
598 }
599 }
600 return SUCCESS_RETURN;
601 }
602
httpclient_common(httpclient_t * client,const char * url,int port,const char * ca_crt,HTTPCLIENT_REQUEST_TYPE method,uint32_t timeout_ms,httpclient_data_t * client_data)603 int httpclient_common(httpclient_t *client, const char *url, int port,
604 const char *ca_crt, HTTPCLIENT_REQUEST_TYPE method,
605 uint32_t timeout_ms, httpclient_data_t *client_data)
606 {
607 iotx_time_t timer;
608 int ret = _http_send(client, url, port, ca_crt, method, client_data);
609 if (SUCCESS_RETURN != ret) {
610 httpclient_close(client);
611 return ret;
612 }
613
614 iotx_time_init(&timer);
615 utils_time_countdown_ms(&timer, timeout_ms);
616
617 if ((NULL != client_data->response_buf) &&
618 (0 != client_data->response_buf_len)) {
619 ret = httpclient_recv_response(client, iotx_time_left(&timer),
620 client_data);
621 if (ret < 0) {
622 httpc_err("httpclient_recv_response is error,ret = %d", ret);
623 httpclient_close(client);
624 return ret;
625 }
626 }
627
628 if (!client_data->is_more) {
629 /* Close the HTTP if no more data. */
630 httpc_info("close http channel");
631 httpclient_close(client);
632 }
633
634 ret = 0;
635 return ret;
636 }
637
iotx_post(httpclient_t * client,const char * url,int port,const char * ca_crt,httpclient_data_t * client_data)638 int iotx_post(httpclient_t *client, const char *url, int port,
639 const char *ca_crt, httpclient_data_t *client_data)
640 {
641 return _http_send(client, url, port, ca_crt, HTTPCLIENT_POST, client_data);
642 }
643
644 /**********************************************************************************/
645
646 typedef struct {
647 httpclient_t client;
648 httpclient_data_t http_client_data;
649 int receive_maxlen;
650 int already_received;
651 char *url;
652 int port;
653 iotx_http_method_t method;
654 char *header;
655 char *cert;
656 int timeout;
657 recvcallback recv_cb;
658 void *recv_ctx;
659 } wrapper_http_handle_t;
660
_replase_str(char ** ptr,void * data)661 static int _replase_str(char **ptr, void *data)
662 {
663 if (*ptr != NULL) {
664 HAL_Free(*ptr);
665 }
666 *ptr = HAL_Malloc(strlen(data) + 1);
667 if (*ptr == NULL) {
668 return FAIL_RETURN;
669 }
670 memset(*ptr, 0, strlen(data) + 1);
671 memcpy(*ptr, data, strlen(data));
672
673 return SUCCESS_RETURN;
674 }
675
wrapper_http_init(void)676 void *wrapper_http_init(void)
677 {
678 wrapper_http_handle_t *handle = HAL_Malloc(sizeof(wrapper_http_handle_t));
679 if (handle == NULL) {
680 return NULL;
681 }
682 memset(handle, 0, sizeof(wrapper_http_handle_t));
683
684 return handle;
685 }
686
wrapper_http_setopt(void * handle,iotx_http_option_t option,void * data)687 int wrapper_http_setopt(void *handle, iotx_http_option_t option, void *data)
688 {
689 wrapper_http_handle_t *http_handle = (wrapper_http_handle_t *)handle;
690
691 if (handle == NULL || data == NULL) {
692 return FAIL_RETURN;
693 }
694
695 switch (option) {
696 case IOTX_HTTPOPT_URL:
697 {
698 _replase_str(&http_handle->url, data);
699 }
700 break;
701 case IOTX_HTTPOPT_PORT:
702 {
703 if (*(int *)(data) < 0) {
704 return FAIL_RETURN;
705 }
706 http_handle->port = *(int *)(data);
707 }
708 break;
709 case IOTX_HTTPOPT_METHOD:
710 {
711 http_handle->method = *(iotx_http_method_t *)data;
712 }
713 break;
714 case IOTX_HTTPOPT_HEADER:
715 {
716 _replase_str(&http_handle->header, data);
717 }
718 break;
719 case IOTX_HTTPOPT_CERT:
720 {
721 http_handle->cert = data;
722 }
723 break;
724 case IOTX_HTTPOPT_TIMEOUT:
725 {
726 if (*(int *)(data) < 0) {
727 return FAIL_RETURN;
728 }
729 http_handle->timeout = *(int *)(data);
730 }
731 break;
732 case IOTX_HTTPOPT_RECVCALLBACK:
733 {
734 http_handle->recv_cb = data;
735 }
736 break;
737 case IOTX_HTTPOPT_RECVMAXLEN:
738 {
739 http_handle->receive_maxlen = *(int *)(data);
740 }
741 break;
742 case IOTX_HTTPOPT_RECVCONTEXT:
743 {
744 http_handle->recv_ctx = (recvcallback)data;
745 }
746 break;
747 default:
748 {
749 httpc_err("Unknown Option");
750 return FAIL_RETURN;
751 }
752 }
753
754 return SUCCESS_RETURN;
755 }
756
wrapper_http_perform(void * handle,void * data,int length)757 int wrapper_http_perform(void *handle, void *data, int length)
758 {
759 int res = 0, received_this_time = 0;
760 iotx_time_t timer;
761 wrapper_http_handle_t *http_handle = (wrapper_http_handle_t *)handle;
762 char *response_payload = NULL;
763
764 if (handle == NULL) {
765 return FAIL_RETURN;
766 }
767
768 if ((http_handle->method == IOTX_HTTP_POST) &&
769 (data == NULL || length <= 0)) {
770 return FAIL_RETURN;
771 }
772
773 if (http_handle->receive_maxlen <= 0) {
774 return FAIL_RETURN;
775 }
776
777 response_payload = HAL_Malloc(http_handle->receive_maxlen);
778 if (response_payload == NULL) {
779 return FAIL_RETURN;
780 }
781 memset(response_payload, 0, http_handle->receive_maxlen);
782
783 http_handle->client.header = http_handle->header;
784 http_handle->http_client_data.post_buf = data;
785 http_handle->http_client_data.post_buf_len = length;
786 http_handle->http_client_data.response_buf = response_payload;
787 http_handle->http_client_data.response_buf_len =
788 http_handle->receive_maxlen;
789
790 res = _http_send(&http_handle->client, http_handle->url, http_handle->port,
791 http_handle->cert,
792 (HTTPCLIENT_REQUEST_TYPE)http_handle->method,
793 &http_handle->http_client_data);
794 if (SUCCESS_RETURN != res) {
795 HAL_Free(response_payload);
796 return res;
797 }
798
799 iotx_time_init(&timer);
800 utils_time_countdown_ms(&timer, http_handle->timeout);
801
802 res = httpclient_recv_response(&http_handle->client, iotx_time_left(&timer),
803 &http_handle->http_client_data);
804 if (res < 0) {
805 httpc_err("httpclient_recv_response is error,res = %d", res);
806 HAL_Free(response_payload);
807 return res;
808 }
809
810 received_this_time = http_handle->http_client_data.response_content_len -
811 http_handle->http_client_data.retrieve_len -
812 http_handle->already_received;
813 http_handle->already_received =
814 http_handle->http_client_data.response_content_len -
815 http_handle->http_client_data.retrieve_len;
816
817 if (res >= SUCCESS_RETURN) {
818 if (http_handle->recv_cb) {
819 http_handle->recv_cb(
820 response_payload, received_this_time,
821 http_handle->http_client_data.response_content_len,
822 http_handle->recv_ctx);
823 }
824 }
825
826 HAL_Free(response_payload);
827
828 return received_this_time;
829 }
830
wrapper_http_deinit(void ** handle)831 void wrapper_http_deinit(void **handle)
832 {
833 wrapper_http_handle_t **http_handle = (wrapper_http_handle_t **)handle;
834
835 if (handle == NULL || *handle == NULL) {
836 return;
837 }
838
839 if ((*http_handle)->url) {
840 HAL_Free((*http_handle)->url);
841 }
842
843 if ((*http_handle)->header) {
844 HAL_Free((*http_handle)->header);
845 }
846
847 httpclient_close(&(*http_handle)->client);
848
849 HAL_Free(*http_handle);
850 *handle = NULL;
851 }
852
853 /**********************************************************************************/
854
855 #endif
856