uhttpd.c 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518
  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. #if !defined(HTTPD_EXCLUDE_DATE)
  38. #include <pro/rfctime.h>
  39. #endif
  40. #include <pro/uhttp/utils.h>
  41. #include <pro/uhttp/uhttpd.h>
  42. #include <pro/uhttp/mediatypes.h>
  43. #include <stdlib.h>
  44. #include <string.h>
  45. #include <io.h>
  46. #include <fcntl.h>
  47. #include <memdebug.h>
  48. #ifndef HTTP_MAX_REQUEST_SIZE
  49. #define HTTP_MAX_REQUEST_SIZE 64
  50. #endif
  51. /*! Constant string "GET". */
  52. const char ct_GET[] = "GET";
  53. /*! Constant string "HEAD". */
  54. const char ct_HEAD[] = "HEAD";
  55. /*! Constant string "POST". */
  56. const char ct_POST[] = "POST";
  57. /*! Constant string "Content-Disposition". */
  58. const char ct_Content_Disposition[] = "Content-Disposition";
  59. /*! Constant string "Content-Type". */
  60. const char ct_Content_Type[] = "Content-Type";
  61. /*! Constant string "Accept-Encoding". */
  62. const char ct_Accept_Encoding[] = "Accept-Encoding";
  63. /*! Constant string "Authorization". */
  64. const char ct_Authorization[] = "Authorization";
  65. /*! Constant string "Connection". */
  66. const char ct_Connection[] = "Connection";
  67. /*! Constant string "close". */
  68. const char ct_close[] = "close";
  69. /*! Constant string "keep-alive". */
  70. const char ct_Keep_Alive[] = "keep-alive";
  71. /*! Constant string "Content-Length". */
  72. const char ct_Content_Length[] = "Content-Length";
  73. /*! Constant string "Cookie". */
  74. const char ct_Cookie[] = "Cookie";
  75. /*! Constant string "Host". */
  76. const char ct_Host[] = "Host";
  77. /*! Constant string "If-Modified-Since". */
  78. const char ct_If_Modified_Since[] = "If-Modified-Since";
  79. /*! Constant string "Referer". */
  80. const char ct_Referer[] = "Referer";
  81. /*! Constant string "User-Agent". */
  82. const char ct_User_Agent[] = "User-Agent";
  83. /*! Constant string "Last-Modified". */
  84. const char ct_Last_Modified[] = "Last-Modified";
  85. /*! Constant string "Expires". */
  86. const char ct_Expires[] = "Expires";
  87. /*! Constant string "Date". */
  88. const char ct_Date[] = "Date";
  89. /*! Constant string "Content-Encoding". */
  90. const char ct_Content_Encoding[] = "Content-Encoding";
  91. /*! Constant string "Location". */
  92. const char ct_Location[] = "Location";
  93. char *http_root_path;
  94. static int HttpAuthValidateAll(HTTPD_SESSION *req);
  95. HTTP_AUTH_VALIDATOR httpd_auth_validator = HttpAuthValidateAll;
  96. static int HttpLocationRedirNone(HTTPD_SESSION *hs);
  97. HTTP_LOC_REDIRECTOR httpd_loc_redirector = HttpLocationRedirNone;
  98. static int HttpAuthValidateAll(HTTPD_SESSION *req)
  99. {
  100. (void)req;
  101. return 0;
  102. }
  103. static int HttpLocationRedirNone(HTTPD_SESSION *hs)
  104. {
  105. (void)hs;
  106. return -1;
  107. }
  108. char *HttpArgParseFirst(HTTP_REQUEST * req)
  109. {
  110. req->req_argp = req->req_query;
  111. return HttpArgParseNext(req);
  112. }
  113. char *HttpArgParseNext(HTTP_REQUEST * req)
  114. {
  115. char *rp = NULL;
  116. char *cp;
  117. int len;
  118. if (req->req_argp) {
  119. cp = strchr(req->req_argp, '&');
  120. if (cp) {
  121. len = (int) (cp - req->req_argp);
  122. cp++;
  123. rp = malloc(len + 1);
  124. if (rp) {
  125. memcpy(rp, req->req_argp, len);
  126. *(rp + len) = '\0';
  127. }
  128. } else {
  129. rp = strdup(req->req_argp);
  130. }
  131. req->req_argp = cp;
  132. if (rp) {
  133. cp = strchr(rp, '=');
  134. if (cp) {
  135. *cp++ = '\0';
  136. HttpUrlUnescape(cp);
  137. }
  138. req->req_argv = cp;
  139. }
  140. free(req->req_argn);
  141. req->req_argn = rp;
  142. HttpUrlUnescape(rp);
  143. }
  144. return rp;
  145. }
  146. char *HttpArgReadNext(HTTPD_SESSION *hs, long *avail)
  147. {
  148. int bufsiz;
  149. int got;
  150. char *cp;
  151. char *rp = NULL;
  152. char *buf = NULL;
  153. if (*avail) {
  154. bufsiz = *avail > 128 ? 128 : *avail;
  155. buf = malloc(bufsiz + 1);
  156. if (buf) {
  157. got = StreamReadUntilChars(hs->s_stream, "&", NULL, buf, bufsiz);
  158. if (got > 0) {
  159. *avail -= got;
  160. rp = strdup(buf);
  161. free(hs->s_req.req_argn);
  162. hs->s_req.req_argn = rp;
  163. cp = strchr(rp, '=');
  164. if (cp) {
  165. *cp++ = '\0';
  166. HttpUrlUnescape(cp);
  167. hs->s_req.req_argv = cp;
  168. }
  169. HttpUrlUnescape(rp);
  170. }
  171. free(buf);
  172. }
  173. }
  174. return rp;
  175. }
  176. char *HttpArgValue(HTTP_REQUEST * req)
  177. {
  178. return req->req_argv;
  179. }
  180. const char *HttpArgValueSub(const char *str, const char *name, int *len)
  181. {
  182. const char *cp = str;
  183. size_t namelen = strlen(name);
  184. *len = 0;
  185. for (;;) {
  186. /* Move to the next disposition parameter. */
  187. cp = strchr(cp, ';');
  188. if (cp == NULL) {
  189. break;
  190. }
  191. /* Skip leading spaces. */
  192. while (*++cp == ' ');
  193. /* Check the parameter name. */
  194. if (strncasecmp(cp, name, namelen) == 0) {
  195. cp += namelen;
  196. /* Skip the name. */
  197. while (*cp && strchr("=\";", *cp) == NULL) {
  198. cp++;
  199. }
  200. /* Check if we have a name/value pair. */
  201. if (*cp == '=') {
  202. /* Skip leading spaces. */
  203. while (*++cp == ' ');
  204. /* Skip leading quote. */
  205. cp += *cp == '"';
  206. /* Determine the length of the value. */
  207. while (cp[*len] && strchr("\";", cp[*len]) == NULL) {
  208. (*len)++;
  209. }
  210. break;
  211. }
  212. }
  213. }
  214. return cp;
  215. }
  216. #if HTTP_VERSION >= 0x10
  217. int HttpParseMultipartHeader(HTTPD_SESSION *hs, const char *bnd, long *avail)
  218. {
  219. int rc = -1;
  220. int got = 0;
  221. char *buf;
  222. char **strval;
  223. int bndlen = strlen(bnd);
  224. buf = malloc(MIN(*avail, HTTP_MAX_REQUEST_SIZE) + 1);
  225. if (buf == NULL) {
  226. return -1;
  227. }
  228. free(hs->s_req.req_bnd_type);
  229. hs->s_req.req_bnd_type = NULL;
  230. free(hs->s_req.req_bnd_dispo);
  231. hs->s_req.req_bnd_dispo = NULL;
  232. while (*avail) {
  233. /* Read the next line, expecting a boundary. */
  234. got = StreamReadUntilChars(hs->s_stream, "\n", "\r", buf, MIN(*avail, HTTP_MAX_REQUEST_SIZE));
  235. if (got <= 0) {
  236. /* Broken connection. */
  237. break;
  238. }
  239. *avail -= got;
  240. if (got > bndlen && strncmp(buf, bnd, bndlen) == 0) {
  241. /* Found a boundary. */
  242. break;
  243. }
  244. }
  245. /* Got boundary, check if it's the last one. */
  246. if (got < bndlen + 2 || strncmp(buf + bndlen, "--", 2)) {
  247. while (*avail) {
  248. /* Get next header name. */
  249. got = StreamReadUntilChars(hs->s_stream, ":\n", "\r", buf, MIN(*avail, HTTP_MAX_REQUEST_SIZE));
  250. if (got <= 0) {
  251. /* Broken connection, stop parsing. */
  252. break;
  253. }
  254. *avail -= got;
  255. if (*buf == '\0') {
  256. /* Empty line marks the end of the request header. */
  257. rc = 0;
  258. break;
  259. }
  260. strval = NULL;
  261. if (strcasecmp(buf, ct_Content_Disposition) == 0) {
  262. strval = &hs->s_req.req_bnd_dispo;
  263. }
  264. else if (strcasecmp(buf, ct_Content_Type) == 0) {
  265. strval = &hs->s_req.req_bnd_type;
  266. }
  267. else {
  268. got = StreamReadUntilChars(hs->s_stream, "\n", NULL, NULL, *avail);
  269. if (got <= 0) {
  270. break;
  271. }
  272. *avail -= got;
  273. }
  274. if (strval) {
  275. got = StreamReadUntilChars(hs->s_stream, "\n", "\r", buf, MIN(*avail, HTTP_MAX_REQUEST_SIZE));
  276. if (got <= 0) {
  277. break;
  278. }
  279. *avail -= got;
  280. *strval = strdup(buf);
  281. }
  282. }
  283. }
  284. free(buf);
  285. return rc;
  286. }
  287. #endif
  288. int HttpParseHeader(HTTPD_SESSION *hs)
  289. {
  290. int got;
  291. char *buf;
  292. char *cp;
  293. buf = malloc(HTTP_MAX_REQUEST_SIZE + 1);
  294. if (buf == NULL) {
  295. return -1;
  296. }
  297. memset(&hs->s_req, 0, sizeof(HTTP_REQUEST));
  298. /* Read the first word of the request. */
  299. got = StreamReadUntilChars(hs->s_stream, " \n", "\r", buf, HTTP_MAX_REQUEST_SIZE);
  300. if (got <= 0) {
  301. free(buf);
  302. return -1;
  303. }
  304. /* Expect a valid method. */
  305. if (strcasecmp(buf, ct_GET) == 0) {
  306. hs->s_req.req_method = HTTP_METHOD_GET;
  307. }
  308. #if HTTP_VERSION >= 0x10
  309. else if (strcasecmp(buf, ct_HEAD) == 0) {
  310. hs->s_req.req_method = HTTP_METHOD_HEAD;
  311. }
  312. else if (strcasecmp(buf, ct_POST) == 0) {
  313. hs->s_req.req_method = HTTP_METHOD_POST;
  314. }
  315. #endif
  316. else {
  317. /* Method not implemented. */
  318. HttpSendError(hs, 501);
  319. free(buf);
  320. return -1;
  321. }
  322. /* Read the second word of the request. */
  323. got = StreamReadUntilChars(hs->s_stream, " \n", "\r", buf, HTTP_MAX_REQUEST_SIZE);
  324. /* Expect a valid URI. */
  325. cp = strchr(buf, '?');
  326. if (cp) {
  327. *cp++ = '\0';
  328. hs->s_req.req_query = strdup(cp);
  329. }
  330. hs->s_req.req_url = UriUnescape(strdup(buf));
  331. /* Read the remaining part of the request. */
  332. got = StreamReadUntilChars(hs->s_stream, "\n", " \r", buf, HTTP_MAX_REQUEST_SIZE);
  333. /* If no HTTP version is provided, then assume HTTP/0.9. */
  334. if (strncasecmp(buf, "HTTP/", 5)) {
  335. hs->s_req.req_version = 0x09;
  336. } else {
  337. hs->s_req.req_version = buf[5] - '0';
  338. hs->s_req.req_version <<= 4;
  339. hs->s_req.req_version += buf[6] - '0';
  340. }
  341. #if HTTP_VERSION >= 0x10
  342. #if HTTP_VERSION >= 0x11 && HTTP_KEEP_ALIVE_REQ
  343. hs->s_req.req_connection = HTTP_CONN_KEEP_ALIVE;
  344. #endif
  345. do {
  346. char **strval;
  347. /* Get next header name. */
  348. if (StreamReadUntilChars(hs->s_stream, ":\n", "\r", buf, HTTP_MAX_REQUEST_SIZE) <= 0) {
  349. /* Broken connection, stop parsing. */
  350. break;
  351. }
  352. if (*buf == '\0') {
  353. /* Empty line marks the end of the request header. */
  354. break;
  355. }
  356. strval = NULL;
  357. if (strcasecmp(buf, ct_Accept_Encoding) == 0) {
  358. strval = &hs->s_req.req_encoding;
  359. }
  360. else if (strcasecmp(buf, ct_Authorization) == 0) {
  361. strval = &hs->s_req.req_auth;
  362. }
  363. #if HTTP_KEEP_ALIVE_REQ
  364. else if (strcasecmp(buf, ct_Connection) == 0) {
  365. got = StreamReadUntilChars(hs->s_stream, "\n", "\r", buf, HTTP_MAX_REQUEST_SIZE);
  366. if (strcasecmp(buf, ct_close) == 0) {
  367. hs->s_req.req_connection = HTTP_CONN_CLOSE;
  368. }
  369. else if (strcasecmp(buf, ct_Keep_Alive) == 0) {
  370. hs->s_req.req_connection = HTTP_CONN_KEEP_ALIVE;
  371. }
  372. }
  373. #endif
  374. else if (strcasecmp(buf, ct_Content_Length) == 0) {
  375. got = StreamReadUntilChars(hs->s_stream, "\n", "\r", buf, HTTP_MAX_REQUEST_SIZE);
  376. hs->s_req.req_length = atol(buf);
  377. }
  378. else if (strcasecmp(buf, ct_Content_Type) == 0) {
  379. strval = &hs->s_req.req_type;
  380. }
  381. else if (strcasecmp(buf, ct_Cookie) == 0) {
  382. strval = &hs->s_req.req_cookie;
  383. }
  384. else if (strcasecmp(buf, ct_Host) == 0) {
  385. strval = &hs->s_req.req_host;
  386. }
  387. #if !defined(HTTPD_EXCLUDE_DATE)
  388. else if (strcasecmp(buf, ct_If_Modified_Since) == 0) {
  389. got = StreamReadUntilChars(hs->s_stream, "\n", "\r", buf, HTTP_MAX_REQUEST_SIZE);
  390. hs->s_req.req_ims = RfcTimeParse(buf);
  391. }
  392. #endif
  393. else if (strcasecmp(buf, ct_Referer) == 0) {
  394. strval = &hs->s_req.req_referer;
  395. }
  396. else if (strcasecmp(buf, ct_User_Agent) == 0) {
  397. strval = &hs->s_req.req_agent;
  398. }
  399. else {
  400. got = StreamReadUntilChars(hs->s_stream, "\n", NULL, NULL, 9999);
  401. }
  402. if (strval) {
  403. got = StreamReadUntilChars(hs->s_stream, "\n", "\r", buf, HTTP_MAX_REQUEST_SIZE);
  404. *strval = strdup(buf);
  405. }
  406. } while(1);
  407. #endif
  408. free(buf);
  409. return 0;
  410. }
  411. int HttpRegisterRootPath(char *path)
  412. {
  413. if (http_root_path) {
  414. free(http_root_path);
  415. }
  416. if (path) {
  417. http_root_path = strdup(path);
  418. if (http_root_path == NULL) {
  419. return -1;
  420. }
  421. } else {
  422. http_root_path = NULL;
  423. }
  424. return 0;
  425. }
  426. void HttpdClientHandler(HTTP_STREAM *sp)
  427. {
  428. char *filename;
  429. HTTPD_SESSION *hs;
  430. HTTP_REQUEST *req;
  431. MEDIA_TYPE_ENTRY *mt;
  432. int err = 0;
  433. hs = malloc(sizeof(HTTPD_SESSION));
  434. if (hs) {
  435. do {
  436. hs->s_stream = sp;
  437. req = &hs->s_req;
  438. if (HttpParseHeader(hs)) {
  439. break;
  440. }
  441. if ((*httpd_auth_validator) (hs)) {
  442. err = 401;
  443. }
  444. else if ((*httpd_loc_redirector) (hs)) {
  445. /* No redirection available. */
  446. filename = AllocConcatStrings(HTTP_ROOT, req->req_url, NULL);
  447. if (filename) {
  448. mt = GetMediaTypeEntry(filename);
  449. if (mt == NULL) {
  450. err = 404;
  451. } else {
  452. mt->media_handler(hs, mt, filename);
  453. }
  454. free(filename);
  455. } else {
  456. err = 404;
  457. }
  458. }
  459. if (err) {
  460. HttpSendError(hs, err);
  461. }
  462. free(req->req_url);
  463. free(req->req_query);
  464. free(req->req_argp);
  465. free(req->req_argn);
  466. #if HTTP_VERSION >= 0x10
  467. free(req->req_realm);
  468. free(req->req_type);
  469. free(req->req_cookie);
  470. free(req->req_auth);
  471. free(req->req_agent);
  472. free(req->req_referer);
  473. free(req->req_host);
  474. free(req->req_encoding);
  475. free(req->req_bnd_dispo);
  476. free(req->req_bnd_type);
  477. #endif
  478. } while(req->req_connection == HTTP_CONN_KEEP_ALIVE);
  479. free(hs);
  480. }
  481. }