mod_ssi.c 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409
  1. /*
  2. * Copyright (C) 2012 by egnite GmbH
  3. * Copyright (C) 2001-2004 by Ole Reinhardt <ole.reinhardt@embedded-it.de>
  4. *
  5. * All rights reserved.
  6. *
  7. * Redistribution and use in source and binary forms, with or without
  8. * modification, are permitted provided that the following conditions
  9. * are met:
  10. *
  11. * 1. Redistributions of source code must retain the above copyright
  12. * notice, this list of conditions and the following disclaimer.
  13. * 2. Redistributions in binary form must reproduce the above copyright
  14. * notice, this list of conditions and the following disclaimer in the
  15. * documentation and/or other materials provided with the distribution.
  16. * 3. Neither the name of the copyright holders nor the names of
  17. * contributors may be used to endorse or promote products derived
  18. * from this software without specific prior written permission.
  19. *
  20. * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
  21. * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
  22. * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
  23. * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
  24. * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
  25. * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
  26. * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
  27. * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
  28. * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
  29. * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
  30. * THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  31. * SUCH DAMAGE.
  32. *
  33. * For additional information see http://www.ethernut.de/
  34. */
  35. /*!
  36. * $Id$
  37. */
  38. #include <io.h>
  39. #include <fcntl.h>
  40. #include <sys/stat.h>
  41. #if !defined(HTTPD_EXCLUDE_DATE)
  42. #include <pro/rfctime.h>
  43. #endif
  44. #include <pro/uhttp/utils.h>
  45. #include <pro/uhttp/modules/mod_cgi_func.h>
  46. #include <pro/uhttp/modules/mod_ssi.h>
  47. #include <stdlib.h>
  48. #include <string.h>
  49. #include <ctype.h>
  50. #include <stdio.h>
  51. #include <memdebug.h>
  52. #define SSI_TYPE_FILE 0x01
  53. #define SSI_TYPE_VIRTUAL 0x02
  54. #define SSI_TYPE_EXEC 0x03
  55. #define SSI_TYPE_ECHO 0x04
  56. #define HTTP_SSI_CMD_INCLUDE 1
  57. #define HTTP_SSI_CMD_ECHO 2
  58. #define HTTP_SSI_CMD_CONFIG 3
  59. #define HTTP_SSI_CMD_SET 4
  60. #define HTTP_SSI_CMD_IF 5
  61. #define HTTP_SSI_CMD_ELIF 6
  62. #define HTTP_SSI_CMD_ELSE 7
  63. #define HTTP_SSI_CMD_ENDIF 8
  64. #define HTTP_SSI_CMD_BLOCK 9
  65. #define HTTP_SSI_CMD_ENDBLOCK 10
  66. static const char* HttpSsiVarHandler(HTTPD_SESSION *hs, const char *name);
  67. static HTTP_SSI_VARHANDLER ssivar_handler = HttpSsiVarHandler;
  68. int HttpSsiProcessFile(HTTPD_SESSION *hs, int fd);
  69. typedef struct _HTTP_SSI_PARAM HTTP_SSI_PARAM;
  70. struct _HTTP_SSI_PARAM {
  71. const char *ipar_name;
  72. int ipar_namelen;
  73. const char *ipar_value;
  74. int ipar_valuelen;
  75. };
  76. typedef int (*HTTP_SSICMD_HANDLER) (HTTPD_SESSION*, HTTP_SSI_PARAM*);
  77. int HttpSsiIncludeHandler(HTTPD_SESSION *hs, HTTP_SSI_PARAM *prm)
  78. {
  79. int fd;
  80. if (prm->ipar_valuelen) {
  81. char *path = NULL;
  82. if (prm->ipar_namelen == 4 && memcmp(prm->ipar_name, "file", 4) == 0) {
  83. path = AllocConcatStringLen("", prm->ipar_value, prm->ipar_valuelen);
  84. }
  85. else if (prm->ipar_namelen == 7 && memcmp(prm->ipar_name, "virtual", 7) == 0) {
  86. path = AllocConcatStringLen(HTTP_ROOT, prm->ipar_value, prm->ipar_valuelen);
  87. }
  88. if (path) {
  89. fd = _open(path, _O_BINARY | _O_RDONLY);
  90. if (fd != -1) {
  91. HttpSsiProcessFile(hs, fd);
  92. _close(fd);
  93. free(path);
  94. return 0;
  95. }
  96. free(path);
  97. }
  98. }
  99. return -1;
  100. }
  101. int HttpSsiExecHandler(HTTPD_SESSION *hs, HTTP_SSI_PARAM *prm)
  102. {
  103. char *path = NULL;
  104. char *args;
  105. char *argcpy = NULL;
  106. HTTP_REQUEST *orig_req;
  107. if (prm->ipar_valuelen) {
  108. if (prm->ipar_namelen == 3 && memcmp(prm->ipar_name, "cgi", 3) == 0) {
  109. path = AllocConcatStringLen("", prm->ipar_value, prm->ipar_valuelen);
  110. }
  111. if (path) {
  112. args = strchr(path, '?');
  113. if (args) {
  114. *args++ = '\0';
  115. }
  116. orig_req = malloc(sizeof(HTTP_REQUEST));
  117. if (orig_req) {
  118. memcpy(orig_req, &hs->s_req, sizeof(HTTP_REQUEST));
  119. hs->s_req.req_method = HTTP_METHOD_GET;
  120. hs->s_req.req_argn = NULL;
  121. #if HTTP_VERSION >= 0x10
  122. hs->s_req.req_length = 0;
  123. #endif
  124. if (args == NULL || hs->s_req.req_query == NULL) {
  125. hs->s_req.req_query = args;
  126. }
  127. else {
  128. char *qs = strstr(args, "$QUERY_STRING");
  129. if (qs) {
  130. int len;
  131. *qs = '\0';
  132. len = strlen(args) + strlen(hs->s_req.req_query) + strlen(qs + 13);
  133. argcpy = malloc(len + 1);
  134. if (argcpy) {
  135. strcpy(argcpy, args);
  136. strcat(argcpy, hs->s_req.req_query);
  137. strcat(argcpy, qs + 13);
  138. }
  139. hs->s_req.req_query = argcpy;
  140. } else {
  141. hs->s_req.req_query = args;
  142. }
  143. }
  144. HttpCgiFunctionHandler(hs, NULL, path);
  145. free(hs->s_req.req_argn);
  146. memcpy(&hs->s_req, orig_req, sizeof(HTTP_REQUEST));
  147. free(orig_req);
  148. free(argcpy);
  149. }
  150. free(path);
  151. }
  152. }
  153. return 0;
  154. }
  155. int HttpSsiEchoHandler(HTTPD_SESSION *hs, HTTP_SSI_PARAM *prm)
  156. {
  157. static char *varname;
  158. const char *value = NULL;
  159. varname = realloc(varname, prm->ipar_valuelen + 1);
  160. memcpy(varname, prm->ipar_value, prm->ipar_valuelen);
  161. *(varname + prm->ipar_valuelen) = '\0';
  162. value = (*ssivar_handler)(hs, varname);
  163. s_puts(value, hs->s_stream);
  164. return 0;
  165. }
  166. typedef struct _HTTP_SSI_COMMAND HTTP_SSI_COMMAND;
  167. struct _HTTP_SSI_COMMAND {
  168. char *icmd_name;
  169. int icmd_namelen;
  170. HTTP_SSICMD_HANDLER icmd_handler;
  171. };
  172. HTTP_SSI_COMMAND ssiCmdList[] = {
  173. //{ "set", 3, NULL },
  174. { "include", 7, HttpSsiIncludeHandler },
  175. //{ "if", 2, NULL },
  176. //{ "fsize", 5, NULL },
  177. //{ "flastmod", 8, NULL },
  178. { "exec", 4, HttpSsiExecHandler },
  179. //{ "endif", 5, NULL },
  180. //{ "else", 4, NULL },
  181. //{ "elif", 4, NULL },
  182. { "echo", 4, HttpSsiEchoHandler },
  183. //{ "config", 6, NULL }
  184. };
  185. #define HTTP_SSI_NUM_COMMANDS (sizeof(ssiCmdList) / sizeof(HTTP_SSI_COMMAND))
  186. int HttpSsiParse(HTTPD_SESSION *hs, const char *buf, int len)
  187. {
  188. int i;
  189. //const char *var_name;
  190. //int var_name_len;
  191. //const char *var_value;
  192. //int var_value_len;
  193. HTTP_SSI_COMMAND *ssiCmd = NULL;
  194. HTTP_SSI_PARAM ssiPrm;
  195. memset(&ssiPrm, 0, sizeof(ssiPrm));
  196. while (len && isspace((int)*buf)) {
  197. buf++;
  198. len--;
  199. }
  200. for (i = 0; i < (int)HTTP_SSI_NUM_COMMANDS; i++) {
  201. if (len > ssiCmdList[i].icmd_namelen &&
  202. strncasecmp(buf, ssiCmdList[i].icmd_name, ssiCmdList[i].icmd_namelen) == 0) {
  203. ssiCmd = &ssiCmdList[i];
  204. len -= ssiCmd->icmd_namelen;
  205. buf += ssiCmd->icmd_namelen;
  206. break;
  207. }
  208. }
  209. if (i == HTTP_SSI_NUM_COMMANDS) {
  210. return -1;
  211. }
  212. while (len && isspace((int)*buf)) {
  213. buf++;
  214. len--;
  215. }
  216. if (len) {
  217. ssiPrm.ipar_name = buf;
  218. i = len;
  219. while (len) {
  220. if (!isalpha((int)*buf)) {
  221. ssiPrm.ipar_namelen = i - len;
  222. break;
  223. }
  224. buf++;
  225. len--;
  226. }
  227. if (len) {
  228. while (len && *buf != '=') {
  229. buf++;
  230. len--;
  231. }
  232. while (len && *buf != '"') {
  233. buf++;
  234. len--;
  235. }
  236. if (len) {
  237. buf++;
  238. len--;
  239. ssiPrm.ipar_value = buf;
  240. i = len;
  241. while (len) {
  242. if (*buf == '"') {
  243. ssiPrm.ipar_valuelen = i - len;
  244. break;
  245. }
  246. buf++;
  247. len--;
  248. }
  249. }
  250. }
  251. }
  252. ssiCmd->icmd_handler(hs, &ssiPrm);
  253. return 0;
  254. }
  255. int HttpSsiProcessFile(HTTPD_SESSION *hs, int fd)
  256. {
  257. long avail;
  258. char *buf;
  259. char *bp = NULL;
  260. int bufsiz;
  261. int buflen;
  262. int off;
  263. char *csp;
  264. char *cep;
  265. int cmdlen;
  266. avail = _filelength(fd);
  267. bufsiz = avail < 1460 ? (int) avail : 1460;
  268. buf = malloc(bufsiz + 1);
  269. buflen = 0;
  270. do {
  271. if (buflen == 0) {
  272. bp = buf;
  273. buflen = _read(fd, bp, bufsiz);
  274. if (buflen <= 0) {
  275. break;
  276. }
  277. avail -= buflen;
  278. buf[buflen] = '\0';
  279. }
  280. /* Search for embedded SSI command. */
  281. csp = strstr(bp, "<!--#");
  282. if (csp) {
  283. /* Found SSI command start, send any preceding data. */
  284. off = (int) (csp - bp);
  285. if (off) {
  286. s_write(bp, 1, off, hs->s_stream);
  287. bp += off;
  288. buflen -= off;
  289. }
  290. /* Search end of SSI command. */
  291. cep = strstr(csp + 5, "-->");
  292. if (cep) {
  293. /* Found SSI command end, process it. */
  294. cmdlen = (int) (cep - csp) + 3;
  295. if (HttpSsiParse(hs, bp + 5, cmdlen - 3)) {
  296. /* Bad SSI command, send it unprocessed. */
  297. s_write(bp, 1, cmdlen, hs->s_stream);
  298. }
  299. buflen -= cmdlen;
  300. bp += cmdlen;
  301. }
  302. else {
  303. /* SSI command end not found. */
  304. if (csp != buf) {
  305. /* If the command start was not at the beginning of
  306. the buffer, then move the file pointer back to
  307. the start of the command. */
  308. _seek(fd, -strlen(csp), SEEK_CUR);
  309. } else {
  310. /* SSI command doesn't fit in our buffer, send it
  311. unprocessed. */
  312. s_write(bp, 1, buflen, hs->s_stream);
  313. }
  314. /* Discard the buffer. */
  315. buflen = 0;
  316. }
  317. } else {
  318. /* No SSI command found. */
  319. if (bp != buf) {
  320. /* If our search was not started at the beginning of
  321. the buffer, then read the last 4 bytes again. */
  322. off = buflen >= 4 ? 4 : buflen;
  323. _seek(fd, -off, SEEK_CUR);
  324. buflen -= off;
  325. }
  326. s_write(bp, 1, buflen, hs->s_stream);
  327. buflen = 0;
  328. }
  329. } while (1);
  330. s_flush(hs->s_stream);
  331. free(buf);
  332. return 0;
  333. }
  334. int HttpSsiHandler(HTTPD_SESSION *hs, const MEDIA_TYPE_ENTRY *mt, const char *filepath)
  335. {
  336. int fd;
  337. fd = _open(filepath, _O_BINARY | _O_RDONLY);
  338. if (fd == -1) {
  339. HttpSendError(hs, 404);
  340. return 0;
  341. }
  342. HttpSendHeaderTop(hs, 200);
  343. s_puts("Cache-Control: no-cache, must-revalidate\r\n", hs->s_stream);
  344. #if !defined(HTTPD_EXCLUDE_DATE)
  345. {
  346. time_t now = time(NULL);
  347. s_vputs(hs->s_stream, ct_Expires, ": ", Rfc1123TimeString(gmtime(&now)), " GMT\r\n", NULL);
  348. }
  349. #endif
  350. HttpSendHeaderBottom(hs, mt->media_type, mt->media_subtype ? mt->media_subtype : mt->media_ext, -1);
  351. HttpSsiProcessFile(hs, fd);
  352. _close(fd);
  353. return 0;
  354. }
  355. static const char* HttpSsiVarHandler(HTTPD_SESSION *hs, const char *name)
  356. {
  357. return name;
  358. }
  359. HTTP_SSI_VARHANDLER HttpRegisterSsiVarHandler(HTTP_SSI_VARHANDLER handler)
  360. {
  361. HTTP_SSI_VARHANDLER rc;
  362. rc = ssivar_handler;
  363. ssivar_handler = handler;
  364. return rc;
  365. }