webclient_file.c 7.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324
  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. * 2017-07-26 chenyong modify log information
  9. */
  10. #include <stdint.h>
  11. #include <stdlib.h>
  12. #include <stdio.h>
  13. #include <string.h>
  14. #include <rtthread.h>
  15. #include <webclient.h>
  16. #ifdef RT_USING_DFS
  17. #include <unistd.h>
  18. #include <fcntl.h>
  19. #define DBG_ENABLE
  20. #define DBG_SECTION_NAME "web.file"
  21. #ifdef WEBCLIENT_DEBUG
  22. #define DBG_LEVEL DBG_LOG
  23. #else
  24. #define DBG_LEVEL DBG_INFO
  25. #endif /* WEBCLIENT_DEBUG */
  26. #define DBG_COLOR
  27. #include <rtdbg.h>
  28. /**
  29. * send GET request and store response data into the file.
  30. *
  31. * @param URI input server address
  32. * @param filename store response date to filename
  33. *
  34. * @return <0: GET request failed
  35. * =0: success
  36. */
  37. int webclient_get_file(const char* URI, const char* filename)
  38. {
  39. int fd = -1, rc = WEBCLIENT_OK;
  40. size_t offset;
  41. int length, total_length = 0;
  42. unsigned char *ptr = RT_NULL;
  43. struct webclient_session* session = RT_NULL;
  44. int resp_status = 0;
  45. session = webclient_session_create(WEBCLIENT_HEADER_BUFSZ);
  46. if(session == RT_NULL)
  47. {
  48. rc = -WEBCLIENT_NOMEM;
  49. goto __exit;
  50. }
  51. if ((resp_status = webclient_get(session, URI)) != 200)
  52. {
  53. LOG_E("get file failed, wrong response: %d (-0x%X).", resp_status, resp_status);
  54. rc = -WEBCLIENT_ERROR;
  55. goto __exit;
  56. }
  57. fd = open(filename, O_WRONLY | O_CREAT | O_TRUNC, 0);
  58. if (fd < 0)
  59. {
  60. LOG_E("get file failed, open file(%s) error.", filename);
  61. rc = -WEBCLIENT_ERROR;
  62. goto __exit;
  63. }
  64. ptr = (unsigned char *) web_malloc(WEBCLIENT_RESPONSE_BUFSZ);
  65. if (ptr == RT_NULL)
  66. {
  67. LOG_E("get file failed, no memory for response buffer.");
  68. rc = -WEBCLIENT_NOMEM;
  69. goto __exit;
  70. }
  71. if (session->content_length < 0)
  72. {
  73. while (1)
  74. {
  75. length = webclient_read(session, ptr, WEBCLIENT_RESPONSE_BUFSZ);
  76. if (length > 0)
  77. {
  78. write(fd, ptr, length);
  79. total_length += length;
  80. LOG_RAW(">");
  81. }
  82. else
  83. {
  84. break;
  85. }
  86. }
  87. }
  88. else
  89. {
  90. for (offset = 0; offset < (size_t) session->content_length;)
  91. {
  92. length = webclient_read(session, ptr,
  93. session->content_length - offset > WEBCLIENT_RESPONSE_BUFSZ ?
  94. WEBCLIENT_RESPONSE_BUFSZ : session->content_length - offset);
  95. if (length > 0)
  96. {
  97. write(fd, ptr, length);
  98. total_length += length;
  99. LOG_RAW(">");
  100. }
  101. else
  102. {
  103. break;
  104. }
  105. offset += length;
  106. }
  107. }
  108. if (total_length)
  109. {
  110. LOG_D("save %d bytes.", total_length);
  111. }
  112. __exit:
  113. if (fd >= 0)
  114. {
  115. close(fd);
  116. }
  117. if (session != RT_NULL)
  118. {
  119. webclient_close(session);
  120. session = RT_NULL;
  121. }
  122. if (ptr != RT_NULL)
  123. {
  124. web_free(ptr);
  125. }
  126. return rc;
  127. }
  128. /**
  129. * post file to http server.
  130. *
  131. * @param URI input server address
  132. * @param filename post data filename
  133. * @param form_data form data
  134. *
  135. * @return <0: POST request failed
  136. * =0: success
  137. */
  138. int webclient_post_file(const char* URI, const char* filename,
  139. const char* form_data)
  140. {
  141. size_t length;
  142. char boundary[60];
  143. int fd = -1, rc = WEBCLIENT_OK;
  144. char *header = RT_NULL, *header_ptr;
  145. unsigned char *buffer = RT_NULL, *buffer_ptr;
  146. struct webclient_session* session = RT_NULL;
  147. int resp_data_len = 0;
  148. fd = open(filename, O_RDONLY, 0);
  149. if (fd < 0)
  150. {
  151. LOG_D("post file failed, open file(%s) error.", filename);
  152. rc = -WEBCLIENT_FILE_ERROR;
  153. goto __exit;
  154. }
  155. /* get the size of file */
  156. length = lseek(fd, 0, SEEK_END);
  157. lseek(fd, 0, SEEK_SET);
  158. buffer = (unsigned char *) web_calloc(1, WEBCLIENT_RESPONSE_BUFSZ);
  159. if (buffer == RT_NULL)
  160. {
  161. LOG_D("post file failed, no memory for response buffer.");
  162. rc = -WEBCLIENT_NOMEM;
  163. goto __exit;
  164. }
  165. header = (char *) web_calloc(1, WEBCLIENT_HEADER_BUFSZ);
  166. if (header == RT_NULL)
  167. {
  168. LOG_D("post file failed, no memory for header buffer.");
  169. rc = -WEBCLIENT_NOMEM;
  170. goto __exit;
  171. }
  172. header_ptr = header;
  173. /* build boundary */
  174. web_snprintf(boundary, sizeof(boundary), "----------------------------%012d", rt_tick_get());
  175. /* build encapsulated mime_multipart information*/
  176. buffer_ptr = buffer;
  177. /* first boundary */
  178. buffer_ptr += web_snprintf((char*) buffer_ptr,
  179. WEBCLIENT_RESPONSE_BUFSZ - (buffer_ptr - buffer), "--%s\r\n", boundary);
  180. buffer_ptr += web_snprintf((char*) buffer_ptr,
  181. WEBCLIENT_RESPONSE_BUFSZ - (buffer_ptr - buffer),
  182. "Content-Disposition: form-data; %s\r\n", form_data);
  183. buffer_ptr += web_snprintf((char*) buffer_ptr,
  184. WEBCLIENT_RESPONSE_BUFSZ - (buffer_ptr - buffer),
  185. "Content-Type: application/octet-stream\r\n\r\n");
  186. /* calculate content-length */
  187. length += buffer_ptr - buffer;
  188. length += strlen(boundary) + 8; /* add the last boundary */
  189. /* build header for upload */
  190. header_ptr += web_snprintf(header_ptr,
  191. WEBCLIENT_HEADER_BUFSZ - (header_ptr - header),
  192. "Content-Length: %d\r\n", length);
  193. header_ptr += web_snprintf(header_ptr,
  194. WEBCLIENT_HEADER_BUFSZ - (header_ptr - header),
  195. "Content-Type: multipart/form-data; boundary=%s\r\n", boundary);
  196. session = webclient_session_create(WEBCLIENT_HEADER_BUFSZ);
  197. if(session == RT_NULL)
  198. {
  199. rc = -WEBCLIENT_NOMEM;
  200. goto __exit;
  201. }
  202. strncpy(session->header->buffer, header, strlen(header));
  203. session->header->length = strlen(session->header->buffer);
  204. rc = webclient_post(session, URI, NULL, 0);
  205. if(rc < 0)
  206. {
  207. goto __exit;
  208. }
  209. /* send mime_multipart */
  210. webclient_write(session, buffer, buffer_ptr - buffer);
  211. /* send file data */
  212. while (1)
  213. {
  214. length = read(fd, buffer, WEBCLIENT_RESPONSE_BUFSZ);
  215. if (length <= 0)
  216. {
  217. break;
  218. }
  219. webclient_write(session, buffer, length);
  220. }
  221. /* send last boundary */
  222. web_snprintf((char*) buffer, WEBCLIENT_RESPONSE_BUFSZ, "\r\n--%s--\r\n", boundary);
  223. webclient_write(session, buffer, strlen(boundary) + 8);
  224. extern int webclient_handle_response(struct webclient_session *session);
  225. if( webclient_handle_response(session) != 200)
  226. {
  227. rc = -WEBCLIENT_ERROR;
  228. goto __exit;
  229. }
  230. resp_data_len = webclient_content_length_get(session);
  231. if (resp_data_len > 0)
  232. {
  233. int bytes_read = 0;
  234. web_memset(buffer, 0x00, WEBCLIENT_RESPONSE_BUFSZ);
  235. do
  236. {
  237. bytes_read = webclient_read(session, buffer,
  238. resp_data_len < WEBCLIENT_RESPONSE_BUFSZ ? resp_data_len : WEBCLIENT_RESPONSE_BUFSZ);
  239. if (bytes_read <= 0)
  240. {
  241. break;
  242. }
  243. resp_data_len -= bytes_read;
  244. } while(resp_data_len > 0);
  245. }
  246. __exit:
  247. if (fd >= 0)
  248. {
  249. close(fd);
  250. }
  251. if (session != RT_NULL)
  252. {
  253. webclient_close(session);
  254. session = RT_NULL;
  255. }
  256. if (buffer != RT_NULL)
  257. {
  258. web_free(buffer);
  259. }
  260. if (header != RT_NULL)
  261. {
  262. web_free(header);
  263. }
  264. return rc;
  265. }
  266. int wget(int argc, char** argv)
  267. {
  268. if (argc != 3)
  269. {
  270. rt_kprintf("Please using: wget <URI> <filename>\n");
  271. return -1;
  272. }
  273. webclient_get_file(argv[1], argv[2]);
  274. return 0;
  275. }
  276. #ifdef FINSH_USING_MSH
  277. #include <finsh.h>
  278. MSH_CMD_EXPORT(wget, Get file by URI: wget <URI> <filename>.);
  279. #endif /* FINSH_USING_MSH */
  280. #endif /* RT_USING_DFS */