utils_httpc.c 26 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802
  1. /*
  2. * Tencent is pleased to support the open source community by making IoT Hub
  3. available.
  4. * Copyright (C) 2016 THL A29 Limited, a Tencent company. All rights reserved.
  5. * Licensed under the MIT License (the "License"); you may not use this file
  6. except in
  7. * compliance with the License. You may obtain a copy of the License at
  8. * http://opensource.org/licenses/MIT
  9. * Unless required by applicable law or agreed to in writing, software
  10. distributed under the License is
  11. * distributed on an "AS IS" basis, WITHOUT WARRANTIES OR CONDITIONS OF ANY
  12. KIND,
  13. * either express or implied. See the License for the specific language
  14. governing permissions and
  15. * limitations under the License.
  16. *
  17. */
  18. #ifdef __cplusplus
  19. extern "C" {
  20. #endif
  21. #include "utils_httpc.h"
  22. #include <ctype.h>
  23. #include <string.h>
  24. #include "qcloud_iot_ca.h"
  25. #include "qcloud_iot_common.h"
  26. #include "qcloud_iot_export.h"
  27. #include "qcloud_iot_import.h"
  28. #include "utils_timer.h"
  29. #define HTTP_CLIENT_MIN(x, y) (((x) < (y)) ? (x) : (y))
  30. #define HTTP_CLIENT_MAX(x, y) (((x) > (y)) ? (x) : (y))
  31. #define HTTP_CLIENT_AUTHB_SIZE 128
  32. #define HTTP_CLIENT_CHUNK_SIZE 1025
  33. #define HTTP_CLIENT_SEND_BUF_SIZE 1024
  34. #define HTTP_CLIENT_MAX_HOST_LEN 64
  35. #define HTTP_CLIENT_MAX_URL_LEN 1024
  36. #define HTTP_RETRIEVE_MORE_DATA (1)
  37. #if defined(MBEDTLS_DEBUG_C)
  38. #define DEBUG_LEVEL 2
  39. #endif
  40. static void _http_client_base64enc(char *out, const char *in)
  41. {
  42. const char code[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=";
  43. int i = 0, x = 0, l = 0;
  44. for (; *in; in++) {
  45. x = x << 8 | *in;
  46. for (l += 8; l >= 6; l -= 6) {
  47. out[i++] = code[(x >> (l - 6)) & 0x3f];
  48. }
  49. }
  50. if (l > 0) {
  51. x <<= 6 - l;
  52. out[i++] = code[x & 0x3f];
  53. }
  54. for (; i % 4;) {
  55. out[i++] = '=';
  56. }
  57. out[i] = '\0';
  58. }
  59. static int _http_client_parse_url(const char *url, char *scheme, uint32_t max_scheme_len, char *host,
  60. uint32_t maxhost_len, int *port, char *path, uint32_t max_path_len)
  61. {
  62. char * scheme_ptr = (char *)url;
  63. char * host_ptr = (char *)strstr(url, "://");
  64. uint32_t host_len = 0;
  65. uint32_t path_len;
  66. char *path_ptr;
  67. char *fragment_ptr;
  68. if (host_ptr == NULL) {
  69. Log_e("Could not find host");
  70. return QCLOUD_ERR_HTTP_PARSE;
  71. }
  72. if (max_scheme_len < host_ptr - scheme_ptr + 1) {
  73. Log_e("Scheme str is too small (%u >= %u)", max_scheme_len, (uint32_t)(host_ptr - scheme_ptr + 1));
  74. return QCLOUD_ERR_HTTP_PARSE;
  75. }
  76. memcpy(scheme, scheme_ptr, host_ptr - scheme_ptr);
  77. scheme[host_ptr - scheme_ptr] = '\0';
  78. host_ptr += 3;
  79. *port = 0;
  80. path_ptr = strchr(host_ptr, '/');
  81. if (NULL == path_ptr) {
  82. path_ptr = scheme_ptr + (int)strlen(url);
  83. host_len = path_ptr - host_ptr;
  84. memcpy(host, host_ptr, host_len);
  85. host[host_len] = '\0';
  86. memcpy(path, "/", 1);
  87. path[1] = '\0';
  88. return QCLOUD_RET_SUCCESS;
  89. }
  90. if (host_len == 0) {
  91. host_len = path_ptr - host_ptr;
  92. }
  93. if (maxhost_len < host_len + 1) {
  94. Log_e("Host str is too long (host_len(%d) >= max_len(%d))", host_len + 1, maxhost_len);
  95. return QCLOUD_ERR_HTTP_PARSE;
  96. }
  97. memcpy(host, host_ptr, host_len);
  98. host[host_len] = '\0';
  99. fragment_ptr = strchr(host_ptr, '#');
  100. if (fragment_ptr != NULL) {
  101. path_len = fragment_ptr - path_ptr;
  102. } else {
  103. path_len = strlen(path_ptr);
  104. }
  105. if (max_path_len < path_len + 1) {
  106. Log_e("Path str is too small (%d >= %d)", max_path_len, path_len + 1);
  107. return QCLOUD_ERR_HTTP_PARSE;
  108. }
  109. memcpy(path, path_ptr, path_len);
  110. path[path_len] = '\0';
  111. return QCLOUD_RET_SUCCESS;
  112. }
  113. static int _http_client_parse_host(const char *url, char *host, uint32_t host_max_len)
  114. {
  115. const char *host_ptr = (const char *)strstr(url, "://");
  116. uint32_t host_len = 0;
  117. char * path_ptr;
  118. if (host_ptr == NULL) {
  119. Log_e("Could not find host");
  120. return QCLOUD_ERR_HTTP_PARSE;
  121. }
  122. host_ptr += 3;
  123. uint32_t pro_len = 0;
  124. pro_len = host_ptr - url;
  125. path_ptr = strchr(host_ptr, '/');
  126. if (path_ptr != NULL)
  127. host_len = path_ptr - host_ptr;
  128. else
  129. host_len = strlen(url) - pro_len;
  130. if (host_max_len < host_len + 1) {
  131. Log_e("Host str is too small (%d >= %d)", host_max_len, host_len + 1);
  132. return QCLOUD_ERR_HTTP_PARSE;
  133. }
  134. memcpy(host, host_ptr, host_len);
  135. host[host_len] = '\0';
  136. return QCLOUD_RET_SUCCESS;
  137. }
  138. static int _http_client_get_info(HTTPClient *client, unsigned char *send_buf, int *send_idx, char *buf, uint32_t len)
  139. {
  140. int rc = QCLOUD_RET_SUCCESS;
  141. int cp_len;
  142. int idx = *send_idx;
  143. if (len == 0) {
  144. len = strlen(buf);
  145. }
  146. do {
  147. if ((HTTP_CLIENT_SEND_BUF_SIZE - idx) >= len) {
  148. cp_len = len;
  149. } else {
  150. cp_len = HTTP_CLIENT_SEND_BUF_SIZE - idx;
  151. }
  152. memcpy(send_buf + idx, buf, cp_len);
  153. idx += cp_len;
  154. len -= cp_len;
  155. if (idx == HTTP_CLIENT_SEND_BUF_SIZE) {
  156. size_t byte_written_len = 0;
  157. rc = client->network_stack.write(&(client->network_stack), send_buf, HTTP_CLIENT_SEND_BUF_SIZE, 5000,
  158. &byte_written_len);
  159. if (byte_written_len) {
  160. return (byte_written_len);
  161. }
  162. }
  163. } while (len);
  164. *send_idx = idx;
  165. return rc;
  166. }
  167. static int _http_client_send_auth(HTTPClient *client, unsigned char *send_buf, int *send_idx)
  168. {
  169. char b_auth[(int)((HTTP_CLIENT_AUTHB_SIZE + 3) * 4 / 3 + 1)];
  170. char base64buff[HTTP_CLIENT_AUTHB_SIZE + 3];
  171. _http_client_get_info(client, send_buf, send_idx, "Authorization: Basic ", 0);
  172. HAL_Snprintf(base64buff, sizeof(base64buff), "%s:%s", client->auth_user, client->auth_password);
  173. _http_client_base64enc(b_auth, base64buff);
  174. b_auth[strlen(b_auth) + 1] = '\0';
  175. b_auth[strlen(b_auth)] = '\n';
  176. _http_client_get_info(client, send_buf, send_idx, b_auth, 0);
  177. return QCLOUD_RET_SUCCESS;
  178. }
  179. static int _http_client_send_header(HTTPClient *client, const char *url, HttpMethod method, HTTPClientData *client_data)
  180. {
  181. char scheme[8] = {0};
  182. char host[HTTP_CLIENT_MAX_HOST_LEN] = {0};
  183. char path[HTTP_CLIENT_MAX_URL_LEN] = {0};
  184. int len;
  185. unsigned char send_buf[HTTP_CLIENT_SEND_BUF_SIZE] = {0};
  186. char buf[HTTP_CLIENT_SEND_BUF_SIZE] = {0};
  187. char * meth = (method == HTTP_GET)
  188. ? "GET"
  189. : (method == HTTP_POST)
  190. ? "POST"
  191. : (method == HTTP_PUT)
  192. ? "PUT"
  193. : (method == HTTP_DELETE) ? "DELETE" : (method == HTTP_HEAD) ? "HEAD" : "";
  194. int rc;
  195. int port;
  196. int res = _http_client_parse_url(url, scheme, sizeof(scheme), host, sizeof(host), &port, path, sizeof(path));
  197. if (res != QCLOUD_RET_SUCCESS) {
  198. Log_e("httpclient_parse_url returned %d", res);
  199. return res;
  200. }
  201. if (strcmp(scheme, "http") == 0) {
  202. } else if (strcmp(scheme, "https") == 0) {
  203. }
  204. memset(send_buf, 0, HTTP_CLIENT_SEND_BUF_SIZE);
  205. len = 0;
  206. HAL_Snprintf(buf, sizeof(buf), "%s %s HTTP/1.1\r\nHost: %s\r\n", meth, path, host);
  207. rc = _http_client_get_info(client, send_buf, &len, buf, strlen(buf));
  208. if (rc) {
  209. Log_e("Could not write request");
  210. return QCLOUD_ERR_HTTP_CONN;
  211. }
  212. if (client->auth_user) {
  213. _http_client_send_auth(client, send_buf, &len);
  214. }
  215. if (client->header) {
  216. _http_client_get_info(client, send_buf, &len, (char *)client->header, strlen(client->header));
  217. }
  218. if (client_data->post_buf != NULL) {
  219. HAL_Snprintf(buf, sizeof(buf), "Content-Length: %d\r\n", client_data->post_buf_len);
  220. _http_client_get_info(client, send_buf, &len, buf, strlen(buf));
  221. if (client_data->post_content_type != NULL) {
  222. HAL_Snprintf(buf, sizeof(buf), "Content-Type: %s\r\n", client_data->post_content_type);
  223. _http_client_get_info(client, send_buf, &len, buf, strlen(buf));
  224. }
  225. }
  226. _http_client_get_info(client, send_buf, &len, "\r\n", 0);
  227. // Log_d("REQUEST:\n%s", send_buf);
  228. size_t written_len = 0;
  229. rc = client->network_stack.write(&client->network_stack, send_buf, len, 5000, &written_len);
  230. if (written_len > 0) {
  231. // Log_d("Written %lu bytes", written_len);
  232. } else if (written_len == 0) {
  233. Log_e("written_len == 0,Connection was closed by server");
  234. return QCLOUD_ERR_HTTP_CLOSED; /* Connection was closed by server */
  235. } else {
  236. Log_e("Connection error (send returned %d)", rc);
  237. return QCLOUD_ERR_HTTP_CONN;
  238. }
  239. return QCLOUD_RET_SUCCESS;
  240. }
  241. static int _http_client_send_userdata(HTTPClient *client, HTTPClientData *client_data)
  242. {
  243. if (client_data->post_buf && client_data->post_buf_len) {
  244. // Log_d("client_data->post_buf: %s", client_data->post_buf);
  245. {
  246. size_t written_len = 0;
  247. int rc = client->network_stack.write(&client->network_stack, (unsigned char *)client_data->post_buf,
  248. client_data->post_buf_len, 5000, &written_len);
  249. if (written_len > 0) {
  250. // Log_d("Written %d bytes", written_len);
  251. } else if (written_len == 0) {
  252. Log_e("written_len == 0,Connection was closed by server");
  253. return QCLOUD_ERR_HTTP_CLOSED;
  254. } else {
  255. Log_e("Connection error (send returned %d)", rc);
  256. return QCLOUD_ERR_HTTP_CONN;
  257. }
  258. }
  259. }
  260. return QCLOUD_RET_SUCCESS;
  261. }
  262. static int _http_client_recv(HTTPClient *client, char *buf, int min_len, int max_len, int *p_read_len,
  263. uint32_t timeout_ms, HTTPClientData *client_data)
  264. {
  265. IOT_FUNC_ENTRY;
  266. int rc = 0;
  267. Timer timer;
  268. size_t recv_size = 0;
  269. InitTimer(&timer);
  270. countdown_ms(&timer, (unsigned int)timeout_ms);
  271. *p_read_len = 0;
  272. rc = client->network_stack.read(&client->network_stack, (unsigned char *)buf, max_len, (uint32_t)left_ms(&timer),
  273. &recv_size);
  274. *p_read_len = (int)recv_size;
  275. if (rc == QCLOUD_ERR_SSL_NOTHING_TO_READ || rc == QCLOUD_ERR_TCP_NOTHING_TO_READ) {
  276. Log_d("HTTP read nothing and timeout");
  277. rc = QCLOUD_RET_SUCCESS;
  278. } else if (rc == QCLOUD_ERR_SSL_READ_TIMEOUT || rc == QCLOUD_ERR_TCP_READ_TIMEOUT) {
  279. if (*p_read_len == client_data->retrieve_len || client_data->retrieve_len == 0)
  280. rc = QCLOUD_RET_SUCCESS;
  281. else
  282. Log_e("network_stack read timeout");
  283. } else if (rc == QCLOUD_ERR_TCP_PEER_SHUTDOWN && *p_read_len > 0) {
  284. /* HTTP server give response and close this connection */
  285. client->network_stack.disconnect(&client->network_stack);
  286. rc = QCLOUD_RET_SUCCESS;
  287. } else if (rc != QCLOUD_RET_SUCCESS) {
  288. Log_e("Connection error rc = %d (recv returned %d)", rc, *p_read_len);
  289. IOT_FUNC_EXIT_RC(rc);
  290. }
  291. IOT_FUNC_EXIT_RC(rc);
  292. }
  293. static int _http_client_retrieve_content(HTTPClient *client, char *data, int len, uint32_t timeout_ms,
  294. HTTPClientData *client_data)
  295. {
  296. IOT_FUNC_ENTRY;
  297. int count = 0;
  298. int templen = 0;
  299. int crlf_pos;
  300. Timer timer;
  301. InitTimer(&timer);
  302. countdown_ms(&timer, (unsigned int)timeout_ms);
  303. client_data->is_more = IOT_TRUE;
  304. if (client_data->response_content_len == -1 && client_data->is_chunked == IOT_FALSE) {
  305. while (1) {
  306. int rc, max_len;
  307. if (count + len < client_data->response_buf_len - 1) {
  308. memcpy(client_data->response_buf + count, data, len);
  309. count += len;
  310. client_data->response_buf[count] = '\0';
  311. } else {
  312. memcpy(client_data->response_buf + count, data, client_data->response_buf_len - 1 - count);
  313. client_data->response_buf[client_data->response_buf_len - 1] = '\0';
  314. return HTTP_RETRIEVE_MORE_DATA;
  315. }
  316. max_len = HTTP_CLIENT_MIN(HTTP_CLIENT_CHUNK_SIZE - 1, client_data->response_buf_len - 1 - count);
  317. rc = _http_client_recv(client, data, 1, max_len, &len, (uint32_t)left_ms(&timer), client_data);
  318. /* Receive data */
  319. // Log_d("data len: %d %d", len, count);
  320. if (rc != QCLOUD_RET_SUCCESS) {
  321. IOT_FUNC_EXIT_RC(rc);
  322. }
  323. if (0 == left_ms(&timer)) {
  324. Log_e("HTTP read timeout!");
  325. IOT_FUNC_EXIT_RC(QCLOUD_ERR_HTTP_TIMEOUT);
  326. }
  327. if (len == 0) {
  328. /* read no more data */
  329. Log_d("no more data, len == 0");
  330. client_data->is_more = IOT_FALSE;
  331. IOT_FUNC_EXIT_RC(QCLOUD_RET_SUCCESS);
  332. }
  333. }
  334. }
  335. while (1) {
  336. uint32_t readLen = 0;
  337. if (client_data->is_chunked && client_data->retrieve_len <= 0) {
  338. /* Read chunk header */
  339. bool foundCrlf;
  340. int n;
  341. do {
  342. foundCrlf = IOT_FALSE;
  343. crlf_pos = 0;
  344. data[len] = 0;
  345. if (len >= 2) {
  346. for (; crlf_pos < len - 2; crlf_pos++) {
  347. if (data[crlf_pos] == '\r' && data[crlf_pos + 1] == '\n') {
  348. foundCrlf = IOT_TRUE;
  349. break;
  350. }
  351. }
  352. }
  353. if (!foundCrlf) {
  354. /* Try to read more */
  355. if (len < HTTP_CLIENT_CHUNK_SIZE) {
  356. int new_trf_len, rc;
  357. rc = _http_client_recv(client, data + len, 0, HTTP_CLIENT_CHUNK_SIZE - len - 1, &new_trf_len,
  358. left_ms(&timer), client_data);
  359. len += new_trf_len;
  360. if (rc != QCLOUD_RET_SUCCESS) {
  361. IOT_FUNC_EXIT_RC(rc);
  362. } else {
  363. continue;
  364. }
  365. } else {
  366. IOT_FUNC_EXIT_RC(QCLOUD_ERR_HTTP);
  367. }
  368. }
  369. } while (!foundCrlf);
  370. data[crlf_pos] = '\0';
  371. // n = sscanf(data, "%x", &readLen);/* chunk length */
  372. readLen = strtoul(data, NULL, 16);
  373. n = (0 == readLen) ? 0 : 1;
  374. client_data->retrieve_len = readLen;
  375. client_data->response_content_len += client_data->retrieve_len;
  376. if (readLen == 0) {
  377. client_data->is_more = IOT_FALSE;
  378. Log_d("no more (last chunk)");
  379. }
  380. if (n != 1) {
  381. Log_e("Could not read chunk length");
  382. return QCLOUD_ERR_HTTP_UNRESOLVED_DNS;
  383. }
  384. memmove(data, &data[crlf_pos + 2], len - (crlf_pos + 2));
  385. len -= (crlf_pos + 2);
  386. } else {
  387. readLen = client_data->retrieve_len;
  388. }
  389. do {
  390. templen = HTTP_CLIENT_MIN(len, readLen);
  391. if (count + templen < client_data->response_buf_len - 1) {
  392. memcpy(client_data->response_buf + count, data, templen);
  393. count += templen;
  394. client_data->response_buf[count] = '\0';
  395. client_data->retrieve_len -= templen;
  396. } else {
  397. memcpy(client_data->response_buf + count, data, client_data->response_buf_len - 1 - count);
  398. client_data->response_buf[client_data->response_buf_len - 1] = '\0';
  399. client_data->retrieve_len -= (client_data->response_buf_len - 1 - count);
  400. IOT_FUNC_EXIT_RC(HTTP_RETRIEVE_MORE_DATA);
  401. }
  402. if (len > readLen) {
  403. Log_d("memmove %d %d %d\n", readLen, len, client_data->retrieve_len);
  404. memmove(data, &data[readLen], len - readLen); /* chunk case, read between two chunks */
  405. len -= readLen;
  406. readLen = 0;
  407. client_data->retrieve_len = 0;
  408. } else {
  409. readLen -= len;
  410. }
  411. if (readLen) {
  412. int rc;
  413. int max_len = HTTP_CLIENT_MIN(HTTP_CLIENT_CHUNK_SIZE - 1, client_data->response_buf_len - 1 - count);
  414. max_len = HTTP_CLIENT_MIN(max_len, readLen);
  415. rc = _http_client_recv(client, data, 1, max_len, &len, left_ms(&timer), client_data);
  416. if (rc != QCLOUD_RET_SUCCESS) {
  417. IOT_FUNC_EXIT_RC(rc);
  418. }
  419. if (left_ms(&timer) == 0) {
  420. Log_e("HTTP read timeout!");
  421. IOT_FUNC_EXIT_RC(QCLOUD_ERR_HTTP_TIMEOUT);
  422. }
  423. }
  424. } while (readLen);
  425. if (client_data->is_chunked) {
  426. if (len < 2) {
  427. int new_trf_len, rc;
  428. /* Read missing chars to find end of chunk */
  429. rc = _http_client_recv(client, data + len, 2 - len, HTTP_CLIENT_CHUNK_SIZE - len - 1, &new_trf_len,
  430. left_ms(&timer), client_data);
  431. if ((rc != QCLOUD_RET_SUCCESS) || (0 == left_ms(&timer))) {
  432. IOT_FUNC_EXIT_RC(rc);
  433. }
  434. len += new_trf_len;
  435. }
  436. if ((data[0] != '\r') || (data[1] != '\n')) {
  437. Log_e("Format error, %s", data); /* after memmove, the beginning of next chunk */
  438. IOT_FUNC_EXIT_RC(QCLOUD_ERR_HTTP_UNRESOLVED_DNS);
  439. }
  440. memmove(data, &data[2], len - 2); /* remove the \r\n */
  441. len -= 2;
  442. } else {
  443. // Log_d("no more (content-length)");
  444. client_data->is_more = IOT_FALSE;
  445. break;
  446. }
  447. }
  448. IOT_FUNC_EXIT_RC(QCLOUD_RET_SUCCESS);
  449. }
  450. static int _http_client_response_parse(HTTPClient *client, char *data, int len, uint32_t timeout_ms,
  451. HTTPClientData *client_data)
  452. {
  453. IOT_FUNC_ENTRY;
  454. int crlf_pos;
  455. Timer timer;
  456. char *tmp_ptr, *ptr_body_end;
  457. InitTimer(&timer);
  458. countdown_ms(&timer, timeout_ms);
  459. client_data->response_content_len = -1;
  460. char *crlf_ptr = strstr(data, "\r\n");
  461. if (crlf_ptr == NULL) {
  462. Log_e("\\r\\n not found");
  463. IOT_FUNC_EXIT_RC(QCLOUD_ERR_HTTP_UNRESOLVED_DNS);
  464. }
  465. crlf_pos = crlf_ptr - data;
  466. data[crlf_pos] = '\0';
  467. #if 0
  468. if (sscanf(data, "HTTP/%*d.%*d %d %*[^\r\n]", &(client->response_code)) != 1) {
  469. Log_e("Not a correct HTTP answer : %s\n", data);
  470. return QCLOUD_ERR_HTTP_UNRESOLVED_DNS;
  471. }
  472. #endif
  473. client->response_code = atoi(data + 9);
  474. if ((client->response_code < 200) || (client->response_code >= 400)) {
  475. Log_w("Response code %d", client->response_code);
  476. if (client->response_code == 403)
  477. IOT_FUNC_EXIT_RC(QCLOUD_ERR_HTTP_AUTH);
  478. if (client->response_code == 404)
  479. IOT_FUNC_EXIT_RC(QCLOUD_ERR_HTTP_NOT_FOUND);
  480. }
  481. // Log_d("Reading headers : %s", data);
  482. // remove null character
  483. memmove(data, &data[crlf_pos + 2], len - (crlf_pos + 2) + 1);
  484. len -= (crlf_pos + 2);
  485. client_data->is_chunked = IOT_FALSE;
  486. if (NULL == (ptr_body_end = strstr(data, "\r\n\r\n"))) {
  487. int new_trf_len, rc;
  488. rc = _http_client_recv(client, data + len, 1, HTTP_CLIENT_CHUNK_SIZE - len - 1, &new_trf_len, left_ms(&timer),
  489. client_data);
  490. if (rc != QCLOUD_RET_SUCCESS) {
  491. IOT_FUNC_EXIT_RC(rc);
  492. }
  493. len += new_trf_len;
  494. data[len] = '\0';
  495. if (NULL == (ptr_body_end = strstr(data, "\r\n\r\n"))) {
  496. Log_e("parse error: no end of the request body");
  497. IOT_FUNC_EXIT_RC(QCLOUD_ERR_FAILURE);
  498. }
  499. }
  500. if (NULL != (tmp_ptr = strstr(data, "Content-Length"))) {
  501. client_data->response_content_len = atoi(tmp_ptr + strlen("Content-Length: "));
  502. client_data->retrieve_len = client_data->response_content_len;
  503. } else if (NULL != (tmp_ptr = strstr(data, "Transfer-Encoding"))) {
  504. int len_chunk = strlen("Chunked");
  505. char *chunk_value = data + strlen("Transfer-Encoding: ");
  506. if ((!memcmp(chunk_value, "Chunked", len_chunk)) || (!memcmp(chunk_value, "chunked", len_chunk))) {
  507. client_data->is_chunked = IOT_TRUE;
  508. client_data->response_content_len = 0;
  509. client_data->retrieve_len = 0;
  510. }
  511. } else {
  512. Log_e("Could not parse header");
  513. IOT_FUNC_EXIT_RC(QCLOUD_ERR_HTTP);
  514. }
  515. len = len - (ptr_body_end + 4 - data);
  516. memmove(data, ptr_body_end + 4, len + 1);
  517. int rc = _http_client_retrieve_content(client, data, len, left_ms(&timer), client_data);
  518. IOT_FUNC_EXIT_RC(rc);
  519. }
  520. static int _http_client_connect(HTTPClient *client)
  521. {
  522. if (QCLOUD_RET_SUCCESS != client->network_stack.connect(&client->network_stack)) {
  523. return QCLOUD_ERR_HTTP_CONN;
  524. }
  525. return QCLOUD_RET_SUCCESS;
  526. }
  527. static int _http_client_send_request(HTTPClient *client, const char *url, HttpMethod method,
  528. HTTPClientData *client_data)
  529. {
  530. int rc;
  531. rc = _http_client_send_header(client, url, method, client_data);
  532. if (rc != 0) {
  533. Log_e("httpclient_send_header is error, rc = %d", rc);
  534. return rc;
  535. }
  536. if (method == HTTP_POST || method == HTTP_PUT) {
  537. rc = _http_client_send_userdata(client, client_data);
  538. }
  539. return rc;
  540. }
  541. static int _http_client_recv_response(HTTPClient *client, uint32_t timeout_ms, HTTPClientData *client_data)
  542. {
  543. IOT_FUNC_ENTRY;
  544. int reclen = 0, rc = QCLOUD_ERR_HTTP_CONN;
  545. char buf[HTTP_CLIENT_CHUNK_SIZE] = {0};
  546. Timer timer;
  547. InitTimer(&timer);
  548. countdown_ms(&timer, timeout_ms);
  549. if (0 == client->network_stack.handle) {
  550. Log_e("Connection has not been established");
  551. IOT_FUNC_EXIT_RC(rc);
  552. }
  553. if (client_data->is_more) {
  554. client_data->response_buf[0] = '\0';
  555. rc = _http_client_retrieve_content(client, buf, reclen, left_ms(&timer), client_data);
  556. } else {
  557. client_data->is_more = IOT_TRUE;
  558. rc = _http_client_recv(client, buf, 1, HTTP_CLIENT_CHUNK_SIZE - 1, &reclen, left_ms(&timer), client_data);
  559. if (rc != QCLOUD_RET_SUCCESS) {
  560. IOT_FUNC_EXIT_RC(rc);
  561. }
  562. // else if(0 == left_ms(&timer)){
  563. // IOT_FUNC_EXIT_RC(QCLOUD_ERR_HTTP_TIMEOUT);
  564. //}
  565. buf[reclen] = '\0';
  566. if (reclen) {
  567. // HAL_Printf("RESPONSE:\n%s", buf);
  568. rc = _http_client_response_parse(client, buf, reclen, left_ms(&timer), client_data);
  569. }
  570. }
  571. IOT_FUNC_EXIT_RC(rc);
  572. }
  573. static int _http_network_init(unsigned char profile_idx, qcloud_Network *pNetwork, const char *host, int port, const char *ca_crt_dir)
  574. {
  575. int rc = QCLOUD_RET_SUCCESS;
  576. if (pNetwork == NULL) {
  577. return QCLOUD_ERR_INVAL;
  578. }
  579. pNetwork->type = NETWORK_TCP;
  580. #ifndef AUTH_WITH_NOTLS
  581. if (ca_crt_dir != NULL) {
  582. pNetwork->ssl_connect_params.ca_crt = ca_crt_dir;
  583. pNetwork->ssl_connect_params.ca_crt_len = strlen(pNetwork->ssl_connect_params.ca_crt);
  584. pNetwork->ssl_connect_params.timeout_ms = 10000;
  585. pNetwork->type = NETWORK_TLS;
  586. }
  587. #endif
  588. pNetwork->host = host;
  589. pNetwork->port = port;
  590. pNetwork->profile_idx = profile_idx;
  591. rc = network_init(pNetwork);
  592. return rc;
  593. }
  594. int qcloud_http_client_connect(HTTPClient *client, const char *url, int port, const char *ca_crt)
  595. {
  596. if (client->network_stack.handle != 0) {
  597. Log_e("http client has connected to host!");
  598. return QCLOUD_ERR_HTTP_CONN;
  599. }
  600. int rc;
  601. char host[HTTP_CLIENT_MAX_HOST_LEN] = {0};
  602. rc = _http_client_parse_host(url, host, sizeof(host));
  603. if (rc != QCLOUD_RET_SUCCESS)
  604. return rc;
  605. rc = _http_network_init(client->profile_idx, &client->network_stack, host, port, ca_crt);
  606. if (rc != QCLOUD_RET_SUCCESS)
  607. return rc;
  608. rc = _http_client_connect(client);
  609. if (rc != QCLOUD_RET_SUCCESS) {
  610. Log_e("http_client_connect is error,rc = %d", rc);
  611. qcloud_http_client_close(client);
  612. } else {
  613. /* reduce log print due to frequent log server connect/disconnect */
  614. if (0 == strcmp(url, LOG_UPLOAD_SERVER_URL))
  615. UPLOAD_DBG("http client connect success");
  616. else
  617. Log_d("http client connect success");
  618. }
  619. return rc;
  620. }
  621. void qcloud_http_client_close(HTTPClient *client)
  622. {
  623. if (client->network_stack.handle != 0) {
  624. client->network_stack.disconnect(&client->network_stack);
  625. }
  626. }
  627. int qcloud_http_client_common(HTTPClient *client, const char *url, int port, const char *ca_crt, HttpMethod method,
  628. HTTPClientData *client_data)
  629. {
  630. int rc;
  631. if (client->network_stack.handle == 0) {
  632. rc = qcloud_http_client_connect(client, url, port, ca_crt);
  633. if (rc != QCLOUD_RET_SUCCESS)
  634. return rc;
  635. }
  636. rc = _http_client_send_request(client, url, method, client_data);
  637. if (rc != QCLOUD_RET_SUCCESS) {
  638. Log_e("http_client_send_request is error,rc = %d", rc);
  639. qcloud_http_client_close(client);
  640. return rc;
  641. }
  642. return QCLOUD_RET_SUCCESS;
  643. }
  644. int qcloud_http_recv_data(HTTPClient *client, uint32_t timeout_ms, HTTPClientData *client_data)
  645. {
  646. IOT_FUNC_ENTRY;
  647. int rc = QCLOUD_RET_SUCCESS;
  648. Timer timer;
  649. InitTimer(&timer);
  650. countdown_ms(&timer, (unsigned int)timeout_ms);
  651. if ((NULL != client_data->response_buf) && (0 != client_data->response_buf_len)) {
  652. rc = _http_client_recv_response(client, left_ms(&timer), client_data);
  653. if (rc < 0) {
  654. Log_e("http_client_recv_response is error,rc = %d", rc);
  655. qcloud_http_client_close(client);
  656. IOT_FUNC_EXIT_RC(rc);
  657. }
  658. }
  659. IOT_FUNC_EXIT_RC(QCLOUD_RET_SUCCESS);
  660. }
  661. #ifdef __cplusplus
  662. }
  663. #endif