httpd_upload.c 8.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262
  1. /*
  2. * Copyright (C) 2012 by egnite GmbH
  3. *
  4. * All rights reserved.
  5. *
  6. * Redistribution and use in source and binary forms, with or without
  7. * modification, are permitted provided that the following conditions
  8. * are met:
  9. *
  10. * 1. Redistributions of source code must retain the above copyright
  11. * notice, this list of conditions and the following disclaimer.
  12. * 2. Redistributions in binary form must reproduce the above copyright
  13. * notice, this list of conditions and the following disclaimer in the
  14. * documentation and/or other materials provided with the distribution.
  15. * 3. Neither the name of the copyright holders nor the names of
  16. * contributors may be used to endorse or promote products derived
  17. * from this software without specific prior written permission.
  18. *
  19. * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
  20. * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
  21. * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
  22. * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
  23. * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
  24. * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
  25. * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
  26. * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
  27. * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
  28. * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
  29. * THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  30. * SUCH DAMAGE.
  31. *
  32. * For additional information see http://www.ethernut.de/
  33. */
  34. /*!
  35. * $Id$
  36. */
  37. #ifdef NUT_OS
  38. #include <sys/version.h>
  39. #include <dev/board.h>
  40. #include <dev/urom.h>
  41. #include <pro/dhcp.h>
  42. #endif
  43. #include <pro/uhttp/mediatypes.h>
  44. #include <pro/uhttp/modules/mod_redir.h>
  45. #include <pro/uhttp/modules/mod_cgi_func.h>
  46. #include <string.h>
  47. #include <stdlib.h>
  48. #include <stdio.h>
  49. #include <io.h>
  50. #include <fcntl.h>
  51. #include <sys/stat.h>
  52. #include <errno.h>
  53. extern char *http_root_path;
  54. #define HTTP_ROOT (http_root_path ? http_root_path : HTTP_DEFAULT_ROOT)
  55. #define MIN(a, b) ((a) < (b) ? (a) : (b))
  56. #define MAX_UPSIZE 1460
  57. static int CheckForPost(HTTP_REQUEST * req, int type)
  58. {
  59. if (req->req_method != HTTP_METHOD_POST || req->req_type == NULL) {
  60. /* Bad method, POST expected. */
  61. return -1;
  62. }
  63. if (type == 0 && strncasecmp(req->req_type, "application/x-www-form-urlencoded", 33) == 0) {
  64. return 0;
  65. }
  66. if (strncasecmp(req->req_type, "multipart/form-data", 19) == 0) {
  67. return 0;
  68. }
  69. /* Bad content. */
  70. return -1;
  71. }
  72. static char *GetMultipartBoundary(HTTP_REQUEST *req)
  73. {
  74. char *rp = NULL;
  75. const char *bptr;
  76. int blen;
  77. /* Make sure this is a multipart post. */
  78. if (CheckForPost(req, 1) == 0) {
  79. /* Retrieve the boundary string. */
  80. bptr = HttpArgValueSub(req->req_type, "boundary", &blen);
  81. if (bptr) {
  82. /* Build a delimiter string. */
  83. rp = malloc(blen + 3);
  84. if (rp) {
  85. rp[0] = '-';
  86. rp[1] = '-';
  87. memcpy(rp + 2, bptr, blen);
  88. rp[blen + 2] = '\0';
  89. }
  90. }
  91. }
  92. return rp;
  93. }
  94. static char *UploadFile(HTTPD_SESSION *hs, char *path)
  95. {
  96. char *rp = NULL;
  97. char *upname = NULL;
  98. long avail;
  99. char *line;
  100. char *delim;
  101. const char *sub_ptr;
  102. int sub_len;
  103. int fd = -1;
  104. int got = 0;
  105. HTTP_STREAM *stream = hs->s_stream;
  106. HTTP_REQUEST *req = &hs->s_req;
  107. /* Retrieve the boundary string. */
  108. delim = GetMultipartBoundary(req);
  109. if (delim == NULL) {
  110. return NULL;
  111. }
  112. avail = req->req_length;
  113. line = malloc(MIN(avail, MAX_UPSIZE) + 1);
  114. if (line == NULL) {
  115. /* No memory. */
  116. free(delim);
  117. return NULL;
  118. }
  119. /* If we have a delimiter, then process the boundary content. */
  120. while (avail > 0) {
  121. /* Parse the next boundary header. */
  122. if (HttpParseMultipartHeader(hs, delim, &avail)) {
  123. /* Broken connection. */
  124. break;
  125. }
  126. /* Ignore headers without content disposition line. */
  127. if (req->req_bnd_dispo) {
  128. /* Retrieve the name of the form item. */
  129. sub_ptr = HttpArgValueSub(req->req_bnd_dispo, "name", &sub_len);
  130. if (sub_ptr) {
  131. /* The item named 'upload' contains the binary data of the file. */
  132. if (strncasecmp(sub_ptr, "image", sub_len) == 0) {
  133. char *filename = NULL;
  134. int fd = -1;
  135. int eol = 0;
  136. /* Get the upload file name. */
  137. sub_ptr = HttpArgValueSub(req->req_bnd_dispo, "filename", &sub_len);
  138. if (sub_ptr && sub_len) {
  139. upname = malloc(sub_len + 1);
  140. if (upname) {
  141. memcpy(upname, sub_ptr, sub_len);
  142. upname[sub_len] = 0;
  143. /* Open the local file that the caller has provided. */
  144. #ifdef NUT_OS
  145. fd = _open(path, _O_CREAT | _O_TRUNC | _O_RDWR | _O_BINARY);
  146. #else
  147. fd = _open(path, _O_CREAT | _O_TRUNC | _O_RDWR | _O_BINARY, _S_IREAD | _S_IWRITE);
  148. #endif
  149. if (fd == -1) {
  150. printf("Error %d opening %s\n", errno, path);
  151. } else {
  152. printf("Uploading %s\n", upname);
  153. }
  154. }
  155. }
  156. /* Recieve the binary data. */
  157. while (avail) {
  158. /* Read until the next boundary line. */
  159. got = StreamReadUntilString(stream, delim, line, MIN(avail, MAX_UPSIZE));
  160. if (got <= 0) {
  161. break;
  162. }
  163. avail -= got;
  164. /* Write data to the local file, if one had been opened. */
  165. if (fd != -1) {
  166. if (eol) {
  167. _write(fd, "\r\n", 2);
  168. }
  169. if (got >= 2 && line[got - 2] == '\r' && line[got - 1] == '\n') {
  170. eol = 1;
  171. got -= 2;
  172. }
  173. _write(fd, line, got);
  174. }
  175. }
  176. if (fd != -1) {
  177. _close(fd);
  178. }
  179. free(filename);
  180. if (got < 0) {
  181. /* Broken connection. */
  182. break;
  183. }
  184. rp = upname;
  185. }
  186. else if (strncasecmp(sub_ptr, "upload", sub_len) == 0) {
  187. got = StreamReadUntilChars(hs->s_stream, "\n", "\r", line, MIN(avail, MAX_UPSIZE));
  188. if (got <= 0) {
  189. break;
  190. }
  191. }
  192. }
  193. }
  194. }
  195. if (fd != -1) {
  196. _close(fd);
  197. }
  198. free(delim);
  199. free(line);
  200. return rp;
  201. }
  202. static int CgiUpload(HTTPD_SESSION *hs)
  203. {
  204. char *upname;
  205. char *lclname;
  206. lclname = malloc(strlen(HTTP_ROOT) + sizeof("image.png"));
  207. strcat(strcpy(lclname, HTTP_ROOT), "image.png");
  208. upname = UploadFile(hs, lclname);
  209. HttpSendRedirection(hs, 303, "/index.html", NULL);
  210. return 0;
  211. }
  212. int main(void)
  213. {
  214. #ifdef NUT_OS
  215. NutRegisterDevice(&DEV_CONSOLE, 0, 0);
  216. freopen(DEV_CONSOLE.dev_name, "w", stdout);
  217. #endif
  218. puts("uHTTP upload sample\nBuild " __DATE__ " " __TIME__);
  219. #ifdef NUT_OS
  220. NutRegisterDevice(&DEV_ETHER, 0, 0);
  221. NutDhcpIfConfig(DEV_ETHER_NAME, NULL, 60000);
  222. NutRegisterDevice(&devUrom, 0, 0);
  223. #endif
  224. StreamInit();
  225. MediaTypeInitDefaults();
  226. HttpRegisterRedir("", "/index.html", 301);
  227. HttpRegisterCgiFunction("upload.cgi", CgiUpload);
  228. HttpRegisterMediaType("cgi", NULL, NULL, HttpCgiFunctionHandler);
  229. StreamClientAccept(HttpdClientHandler, NULL);
  230. puts("Exit");
  231. #ifdef NUT_OS
  232. for (;;) ;
  233. #endif
  234. return 0;
  235. }