webclient.c 48 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651165216531654165516561657165816591660166116621663166416651666166716681669167016711672167316741675167616771678167916801681168216831684168516861687168816891690169116921693169416951696169716981699170017011702170317041705170617071708170917101711171217131714171517161717171817191720172117221723172417251726172717281729173017311732173317341735173617371738173917401741174217431744174517461747174817491750175117521753175417551756175717581759176017611762176317641765176617671768176917701771177217731774177517761777177817791780178117821783178417851786178717881789179017911792179317941795179617971798179918001801180218031804180518061807180818091810181118121813181418151816181718181819182018211822182318241825182618271828182918301831183218331834183518361837183818391840184118421843184418451846184718481849185018511852185318541855185618571858185918601861186218631864186518661867186818691870187118721873
  1. /*
  2. * Copyright (c) 2006-2022, RT-Thread Development Team
  3. *
  4. * SPDX-License-Identifier: Apache-2.0
  5. *
  6. * Change Logs:
  7. * Date Author Notes
  8. * 2013-05-05 Bernard the first version
  9. * 2013-06-10 Bernard fix the slow speed issue when download file.
  10. * 2015-11-14 aozima add content_length_remainder.
  11. * 2017-12-23 aozima update gethostbyname to getaddrinfo.
  12. * 2018-01-04 aozima add ipv6 address support.
  13. * 2018-07-26 chenyong modify log information
  14. * 2018-08-07 chenyong modify header processing
  15. * 2021-06-09 xiangxistu add shard download function
  16. */
  17. #include <stdio.h>
  18. #include <stdlib.h>
  19. #include <string.h>
  20. #include <ctype.h>
  21. #include <webclient.h>
  22. #include <sys/errno.h>
  23. #include <sys/time.h>
  24. /* support both enable and disable "SAL_USING_POSIX" */
  25. #if defined(RT_USING_SAL)
  26. #include <netdb.h>
  27. #include <sys/socket.h>
  28. #else
  29. #include <lwip/netdb.h>
  30. #include <lwip/sockets.h>
  31. #endif /* RT_USING_SAL */
  32. #define DBG_ENABLE
  33. #define DBG_SECTION_NAME "web"
  34. #ifdef WEBCLIENT_DEBUG
  35. #define DBG_LEVEL DBG_LOG
  36. #else
  37. #define DBG_LEVEL DBG_INFO
  38. #endif /* WEBCLIENT_DEBUG */
  39. #define DBG_COLOR
  40. #include <rtdbg.h>
  41. /* default receive or send timeout */
  42. #define WEBCLIENT_DEFAULT_TIMEO 6
  43. extern long int strtol(const char *nptr, char **endptr, int base);
  44. static int webclient_strncasecmp(const char *a, const char *b, size_t n)
  45. {
  46. uint8_t c1, c2;
  47. if (n <= 0)
  48. return 0;
  49. do {
  50. c1 = tolower(*a++);
  51. c2 = tolower(*b++);
  52. } while (--n && c1 && c1 == c2);
  53. return c1 - c2;
  54. }
  55. static const char *webclient_strstri(const char* str, const char* subStr)
  56. {
  57. int len = strlen(subStr);
  58. if(len == 0)
  59. {
  60. return RT_NULL;
  61. }
  62. while(*str)
  63. {
  64. if(webclient_strncasecmp(str, subStr, len) == 0)
  65. {
  66. return str;
  67. }
  68. ++str;
  69. }
  70. return RT_NULL;
  71. }
  72. static int webclient_send(struct webclient_session* session, const void *buffer, size_t len, int flag)
  73. {
  74. #ifdef WEBCLIENT_USING_MBED_TLS
  75. if (session->tls_session)
  76. {
  77. return mbedtls_client_write(session->tls_session, buffer, len);
  78. }
  79. #endif
  80. return send(session->socket, buffer, len, flag);
  81. }
  82. static int webclient_recv(struct webclient_session* session, void *buffer, size_t len, int flag)
  83. {
  84. #ifdef WEBCLIENT_USING_MBED_TLS
  85. if (session->tls_session)
  86. {
  87. return mbedtls_client_read(session->tls_session, buffer, len);
  88. }
  89. #endif
  90. return recv(session->socket, buffer, len, flag);
  91. }
  92. static int webclient_read_line(struct webclient_session *session, char *buffer, int size)
  93. {
  94. int rc, count = 0;
  95. char ch = 0, last_ch = 0;
  96. RT_ASSERT(session);
  97. RT_ASSERT(buffer);
  98. /* Keep reading until we fill the buffer. */
  99. while (count < size)
  100. {
  101. rc = webclient_recv(session, (unsigned char *) &ch, 1, 0);
  102. #if defined(WEBCLIENT_USING_MBED_TLS) || defined(WEBCLIENT_USING_SAL_TLS)
  103. if (session->is_tls && (rc == MBEDTLS_ERR_SSL_WANT_READ || rc == MBEDTLS_ERR_SSL_WANT_WRITE))
  104. {
  105. continue;
  106. }
  107. #endif
  108. if (rc <= 0)
  109. return rc;
  110. if (ch == '\n' && last_ch == '\r')
  111. break;
  112. buffer[count++] = ch;
  113. last_ch = ch;
  114. }
  115. if (count > size)
  116. {
  117. LOG_E("read line failed. The line data length is out of buffer size(%d)!", count);
  118. return -WEBCLIENT_ERROR;
  119. }
  120. return count;
  121. }
  122. /**
  123. * resolve server address
  124. *
  125. * @param session http session
  126. * @param res the server address information
  127. * @param url the input server URI address
  128. * @param request the pointer to point the request url, for example, /index.html
  129. *
  130. * @return 0 on resolve server address OK, others failed
  131. *
  132. * URL example:
  133. * http://www.rt-thread.org
  134. * http://www.rt-thread.org:80
  135. * https://www.rt-thread.org/
  136. * http://192.168.1.1:80/index.htm
  137. * http://[fe80::1]
  138. * http://[fe80::1]/
  139. * http://[fe80::1]/index.html
  140. * http://[fe80::1]:80/index.html
  141. */
  142. static int webclient_resolve_address(struct webclient_session *session, struct addrinfo **res,
  143. const char *url, const char **request)
  144. {
  145. int rc = WEBCLIENT_OK;
  146. char *ptr;
  147. char port_str[6] = "80"; /* default port of 80(http) */
  148. const char *port_ptr;
  149. const char *path_ptr;
  150. const char *host_addr = 0;
  151. int url_len, host_addr_len = 0;
  152. RT_ASSERT(res);
  153. RT_ASSERT(request);
  154. /* make sure *res = NULL before getaddrinfo */
  155. *res = RT_NULL;
  156. url_len = strlen(url);
  157. /* strip protocol(http or https) */
  158. if (strncmp(url, "http://", 7) == 0)
  159. {
  160. host_addr = url + 7;
  161. }
  162. else if (strncmp(url, "https://", 8) == 0)
  163. {
  164. strncpy(port_str, "443", 4);
  165. host_addr = url + 8;
  166. }
  167. else
  168. {
  169. rc = -WEBCLIENT_ERROR;
  170. goto __exit;
  171. }
  172. /* ipv6 address */
  173. if (host_addr[0] == '[')
  174. {
  175. host_addr += 1;
  176. ptr = strstr(host_addr, "]");
  177. if (!ptr)
  178. {
  179. rc = -WEBCLIENT_ERROR;
  180. goto __exit;
  181. }
  182. host_addr_len = ptr - host_addr;
  183. }
  184. path_ptr = strstr(host_addr, "/");
  185. *request = path_ptr ? path_ptr : "/";
  186. /* resolve port */
  187. port_ptr = strstr(host_addr + host_addr_len, ":");
  188. if (port_ptr && (!path_ptr || (port_ptr < path_ptr)))
  189. {
  190. if (!path_ptr)
  191. {
  192. strcpy(port_str, port_ptr + 1);
  193. }
  194. else
  195. {
  196. int port_len = path_ptr - port_ptr - 1;
  197. strncpy(port_str, port_ptr + 1, port_len);
  198. port_str[port_len] = '\0';
  199. }
  200. }
  201. else
  202. {
  203. port_ptr = RT_NULL;
  204. }
  205. if (port_ptr && (!path_ptr))
  206. {
  207. strcpy(port_str, port_ptr + 1);
  208. }
  209. /* ipv4 or domain. */
  210. if (!host_addr_len)
  211. {
  212. if (port_ptr)
  213. {
  214. host_addr_len = port_ptr - host_addr;
  215. }
  216. else if (path_ptr)
  217. {
  218. host_addr_len = path_ptr - host_addr;
  219. }
  220. else
  221. {
  222. host_addr_len = strlen(host_addr);
  223. }
  224. }
  225. if ((host_addr_len < 1) || (host_addr_len > url_len))
  226. {
  227. rc = -WEBCLIENT_ERROR;
  228. goto __exit;
  229. }
  230. /* get host address ok. */
  231. {
  232. char *host_addr_new = web_malloc(host_addr_len + 1);
  233. if (!host_addr_new)
  234. {
  235. rc = -WEBCLIENT_ERROR;
  236. goto __exit;
  237. }
  238. rt_memcpy(host_addr_new, host_addr, host_addr_len);
  239. host_addr_new[host_addr_len] = '\0';
  240. session->host = host_addr_new;
  241. }
  242. LOG_D("host address: %s , port: %s", session->host, port_str);
  243. #ifdef WEBCLIENT_USING_MBED_TLS
  244. if (session->tls_session)
  245. {
  246. session->tls_session->port = web_strdup(port_str);
  247. session->tls_session->host = web_strdup(session->host);
  248. if (session->tls_session->port == RT_NULL || session->tls_session->host == RT_NULL)
  249. {
  250. return -WEBCLIENT_NOMEM;
  251. }
  252. return rc;
  253. }
  254. #endif
  255. /* resolve the host name. */
  256. {
  257. struct addrinfo hint;
  258. int ret;
  259. web_memset(&hint, 0, sizeof(hint));
  260. ret = getaddrinfo(session->host, port_str, &hint, res);
  261. if (ret != 0)
  262. {
  263. LOG_E("getaddrinfo err: %d '%s'.", ret, session->host);
  264. rc = -WEBCLIENT_ERROR;
  265. goto __exit;
  266. }
  267. }
  268. __exit:
  269. if (rc != WEBCLIENT_OK)
  270. {
  271. if (session->host)
  272. {
  273. web_free(session->host);
  274. session->host = RT_NULL;
  275. }
  276. if (*res)
  277. {
  278. freeaddrinfo(*res);
  279. *res = RT_NULL;
  280. }
  281. }
  282. return rc;
  283. }
  284. #ifdef WEBCLIENT_USING_MBED_TLS
  285. /**
  286. * create and initialize https session.
  287. *
  288. * @param session webclient session
  289. * @param URI input server URI address
  290. *
  291. * @return <0: create failed, no memory or other errors
  292. * =0: success
  293. */
  294. static int webclient_open_tls(struct webclient_session *session, const char *URI)
  295. {
  296. int tls_ret = 0;
  297. const char *pers = "webclient";
  298. RT_ASSERT(session);
  299. session->tls_session = (MbedTLSSession *) web_calloc(1, sizeof(MbedTLSSession));
  300. if (session->tls_session == RT_NULL)
  301. {
  302. return -WEBCLIENT_NOMEM;
  303. }
  304. session->tls_session->buffer_len = WEBCLIENT_RESPONSE_BUFSZ;
  305. session->tls_session->buffer = web_malloc(session->tls_session->buffer_len);
  306. if(session->tls_session->buffer == RT_NULL)
  307. {
  308. LOG_E("no memory for tls_session buffer!");
  309. return -WEBCLIENT_ERROR;
  310. }
  311. if((tls_ret = mbedtls_client_init(session->tls_session, (void *)pers, strlen(pers))) < 0)
  312. {
  313. LOG_E("initialize https client failed return: -0x%x.", -tls_ret);
  314. return -WEBCLIENT_ERROR;
  315. }
  316. return WEBCLIENT_OK;
  317. }
  318. #endif
  319. /**
  320. * connect to http server.
  321. *
  322. * @param session webclient session
  323. * @param URI the input server URI address
  324. *
  325. * @return <0: connect failed or other error
  326. * =0: connect success
  327. */
  328. static int webclient_connect(struct webclient_session *session, const char *URI)
  329. {
  330. int rc = WEBCLIENT_OK;
  331. int socket_handle;
  332. struct timeval timeout;
  333. struct addrinfo *res = RT_NULL;
  334. const char *req_url;
  335. RT_ASSERT(session);
  336. RT_ASSERT(URI);
  337. timeout.tv_sec = WEBCLIENT_DEFAULT_TIMEO;
  338. timeout.tv_usec = 0;
  339. if (strncmp(URI, "https://", 8) == 0)
  340. {
  341. #if defined(WEBCLIENT_USING_SAL_TLS)
  342. session->is_tls = RT_TRUE;
  343. #elif defined(WEBCLIENT_USING_MBED_TLS)
  344. if(webclient_open_tls(session, URI) < 0)
  345. {
  346. LOG_E("connect failed, https client open URI(%s) failed!", URI);
  347. return -WEBCLIENT_ERROR;
  348. }
  349. session->is_tls = RT_TRUE;
  350. #else
  351. LOG_E("not support https connect, please enable webclient https configure!");
  352. rc = -WEBCLIENT_ERROR;
  353. goto __exit;
  354. #endif
  355. }
  356. /* Check valid IP address and URL */
  357. rc = webclient_resolve_address(session, &res, URI, &req_url);
  358. if (rc != WEBCLIENT_OK)
  359. {
  360. LOG_E("connect failed, resolve address error(%d).", rc);
  361. goto __exit;
  362. }
  363. /* Not use 'getaddrinfo()' for https connection */
  364. if (session->is_tls == RT_FALSE && res == RT_NULL)
  365. {
  366. rc = -WEBCLIENT_ERROR;
  367. goto __exit;
  368. }
  369. /* copy host address */
  370. if (req_url)
  371. {
  372. session->req_url = web_strdup(req_url);
  373. }
  374. else
  375. {
  376. LOG_E("connect failed, resolve request address error.");
  377. rc = -WEBCLIENT_ERROR;
  378. goto __exit;
  379. }
  380. #ifdef WEBCLIENT_USING_MBED_TLS
  381. if (session->tls_session)
  382. {
  383. int tls_ret = 0;
  384. if ((tls_ret = mbedtls_client_context(session->tls_session)) < 0)
  385. {
  386. LOG_E("connect failed, https client context return: -0x%x", -tls_ret);
  387. return -WEBCLIENT_ERROR;
  388. }
  389. if ((tls_ret = mbedtls_client_connect(session->tls_session)) < 0)
  390. {
  391. LOG_E("connect failed, https client connect return: -0x%x", -tls_ret);
  392. return -WEBCLIENT_CONNECT_FAILED;
  393. }
  394. socket_handle = session->tls_session->server_fd.fd;
  395. /* set recv timeout option */
  396. setsockopt(socket_handle, SOL_SOCKET, SO_RCVTIMEO, (void*) &timeout,
  397. sizeof(timeout));
  398. setsockopt(socket_handle, SOL_SOCKET, SO_SNDTIMEO, (void*) &timeout,
  399. sizeof(timeout));
  400. session->socket = socket_handle;
  401. return WEBCLIENT_OK;
  402. }
  403. #endif
  404. {
  405. #ifdef WEBCLIENT_USING_SAL_TLS
  406. if (session->is_tls)
  407. {
  408. socket_handle = socket(res->ai_family, SOCK_STREAM, PROTOCOL_TLS);
  409. }
  410. else
  411. {
  412. socket_handle = socket(res->ai_family, SOCK_STREAM, IPPROTO_TCP);
  413. }
  414. #else
  415. socket_handle = socket(res->ai_family, SOCK_STREAM, IPPROTO_TCP);
  416. #endif
  417. if (socket_handle < 0)
  418. {
  419. LOG_E("connect failed, create socket(%d) error.", socket_handle);
  420. rc = -WEBCLIENT_NOSOCKET;
  421. goto __exit;
  422. }
  423. /* set receive and send timeout option */
  424. setsockopt(socket_handle, SOL_SOCKET, SO_RCVTIMEO, (void *) &timeout,
  425. sizeof(timeout));
  426. setsockopt(socket_handle, SOL_SOCKET, SO_SNDTIMEO, (void *) &timeout,
  427. sizeof(timeout));
  428. if (connect(socket_handle, res->ai_addr, res->ai_addrlen) != 0)
  429. {
  430. /* connect failed, close socket */
  431. LOG_E("connect failed, connect socket(%d) error.", socket_handle);
  432. closesocket(socket_handle);
  433. rc = -WEBCLIENT_CONNECT_FAILED;
  434. goto __exit;
  435. }
  436. session->socket = socket_handle;
  437. }
  438. __exit:
  439. if (res)
  440. {
  441. freeaddrinfo(res);
  442. }
  443. return rc;
  444. }
  445. /**
  446. * add fields data to request header data.
  447. *
  448. * @param session webclient session
  449. * @param fmt fields format
  450. *
  451. * @return >0: data length of successfully added
  452. * <0: not enough header buffer size
  453. */
  454. int webclient_header_fields_add(struct webclient_session *session, const char *fmt, ...)
  455. {
  456. rt_int32_t length;
  457. va_list args;
  458. RT_ASSERT(session);
  459. RT_ASSERT(session->header->buffer);
  460. va_start(args, fmt);
  461. length = web_vsnprintf(session->header->buffer + session->header->length,
  462. session->header->size - session->header->length, fmt, args);
  463. va_end(args);
  464. if (length < 0)
  465. {
  466. LOG_E("add fields header data failed, return length(%d) error.", length);
  467. return -WEBCLIENT_ERROR;
  468. }
  469. session->header->length += length;
  470. /* check header size */
  471. if (session->header->length >= session->header->size)
  472. {
  473. LOG_E("not enough header buffer size(%d)!", session->header->size);
  474. return -WEBCLIENT_ERROR;
  475. }
  476. return length;
  477. }
  478. /**
  479. * get fields information from request/response header data.
  480. *
  481. * @param session webclient session
  482. * @param fields fields keyword
  483. *
  484. * @return = NULL: get fields data failed
  485. * != NULL: success get fields data
  486. */
  487. const char *webclient_header_fields_get(struct webclient_session *session, const char *fields)
  488. {
  489. char *resp_buf = RT_NULL;
  490. size_t resp_buf_len = 0;
  491. RT_ASSERT(session);
  492. RT_ASSERT(session->header->buffer);
  493. resp_buf = session->header->buffer;
  494. while (resp_buf_len < session->header->length)
  495. {
  496. if (webclient_strstri(resp_buf, fields) == resp_buf)
  497. {
  498. char *mime_ptr = RT_NULL;
  499. /* jump space */
  500. mime_ptr = strstr(resp_buf, ":");
  501. if (mime_ptr != NULL)
  502. {
  503. mime_ptr += 1;
  504. while (*mime_ptr && (*mime_ptr == ' ' || *mime_ptr == '\t'))
  505. mime_ptr++;
  506. return mime_ptr;
  507. }
  508. }
  509. if (*resp_buf == '\0')
  510. break;
  511. resp_buf += strlen(resp_buf) + 1;
  512. resp_buf_len += strlen(resp_buf) + 1;
  513. }
  514. return RT_NULL;
  515. }
  516. /**
  517. * get http response status code.
  518. *
  519. * @param session webclient session
  520. *
  521. * @return response status code
  522. */
  523. int webclient_resp_status_get(struct webclient_session *session)
  524. {
  525. RT_ASSERT(session);
  526. return session->resp_status;
  527. }
  528. /**
  529. * get http response data content length.
  530. *
  531. * @param session webclient session
  532. *
  533. * @return response content length
  534. */
  535. int webclient_content_length_get(struct webclient_session *session)
  536. {
  537. RT_ASSERT(session);
  538. return session->content_length;
  539. }
  540. static int webclient_send_header(struct webclient_session *session, int method)
  541. {
  542. int rc = WEBCLIENT_OK;
  543. char *header = RT_NULL;
  544. RT_ASSERT(session);
  545. header = session->header->buffer;
  546. if (session->header->length == 0 && method <= WEBCLIENT_GET)
  547. {
  548. /* use default header data */
  549. if (webclient_header_fields_add(session, "GET %s HTTP/1.1\r\n", session->req_url) < 0)
  550. return -WEBCLIENT_NOMEM;
  551. if (webclient_header_fields_add(session, "Host: %s\r\n", session->host) < 0)
  552. return -WEBCLIENT_NOMEM;
  553. if (webclient_header_fields_add(session, "User-Agent: RT-Thread HTTP Agent\r\n\r\n") < 0)
  554. return -WEBCLIENT_NOMEM;
  555. webclient_write(session, (unsigned char *) session->header->buffer, session->header->length);
  556. }
  557. else
  558. {
  559. if (method != WEBCLIENT_USER_METHOD)
  560. {
  561. /* check and add fields header data */
  562. if (web_memcmp(header, "HTTP/1.", strlen("HTTP/1.")))
  563. {
  564. char *header_buffer = RT_NULL;
  565. int length = 0;
  566. header_buffer = web_strdup(session->header->buffer);
  567. if (header_buffer == RT_NULL)
  568. {
  569. LOG_E("no memory for header buffer!");
  570. rc = -WEBCLIENT_NOMEM;
  571. goto __exit;
  572. }
  573. /* splice http request header data */
  574. if (method == WEBCLIENT_GET)
  575. length = web_snprintf(session->header->buffer, session->header->size, "GET %s HTTP/1.1\r\n%s",
  576. session->req_url ? session->req_url : "/", header_buffer);
  577. else if (method == WEBCLIENT_POST)
  578. length = web_snprintf(session->header->buffer, session->header->size, "POST %s HTTP/1.1\r\n%s",
  579. session->req_url ? session->req_url : "/", header_buffer);
  580. else if (method == WEBCLIENT_HEAD)
  581. length = web_snprintf(session->header->buffer, session->header->size, "HEAD %s HTTP/1.1\r\n%s",
  582. session->req_url ? session->req_url : "/", header_buffer);
  583. session->header->length = length;
  584. web_free(header_buffer);
  585. }
  586. if (strstr(header, "Host:") == RT_NULL)
  587. {
  588. if (webclient_header_fields_add(session, "Host: %s\r\n", session->host) < 0)
  589. return -WEBCLIENT_NOMEM;
  590. }
  591. if (strstr(header, "User-Agent:") == RT_NULL)
  592. {
  593. if (webclient_header_fields_add(session, "User-Agent: RT-Thread HTTP Agent\r\n") < 0)
  594. return -WEBCLIENT_NOMEM;
  595. }
  596. if (strstr(header, "Accept:") == RT_NULL)
  597. {
  598. if (webclient_header_fields_add(session, "Accept: */*\r\n") < 0)
  599. return -WEBCLIENT_NOMEM;
  600. }
  601. /* header data end */
  602. web_snprintf(session->header->buffer + session->header->length, session->header->size - session->header->length, "\r\n");
  603. session->header->length += 2;
  604. /* check header size */
  605. if (session->header->length > session->header->size)
  606. {
  607. LOG_E("send header failed, not enough header buffer size(%d)!", session->header->size);
  608. rc = -WEBCLIENT_NOBUFFER;
  609. goto __exit;
  610. }
  611. webclient_write(session, (unsigned char *) session->header->buffer, session->header->length);
  612. }
  613. else
  614. {
  615. webclient_write(session, (unsigned char *) session->header->buffer, session->header->length);
  616. }
  617. }
  618. /* get and echo request header data */
  619. {
  620. char *header_str, *header_ptr;
  621. int header_line_len;
  622. LOG_D("request header:");
  623. for(header_str = session->header->buffer; (header_ptr = strstr(header_str, "\r\n")) != RT_NULL; )
  624. {
  625. header_line_len = header_ptr - header_str;
  626. if (header_line_len > 0)
  627. {
  628. LOG_D("%.*s", header_line_len, header_str);
  629. }
  630. header_str = header_ptr + strlen("\r\n");
  631. }
  632. #ifdef WEBCLIENT_DEBUG
  633. LOG_RAW("\n");
  634. #endif
  635. }
  636. __exit:
  637. return rc;
  638. }
  639. /**
  640. * resolve server response data.
  641. *
  642. * @param session webclient session
  643. *
  644. * @return <0: resolve response data failed
  645. * =0: success
  646. */
  647. int webclient_handle_response(struct webclient_session *session)
  648. {
  649. int rc = WEBCLIENT_OK;
  650. char *mime_buffer = RT_NULL;
  651. char *mime_ptr = RT_NULL;
  652. const char *transfer_encoding;
  653. int i;
  654. RT_ASSERT(session);
  655. /* clean header buffer and size */
  656. web_memset(session->header->buffer, 0x00, session->header->size);
  657. session->header->length = 0;
  658. LOG_D("response header:");
  659. /* We now need to read the header information */
  660. while (1)
  661. {
  662. mime_buffer = session->header->buffer + session->header->length;
  663. /* read a line from the header information. */
  664. rc = webclient_read_line(session, mime_buffer, session->header->size - session->header->length);
  665. if (rc < 0)
  666. break;
  667. /* End of headers is a blank line. exit. */
  668. if (rc == 0)
  669. break;
  670. if ((rc == 1) && (mime_buffer[0] == '\r'))
  671. {
  672. mime_buffer[0] = '\0';
  673. break;
  674. }
  675. /* set terminal charater */
  676. mime_buffer[rc - 1] = '\0';
  677. /* echo response header data */
  678. LOG_D("%s", mime_buffer);
  679. session->header->length += rc;
  680. if (session->header->length >= session->header->size)
  681. {
  682. LOG_E("not enough header buffer size(%d)!", session->header->size);
  683. return -WEBCLIENT_NOMEM;
  684. }
  685. }
  686. /* get HTTP status code */
  687. mime_ptr = web_strdup(session->header->buffer);
  688. if (mime_ptr == RT_NULL)
  689. {
  690. LOG_E("no memory for get http status code buffer!");
  691. return -WEBCLIENT_NOMEM;
  692. }
  693. if (strstr(mime_ptr, "HTTP/1."))
  694. {
  695. char *ptr = mime_ptr;
  696. ptr += strlen("HTTP/1.x");
  697. while (*ptr && (*ptr == ' ' || *ptr == '\t'))
  698. ptr++;
  699. /* Terminate string after status code */
  700. for (i = 0; ((ptr[i] != ' ') && (ptr[i] != '\t')); i++);
  701. ptr[i] = '\0';
  702. session->resp_status = (int) strtol(ptr, RT_NULL, 10);
  703. }
  704. /* get content length */
  705. if (webclient_header_fields_get(session, "Content-Length") != RT_NULL)
  706. {
  707. session->content_length = atoi(webclient_header_fields_get(session, "Content-Length"));
  708. }
  709. session->content_remainder = session->content_length ? (size_t) session->content_length : 0xFFFFFFFF;
  710. transfer_encoding = webclient_header_fields_get(session, "Transfer-Encoding");
  711. if (transfer_encoding && strcmp(transfer_encoding, "chunked") == 0)
  712. {
  713. rt_uint16_t len = session->header->size;
  714. char *line = rt_malloc(len);
  715. /* chunk mode, we should get the first chunk size */
  716. webclient_read_line(session, line, len);
  717. session->chunk_sz = strtol(line, RT_NULL, 16);
  718. session->chunk_offset = 0;
  719. rt_free(line);
  720. }
  721. if (mime_ptr)
  722. {
  723. web_free(mime_ptr);
  724. }
  725. if (rc < 0)
  726. {
  727. return rc;
  728. }
  729. return session->resp_status;
  730. }
  731. /**
  732. * create webclient session, set maximum header and response size
  733. *
  734. * @param header_sz maximum send header size
  735. * @param resp_sz maximum response data size
  736. *
  737. * @return webclient session structure
  738. */
  739. struct webclient_session *webclient_session_create(size_t header_sz)
  740. {
  741. struct webclient_session *session;
  742. /* create session */
  743. session = (struct webclient_session *) web_calloc(1, sizeof(struct webclient_session));
  744. if (session == RT_NULL)
  745. {
  746. LOG_E("webclient create failed, no memory for webclient session!");
  747. return RT_NULL;
  748. }
  749. /* initialize the socket of session */
  750. session->socket = -1;
  751. session->content_length = -1;
  752. session->header = (struct webclient_header *) web_calloc(1, sizeof(struct webclient_header));
  753. if (session->header == RT_NULL)
  754. {
  755. LOG_E("webclient create failed, no memory for session header!");
  756. web_free(session);
  757. session = RT_NULL;
  758. return RT_NULL;
  759. }
  760. session->header->size = header_sz;
  761. session->header->buffer = (char *) web_calloc(1, header_sz);
  762. if (session->header->buffer == RT_NULL)
  763. {
  764. LOG_E("webclient create failed, no memory for session header buffer!");
  765. web_free(session->header);
  766. web_free(session);
  767. session = RT_NULL;
  768. return RT_NULL;
  769. }
  770. return session;
  771. }
  772. static int webclient_clean(struct webclient_session *session);
  773. /**
  774. * send GET request to http server and get response header.
  775. *
  776. * @param session webclient session
  777. * @param URI input server URI address
  778. * @param header GET request header
  779. * = NULL: use default header data
  780. * != NULL: use custom header data
  781. *
  782. * @return <0: send GET request failed
  783. * >0: response http status code
  784. */
  785. int webclient_get(struct webclient_session *session, const char *URI)
  786. {
  787. int rc = WEBCLIENT_OK;
  788. int resp_status = 0;
  789. RT_ASSERT(session);
  790. RT_ASSERT(URI);
  791. rc = webclient_connect(session, URI);
  792. if (rc != WEBCLIENT_OK)
  793. {
  794. /* connect to webclient server failed. */
  795. return rc;
  796. }
  797. rc = webclient_send_header(session, WEBCLIENT_GET);
  798. if (rc != WEBCLIENT_OK)
  799. {
  800. /* send header to webclient server failed. */
  801. return rc;
  802. }
  803. /* handle the response header of webclient server */
  804. resp_status = webclient_handle_response(session);
  805. LOG_D("get position handle response(%d).", resp_status);
  806. if (resp_status > 0)
  807. {
  808. const char *location = webclient_header_fields_get(session, "Location");
  809. /* relocation */
  810. if ((resp_status == 302 || resp_status == 301) && location)
  811. {
  812. char *new_url;
  813. new_url = web_strdup(location);
  814. if (new_url == RT_NULL)
  815. {
  816. return -WEBCLIENT_NOMEM;
  817. }
  818. /* clean webclient session */
  819. webclient_clean(session);
  820. /* clean webclient session header */
  821. session->header->length = 0;
  822. web_memset(session->header->buffer, 0, session->header->size);
  823. rc = webclient_get(session, new_url);
  824. web_free(new_url);
  825. return rc;
  826. }
  827. }
  828. return resp_status;
  829. }
  830. /**
  831. * register a handle function for http breakpoint resume and shard download.
  832. *
  833. * @param function
  834. *
  835. * @return the pointer
  836. */
  837. int *webclient_register_shard_position_function(struct webclient_session *session, int (*handle_function)(char *buffer, int size))
  838. {
  839. session->handle_function = handle_function;
  840. return (int *)session->handle_function;
  841. }
  842. /**
  843. * http breakpoint resume and shard download.
  844. *
  845. * @param session webclient session
  846. * @param URI input server URI address
  847. * @param length the length of point
  848. *
  849. * @return <0: send GET request failed
  850. * >0: response http status code
  851. */
  852. int webclient_shard_head_function(struct webclient_session *session, const char *URI, int *length)
  853. {
  854. RT_ASSERT(session);
  855. RT_ASSERT(URI);
  856. int rc = WEBCLIENT_OK;
  857. int resp_status = 0;
  858. if(session->socket == -1)
  859. {
  860. rc = webclient_connect(session, URI);
  861. if (rc != WEBCLIENT_OK)
  862. {
  863. return rc;
  864. }
  865. }
  866. /* clean header buffer and size */
  867. web_memset(session->header->buffer, 0x00, session->header->size);
  868. session->header->length = 0;
  869. rc = webclient_send_header(session, WEBCLIENT_HEAD);
  870. if (rc != WEBCLIENT_OK)
  871. {
  872. return rc;
  873. }
  874. /* handle the response header of webclient server by HEAD request */
  875. resp_status = webclient_handle_response(session);
  876. if(resp_status >= 0)
  877. {
  878. *length = webclient_content_length_get(session);
  879. LOG_D("The length[%04d] of real data of URI.", *length);
  880. }
  881. return rc;
  882. }
  883. /**
  884. * http breakpoint resume and shard download.
  885. *
  886. * @param session webclient session
  887. * @param URI input server URI address
  888. * @param start the position of you want to receive
  889. * @param length the length of data length from "webclient_shard_head_function"
  890. * @param mem_size the buffer size that you alloc
  891. *
  892. * @return <0: send GET request failed
  893. * >0: response http status code
  894. */
  895. int webclient_shard_position_function(struct webclient_session *session, const char *URI, int start, int length, int mem_size)
  896. {
  897. int rc = WEBCLIENT_OK;
  898. int result = RT_EOK;
  899. int resp_status = 0;
  900. size_t resp_len = 0;
  901. char *buffer = RT_NULL;
  902. int start_position, end_position = 0;
  903. int total_len = 0;
  904. RT_ASSERT(session);
  905. RT_ASSERT(URI);
  906. RT_ASSERT(mem_size);
  907. /* set the offset of "Range" and "total_len" */
  908. end_position = start;
  909. total_len = start + length;
  910. /* clean header buffer and size */
  911. web_memset(session->header->buffer, 0x00, session->header->size);
  912. session->header->length = 0;
  913. for(start_position = end_position; total_len != end_position + 1;)
  914. {
  915. RT_ASSERT(start_position <= total_len);
  916. int data_len = 0;
  917. end_position = start_position + mem_size - 1;
  918. if(end_position >= total_len)
  919. {
  920. end_position = total_len - 1;
  921. }
  922. /* splice header and send header */
  923. LOG_D("Range: [%04d -> %04d]", start_position, end_position);
  924. webclient_header_fields_add(session, "Range: bytes=%d-%d\r\n", start_position, end_position);
  925. rc = webclient_send_header(session, WEBCLIENT_GET);
  926. if (rc != WEBCLIENT_OK)
  927. {
  928. return rc;
  929. }
  930. /* handle the response header of webclient server */
  931. resp_status = webclient_handle_response(session);
  932. LOG_D("get position handle response(%d).", resp_status);
  933. if (resp_status == 206)
  934. {
  935. /* normal resp_status */
  936. }
  937. else if(resp_status > 0)
  938. {
  939. const char *location = webclient_header_fields_get(session, "Location");
  940. /* relocation */
  941. if ((resp_status == 302 || resp_status == 301) && location)
  942. {
  943. char *new_url;
  944. new_url = web_strdup(location);
  945. if (new_url == RT_NULL)
  946. {
  947. return -WEBCLIENT_NOMEM;
  948. }
  949. /* clean webclient session */
  950. webclient_clean(session);
  951. /* clean webclient session header */
  952. session->header->length = 0;
  953. web_memset(session->header->buffer, 0, session->header->size);
  954. rc = webclient_shard_position_function(session, new_url, start, length, mem_size);
  955. web_free(new_url);
  956. return rc;
  957. }
  958. }
  959. else
  960. {
  961. if(resp_status == -WEBCLIENT_ERROR)
  962. {
  963. if(session->socket == -WEBCLIENT_ERROR)
  964. {
  965. /* clean webclient session */
  966. webclient_clean(session);
  967. if(webclient_connect(session, URI) == WEBCLIENT_OK)
  968. {
  969. LOG_D("webclient reconnect success, retry at [%06d]", end_position);
  970. end_position = start_position;
  971. continue;
  972. }
  973. else
  974. {
  975. LOG_E("webclient reconnect failed. Please retry by yourself.");
  976. return -WEBCLIENT_ERROR;
  977. }
  978. }
  979. }
  980. }
  981. /* receive the incoming data */
  982. data_len = webclient_response(session, (void **)&buffer, &resp_len);
  983. if(data_len > 0)
  984. {
  985. start_position += data_len;
  986. result = session->handle_function(buffer, data_len);
  987. if(result != RT_EOK)
  988. {
  989. return -WEBCLIENT_ERROR;
  990. }
  991. }
  992. else
  993. {
  994. /* clean webclient session */
  995. webclient_clean(session);
  996. if(session->socket == -WEBCLIENT_ERROR)
  997. {
  998. webclient_connect(session, URI);
  999. }
  1000. }
  1001. /* clean header buffer and size */
  1002. web_memset(session->header->buffer, 0x00, session->header->size);
  1003. session->header->length = 0;
  1004. }
  1005. return rc;
  1006. }
  1007. /**
  1008. * send POST request to server and get response header data.
  1009. *
  1010. * @param session webclient session
  1011. * @param URI input server URI address
  1012. * @param post_data data send to the server
  1013. * = NULL: just connect server and send header
  1014. * != NULL: send header and body data, resolve response data
  1015. * @param data_len the length of send data
  1016. *
  1017. * @return <0: send POST request failed
  1018. * =0: send POST header success
  1019. * >0: response http status code
  1020. */
  1021. int webclient_post(struct webclient_session *session, const char *URI, const void *post_data, size_t data_len)
  1022. {
  1023. int rc = WEBCLIENT_OK;
  1024. int resp_status = 0;
  1025. RT_ASSERT(session);
  1026. RT_ASSERT(URI);
  1027. if ((post_data != RT_NULL) && (data_len == 0))
  1028. {
  1029. LOG_E("input post data length failed");
  1030. return -WEBCLIENT_ERROR;
  1031. }
  1032. rc = webclient_connect(session, URI);
  1033. if (rc != WEBCLIENT_OK)
  1034. {
  1035. /* connect to webclient server failed. */
  1036. return rc;
  1037. }
  1038. rc = webclient_send_header(session, WEBCLIENT_POST);
  1039. if (rc != WEBCLIENT_OK)
  1040. {
  1041. /* send header to webclient server failed. */
  1042. return rc;
  1043. }
  1044. if (post_data && (data_len > 0))
  1045. {
  1046. webclient_write(session, post_data, data_len);
  1047. /* resolve response data, get http status code */
  1048. resp_status = webclient_handle_response(session);
  1049. LOG_D("post handle response(%d).", resp_status);
  1050. }
  1051. return resp_status;
  1052. }
  1053. /**
  1054. * set receive and send data timeout.
  1055. *
  1056. * @param session http session
  1057. * @param millisecond timeout millisecond
  1058. *
  1059. * @return 0: set timeout success
  1060. */
  1061. int webclient_set_timeout(struct webclient_session *session, int millisecond)
  1062. {
  1063. struct timeval timeout;
  1064. int second = rt_tick_from_millisecond(millisecond) / 1000;
  1065. RT_ASSERT(session);
  1066. timeout.tv_sec = second;
  1067. timeout.tv_usec = 0;
  1068. /* set recv timeout option */
  1069. setsockopt(session->socket, SOL_SOCKET, SO_RCVTIMEO,
  1070. (void *) &timeout, sizeof(timeout));
  1071. setsockopt(session->socket, SOL_SOCKET, SO_SNDTIMEO,
  1072. (void *) &timeout, sizeof(timeout));
  1073. return 0;
  1074. }
  1075. static int webclient_next_chunk(struct webclient_session *session)
  1076. {
  1077. char line[64];
  1078. int length;
  1079. RT_ASSERT(session);
  1080. web_memset(line, 0x00, sizeof(line));
  1081. length = webclient_read_line(session, line, sizeof(line));
  1082. if (length > 0)
  1083. {
  1084. if (strcmp(line, "\r") == 0)
  1085. {
  1086. length = webclient_read_line(session, line, sizeof(line));
  1087. if (length <= 0)
  1088. {
  1089. closesocket(session->socket);
  1090. session->socket = -1;
  1091. return length;
  1092. }
  1093. }
  1094. }
  1095. else
  1096. {
  1097. closesocket(session->socket);
  1098. session->socket = -1;
  1099. return length;
  1100. }
  1101. session->chunk_sz = strtol(line, RT_NULL, 16);
  1102. session->chunk_offset = 0;
  1103. if (session->chunk_sz == 0)
  1104. {
  1105. /* end of chunks */
  1106. closesocket(session->socket);
  1107. session->socket = -1;
  1108. session->chunk_sz = -1;
  1109. }
  1110. return session->chunk_sz;
  1111. }
  1112. /**
  1113. * read data from http server.
  1114. *
  1115. * @param session http session
  1116. * @param buffer read buffer
  1117. * @param length the maximum of read buffer size
  1118. *
  1119. * @return <0: read data error
  1120. * =0: http server disconnect
  1121. * >0: successfully read data length
  1122. */
  1123. int webclient_read(struct webclient_session *session, void *buffer, size_t length)
  1124. {
  1125. int bytes_read = 0;
  1126. int total_read = 0;
  1127. int left;
  1128. RT_ASSERT(session);
  1129. /* get next chunk size is zero, client is already closed, return zero */
  1130. if (session->chunk_sz < 0)
  1131. {
  1132. return 0;
  1133. }
  1134. if (session->socket < 0)
  1135. {
  1136. return -WEBCLIENT_DISCONNECT;
  1137. }
  1138. if (length == 0)
  1139. {
  1140. return 0;
  1141. }
  1142. /* which is transfered as chunk mode */
  1143. if (session->chunk_sz)
  1144. {
  1145. if ((int) length > (session->chunk_sz - session->chunk_offset))
  1146. {
  1147. length = session->chunk_sz - session->chunk_offset;
  1148. }
  1149. bytes_read = webclient_recv(session, buffer, length, 0);
  1150. if (bytes_read <= 0)
  1151. {
  1152. if (errno == EWOULDBLOCK || errno == EAGAIN)
  1153. {
  1154. /* recv timeout */
  1155. return -WEBCLIENT_TIMEOUT;
  1156. }
  1157. else
  1158. {
  1159. closesocket(session->socket);
  1160. session->socket = -1;
  1161. return 0;
  1162. }
  1163. }
  1164. session->chunk_offset += bytes_read;
  1165. if (session->chunk_offset >= session->chunk_sz)
  1166. {
  1167. webclient_next_chunk(session);
  1168. }
  1169. return bytes_read;
  1170. }
  1171. if (session->content_length > 0)
  1172. {
  1173. if (length > session->content_remainder)
  1174. {
  1175. length = session->content_remainder;
  1176. }
  1177. if (length == 0)
  1178. {
  1179. return 0;
  1180. }
  1181. }
  1182. /*
  1183. * Read until: there is an error, we've read "size" bytes or the remote
  1184. * side has closed the connection.
  1185. */
  1186. left = length;
  1187. do
  1188. {
  1189. bytes_read = webclient_recv(session, (void *)((char *)buffer + total_read), left, 0);
  1190. if (bytes_read <= 0)
  1191. {
  1192. #if defined(WEBCLIENT_USING_SAL_TLS) || defined(WEBCLIENT_USING_MBED_TLS)
  1193. if(session->is_tls &&
  1194. (bytes_read == MBEDTLS_ERR_SSL_WANT_READ || bytes_read == MBEDTLS_ERR_SSL_WANT_WRITE))
  1195. {
  1196. continue;
  1197. }
  1198. #endif
  1199. LOG_D("receive data error(%d).", bytes_read);
  1200. if (total_read)
  1201. {
  1202. break;
  1203. }
  1204. else
  1205. {
  1206. if (errno == EWOULDBLOCK || errno == EAGAIN)
  1207. {
  1208. /* recv timeout */
  1209. LOG_E("receive data timeout.");
  1210. return -WEBCLIENT_TIMEOUT;
  1211. }
  1212. else
  1213. {
  1214. closesocket(session->socket);
  1215. session->socket = -1;
  1216. return 0;
  1217. }
  1218. }
  1219. }
  1220. left -= bytes_read;
  1221. total_read += bytes_read;
  1222. }
  1223. while (left);
  1224. if (session->content_length > 0)
  1225. {
  1226. session->content_remainder -= total_read;
  1227. }
  1228. return total_read;
  1229. }
  1230. /**
  1231. * write data to http server.
  1232. *
  1233. * @param session http session
  1234. * @param buffer write buffer
  1235. * @param length write buffer size
  1236. *
  1237. * @return <0: write data error
  1238. * =0: http server disconnect
  1239. * >0: successfully write data length
  1240. */
  1241. int webclient_write(struct webclient_session *session, const void *buffer, size_t length)
  1242. {
  1243. int bytes_write = 0;
  1244. int total_write = 0;
  1245. int left = length;
  1246. RT_ASSERT(session);
  1247. if (session->socket < 0)
  1248. {
  1249. return -WEBCLIENT_DISCONNECT;
  1250. }
  1251. if (length == 0)
  1252. {
  1253. return 0;
  1254. }
  1255. /* send all of data on the buffer. */
  1256. do
  1257. {
  1258. bytes_write = webclient_send(session, (void *)((char *)buffer + total_write), left, 0);
  1259. if (bytes_write <= 0)
  1260. {
  1261. #if defined(WEBCLIENT_USING_SAL_TLS) || defined(WEBCLIENT_USING_MBED_TLS)
  1262. if(session->is_tls &&
  1263. (bytes_write == MBEDTLS_ERR_SSL_WANT_READ || bytes_write == MBEDTLS_ERR_SSL_WANT_WRITE))
  1264. {
  1265. continue;
  1266. }
  1267. #endif
  1268. if (errno == EWOULDBLOCK || errno == EAGAIN)
  1269. {
  1270. /* send timeout */
  1271. if (total_write)
  1272. {
  1273. return total_write;
  1274. }
  1275. continue;
  1276. /* TODO: whether return the TIMEOUT
  1277. * return -WEBCLIENT_TIMEOUT; */
  1278. }
  1279. else
  1280. {
  1281. closesocket(session->socket);
  1282. session->socket = -1;
  1283. if (total_write == 0)
  1284. {
  1285. return -WEBCLIENT_DISCONNECT;
  1286. }
  1287. break;
  1288. }
  1289. }
  1290. left -= bytes_write;
  1291. total_write += bytes_write;
  1292. }
  1293. while (left);
  1294. return total_write;
  1295. }
  1296. /* close session socket, free host and request url */
  1297. static int webclient_clean(struct webclient_session *session)
  1298. {
  1299. #ifdef WEBCLIENT_USING_MBED_TLS
  1300. if (session->tls_session)
  1301. {
  1302. mbedtls_client_close(session->tls_session);
  1303. }
  1304. else
  1305. {
  1306. if (session->socket >= 0)
  1307. {
  1308. closesocket(session->socket);
  1309. session->socket = -1;
  1310. }
  1311. }
  1312. #else
  1313. if (session->socket >= 0)
  1314. {
  1315. closesocket(session->socket);
  1316. session->socket = -1;
  1317. }
  1318. #endif
  1319. if (session->host)
  1320. {
  1321. web_free(session->host);
  1322. session->host = RT_NULL;
  1323. }
  1324. if (session->req_url)
  1325. {
  1326. web_free(session->req_url);
  1327. session->req_url = RT_NULL;
  1328. }
  1329. session->content_length = -1;
  1330. return 0;
  1331. }
  1332. /**
  1333. * close a webclient client session.
  1334. *
  1335. * @param session http client session
  1336. *
  1337. * @return 0: close success
  1338. */
  1339. int webclient_close(struct webclient_session *session)
  1340. {
  1341. RT_ASSERT(session);
  1342. webclient_clean(session);
  1343. if (session->header && session->header->buffer)
  1344. {
  1345. web_free(session->header->buffer);
  1346. }
  1347. if (session->header)
  1348. {
  1349. web_free(session->header);
  1350. }
  1351. if (session)
  1352. {
  1353. web_free(session);
  1354. session = RT_NULL;
  1355. }
  1356. return 0;
  1357. }
  1358. /**
  1359. * get wenclient request response data.
  1360. *
  1361. * @param session wenclient session
  1362. * @param response response buffer address
  1363. * @param resp_len response buffer length
  1364. *
  1365. * @return response data size
  1366. */
  1367. int webclient_response(struct webclient_session *session, void **response, size_t *resp_len)
  1368. {
  1369. unsigned char *buf_ptr;
  1370. unsigned char *response_buf = 0;
  1371. int length, total_read = 0;
  1372. RT_ASSERT(session);
  1373. RT_ASSERT(response);
  1374. /* initialize response */
  1375. *response = RT_NULL;
  1376. /* not content length field kind */
  1377. if (session->content_length < 0)
  1378. {
  1379. size_t result_sz;
  1380. total_read = 0;
  1381. while (1)
  1382. {
  1383. unsigned char *new_resp = RT_NULL;
  1384. result_sz = total_read + WEBCLIENT_RESPONSE_BUFSZ;
  1385. new_resp = web_realloc(response_buf, result_sz + 1);
  1386. if (new_resp == RT_NULL)
  1387. {
  1388. LOG_E("no memory for realloc new response buffer!");
  1389. break;
  1390. }
  1391. response_buf = new_resp;
  1392. buf_ptr = (unsigned char *) response_buf + total_read;
  1393. /* read result */
  1394. length = webclient_read(session, buf_ptr, result_sz - total_read);
  1395. if (length <= 0)
  1396. break;
  1397. total_read += length;
  1398. }
  1399. }
  1400. else
  1401. {
  1402. int result_sz;
  1403. result_sz = session->content_length;
  1404. response_buf = web_calloc(1, result_sz + 1);
  1405. if (response_buf == RT_NULL)
  1406. {
  1407. return -WEBCLIENT_NOMEM;
  1408. }
  1409. buf_ptr = (unsigned char *) response_buf;
  1410. for (total_read = 0; total_read < result_sz;)
  1411. {
  1412. length = webclient_read(session, buf_ptr, result_sz - total_read);
  1413. if (length <= 0)
  1414. break;
  1415. buf_ptr += length;
  1416. total_read += length;
  1417. }
  1418. }
  1419. if ((total_read == 0) && (response_buf != 0))
  1420. {
  1421. web_free(response_buf);
  1422. response_buf = RT_NULL;
  1423. }
  1424. if (response_buf)
  1425. {
  1426. *response = (void *)response_buf;
  1427. *(response_buf + total_read) = '\0';
  1428. *resp_len = total_read;
  1429. }
  1430. return total_read;
  1431. }
  1432. /**
  1433. * add request(GET/POST) header data.
  1434. *
  1435. * @param request_header add request buffer address
  1436. * @param fmt fields format
  1437. *
  1438. * @return <=0: add header failed
  1439. * >0: add header data size
  1440. */
  1441. int webclient_request_header_add(char **request_header, const char *fmt, ...)
  1442. {
  1443. rt_int32_t length, header_length;
  1444. char *header;
  1445. va_list args;
  1446. RT_ASSERT(request_header);
  1447. if (*request_header == RT_NULL)
  1448. {
  1449. header = rt_calloc(1, WEBCLIENT_HEADER_BUFSZ);
  1450. if (header == RT_NULL)
  1451. {
  1452. LOG_E("No memory for webclient request header add.");
  1453. return RT_NULL;
  1454. }
  1455. *request_header = header;
  1456. }
  1457. else
  1458. {
  1459. header = *request_header;
  1460. }
  1461. va_start(args, fmt);
  1462. header_length = strlen(header);
  1463. length = web_vsnprintf(header + header_length, WEBCLIENT_HEADER_BUFSZ - header_length, fmt, args);
  1464. if (length < 0)
  1465. {
  1466. LOG_E("add request header data failed, return length(%d) error.", length);
  1467. return -WEBCLIENT_ERROR;
  1468. }
  1469. va_end(args);
  1470. /* check header size */
  1471. if (strlen(header) >= WEBCLIENT_HEADER_BUFSZ)
  1472. {
  1473. LOG_E("not enough request header data size(%d)!", WEBCLIENT_HEADER_BUFSZ);
  1474. return -WEBCLIENT_ERROR;
  1475. }
  1476. return length;
  1477. }
  1478. /**
  1479. * send request(GET/POST) to server and get response data.
  1480. *
  1481. * @param URI input server address
  1482. * @param header send header data
  1483. * = NULL: use default header data, must be GET request
  1484. * != NULL: user custom header data, GET or POST request
  1485. * @param post_data data sent to the server
  1486. * = NULL: it is GET request
  1487. * != NULL: it is POST request
  1488. * @param data_len send data length
  1489. * @param response response buffer address
  1490. * @param resp_len response buffer length
  1491. *
  1492. * @return <0: request failed
  1493. * >=0: response buffer size
  1494. */
  1495. int webclient_request(const char *URI, const char *header, const void *post_data, size_t data_len, void **response, size_t *resp_len)
  1496. {
  1497. struct webclient_session *session = RT_NULL;
  1498. int rc = WEBCLIENT_OK;
  1499. int totle_length = 0;
  1500. RT_ASSERT(URI);
  1501. if (post_data == RT_NULL && response == RT_NULL)
  1502. {
  1503. LOG_E("request get failed, get response data cannot be empty.");
  1504. return -WEBCLIENT_ERROR;
  1505. }
  1506. if ((post_data != RT_NULL) && (data_len == 0))
  1507. {
  1508. LOG_E("input post data length failed");
  1509. return -WEBCLIENT_ERROR;
  1510. }
  1511. if ((response != RT_NULL && resp_len == RT_NULL) ||
  1512. (response == RT_NULL && resp_len != RT_NULL))
  1513. {
  1514. LOG_E("input response data or length failed");
  1515. return -WEBCLIENT_ERROR;
  1516. }
  1517. if (post_data == RT_NULL)
  1518. {
  1519. /* send get request */
  1520. session = webclient_session_create(WEBCLIENT_HEADER_BUFSZ);
  1521. if (session == RT_NULL)
  1522. {
  1523. rc = -WEBCLIENT_NOMEM;
  1524. goto __exit;
  1525. }
  1526. if (header != RT_NULL)
  1527. {
  1528. char *header_str, *header_ptr;
  1529. int header_line_length;
  1530. for(header_str = (char *)header; (header_ptr = strstr(header_str, "\r\n")) != RT_NULL; )
  1531. {
  1532. header_line_length = header_ptr + strlen("\r\n") - header_str;
  1533. webclient_header_fields_add(session, "%.*s", header_line_length, header_str);
  1534. header_str += header_line_length;
  1535. }
  1536. }
  1537. if (webclient_get(session, URI) != 200)
  1538. {
  1539. rc = -WEBCLIENT_ERROR;
  1540. goto __exit;
  1541. }
  1542. totle_length = webclient_response(session, response, resp_len);
  1543. if (totle_length <= 0)
  1544. {
  1545. rc = -WEBCLIENT_ERROR;
  1546. goto __exit;
  1547. }
  1548. }
  1549. else
  1550. {
  1551. /* send post request */
  1552. session = webclient_session_create(WEBCLIENT_HEADER_BUFSZ);
  1553. if (session == RT_NULL)
  1554. {
  1555. rc = -WEBCLIENT_NOMEM;
  1556. goto __exit;
  1557. }
  1558. if (header != RT_NULL)
  1559. {
  1560. char *header_str, *header_ptr;
  1561. int header_line_length;
  1562. for(header_str = (char *)header; (header_ptr = strstr(header_str, "\r\n")) != RT_NULL; )
  1563. {
  1564. header_line_length = header_ptr + strlen("\r\n") - header_str;
  1565. webclient_header_fields_add(session, "%.*s", header_line_length, header_str);
  1566. header_str += header_line_length;
  1567. }
  1568. }
  1569. if (strstr(session->header->buffer, "Content-Length") == RT_NULL)
  1570. {
  1571. webclient_header_fields_add(session, "Content-Length: %d\r\n", strlen(post_data));
  1572. }
  1573. if (strstr(session->header->buffer, "Content-Type") == RT_NULL)
  1574. {
  1575. webclient_header_fields_add(session, "Content-Type: application/octet-stream\r\n");
  1576. }
  1577. if (webclient_post(session, URI, post_data, data_len) != 200)
  1578. {
  1579. rc = -WEBCLIENT_ERROR;
  1580. goto __exit;
  1581. }
  1582. totle_length = webclient_response(session, response, resp_len);
  1583. if (totle_length <= 0)
  1584. {
  1585. rc = -WEBCLIENT_ERROR;
  1586. goto __exit;
  1587. }
  1588. }
  1589. __exit:
  1590. if (session)
  1591. {
  1592. webclient_close(session);
  1593. session = RT_NULL;
  1594. }
  1595. if (rc < 0)
  1596. {
  1597. return rc;
  1598. }
  1599. return totle_length;
  1600. }