wn_module_ssi.c 8.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311
  1. /*
  2. * File : wn_module_ssi.c
  3. * This file is part of RT-Thread RTOS
  4. * COPYRIGHT (C) 2006 - 2018, RT-Thread Development Team
  5. *
  6. * This software is dual-licensed: you can redistribute it and/or modify
  7. * it under the terms of the GNU General Public License version 2 as
  8. * published by the Free Software Foundation. For the terms of this
  9. * license, see <http://www.gnu.org/licenses/>.
  10. *
  11. * You are free to use this software under the terms of the GNU General
  12. * Public License, but WITHOUT ANY WARRANTY; without even the implied
  13. * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
  14. * See the GNU General Public License for more details.
  15. *
  16. * Alternatively for commercial application, you can contact us
  17. * by email <business@rt-thread.com> for commercial license.
  18. *
  19. * Change Logs:
  20. * Date Author Notes
  21. * 2012-06-25 Bernard the first version
  22. * 2023-12-10 RCSN add virtual handler
  23. */
  24. #include <string.h>
  25. #include <webnet.h>
  26. #include <wn_session.h>
  27. #include <wn_module.h>
  28. #ifdef RT_USING_DFS
  29. #if RT_VER_NUM >= 0x40100
  30. #include <stdio.h> /* fix SEEK_END */
  31. #include <fcntl.h> /* fix O_RDONLY */
  32. #include <unistd.h> /* fix lseek */
  33. #else
  34. #include <dfs_posix.h>
  35. #endif /*RT_VER_NUM >= 0x40100*/
  36. #endif
  37. #if defined(WEBNET_USING_SSI)
  38. #define SSI_INCLUDE_STRING "<!--#include "
  39. #define SSI_EXEC_STRING "<!--#exec "
  40. #define SSI_VIRTUAL_STRING "virtual=\""
  41. #define SSI_FILE_STRING "file=\""
  42. #define SSI_CGI_STRING "cgi=\""
  43. #define SSI_END_STRING "\" -->"
  44. #if defined(WEBNET_USING_SSI_VIRTUAL_HANDLER)
  45. struct webnet_ssi_virtual_item
  46. {
  47. const char* name;
  48. void (*handler)(struct webnet_session* session);
  49. };
  50. static struct webnet_ssi_virtual_item* _ssi_virtual_items = RT_NULL;
  51. static rt_uint32_t _ssi_virtual_count = 0;
  52. #endif
  53. static void _webnet_ssi_sendfile(struct webnet_session* session, const char* filename)
  54. {
  55. int fd;
  56. int file_length;
  57. rt_size_t size, readbytes;
  58. fd = open(filename, O_RDONLY, 0);
  59. if (fd < 0) return; /* open file failed */
  60. /* get file size */
  61. file_length = lseek(fd, 0, SEEK_END);
  62. /* seek to beginning of file */
  63. lseek(fd, 0, SEEK_SET);
  64. if (file_length <= 0)
  65. {
  66. close(fd);
  67. return ;
  68. }
  69. while (file_length)
  70. {
  71. if (file_length > sizeof(session->buffer))
  72. size = (rt_size_t) sizeof(session->buffer);
  73. else
  74. size = file_length;
  75. readbytes = read(fd, session->buffer, size);
  76. if (readbytes <= 0)
  77. /* no more data */
  78. break;
  79. if (webnet_session_write(session, session->buffer, readbytes) == 0)
  80. break;
  81. file_length -= (long) readbytes;
  82. }
  83. /* close file */
  84. close(fd);
  85. }
  86. static void _webnet_ssi_dofile(struct webnet_session* session, int fd)
  87. {
  88. char *ssi_begin, *ssi_end;
  89. char *offset, *end;
  90. char *buffer;
  91. char *path;
  92. rt_uint32_t length;
  93. ssi_begin = ssi_end = RT_NULL;
  94. offset = end = RT_NULL;
  95. buffer = path = RT_NULL;
  96. /* get file length */
  97. length = lseek(fd, 0, SEEK_END);
  98. lseek(fd, 0, SEEK_SET);
  99. /* allocate ssi include file path */
  100. path = (char*) wn_malloc(WEBNET_PATH_MAX);
  101. /* allocate read buffer */
  102. buffer = (char*) wn_malloc (length);
  103. if (path == RT_NULL || buffer == RT_NULL)
  104. {
  105. session->request->result_code = 500;
  106. goto __exit;
  107. }
  108. /* write page header */
  109. webnet_session_set_header(session, "text/html", 200, "OK", -1);
  110. /* read file to buffer */
  111. if (read(fd, buffer, length) != length) /* read failed */
  112. {
  113. session->request->result_code = 500;
  114. close(fd);
  115. goto __exit;
  116. }
  117. /* close file */
  118. close(fd);
  119. offset = buffer;
  120. end = buffer + length;
  121. while (offset < end)
  122. {
  123. /* get beginning of ssi */
  124. ssi_begin = strstr(offset, SSI_INCLUDE_STRING);
  125. if (ssi_begin == RT_NULL)
  126. {
  127. /* write content directly */
  128. webnet_session_write(session, (const rt_uint8_t*)offset, end - offset);
  129. break;
  130. }
  131. /* get end of ssi */
  132. ssi_end = strstr(ssi_begin, "\" -->");
  133. if (ssi_end == RT_NULL)
  134. {
  135. /* write content directly */
  136. webnet_session_write(session, (const rt_uint8_t*)offset, end - offset);
  137. break;
  138. }
  139. else
  140. {
  141. char *include_begin, *include_end;
  142. char *filename;
  143. /* write content */
  144. webnet_session_write(session, (const rt_uint8_t*)offset, ssi_begin - offset);
  145. offset = ssi_begin + sizeof(SSI_INCLUDE_STRING) - 1;
  146. include_begin = strstr(ssi_begin, SSI_VIRTUAL_STRING);
  147. if (include_begin != RT_NULL)
  148. {
  149. filename = include_begin + sizeof(SSI_VIRTUAL_STRING) - 1;
  150. include_end = strstr(filename, "\"");
  151. *include_end = '\0';
  152. #if defined(WEBNET_USING_SSI_VIRTUAL_HANDLER)
  153. rt_uint32_t index;
  154. for (index = 0; index < _ssi_virtual_count; index++)
  155. {
  156. if ((strlen(filename) == strlen(_ssi_virtual_items[index].name))
  157. && strncasecmp(filename, _ssi_virtual_items[index].name, strlen(_ssi_virtual_items[index].name)) == 0)
  158. {
  159. /* found it */
  160. _ssi_virtual_items[index].handler(session);
  161. }
  162. }
  163. #else
  164. if (webnet_session_get_physical_path(session, filename, path) == 0)
  165. {
  166. _webnet_ssi_sendfile(session, path);
  167. }
  168. #endif
  169. }
  170. else
  171. {
  172. include_begin = strstr(ssi_begin, SSI_FILE_STRING);
  173. if (include_begin != RT_NULL)
  174. {
  175. filename = include_begin + sizeof(SSI_FILE_STRING) - 1;
  176. include_end = strstr(filename, "\"");
  177. *include_end = '\0';
  178. _webnet_ssi_sendfile(session, filename);
  179. }
  180. }
  181. offset = ssi_end + sizeof(SSI_END_STRING) - 1;
  182. }
  183. }
  184. /* exit and release buffer buffer */
  185. __exit:
  186. if (path != RT_NULL) wn_free(path);
  187. if (buffer != RT_NULL) wn_free(buffer);
  188. }
  189. static const char* ssi_extension[] =
  190. {
  191. ".shtm",
  192. ".SHTM",
  193. ".shtml",
  194. ".SHTML",
  195. ".stm",
  196. ".STM",
  197. RT_NULL
  198. };
  199. int webnet_module_ssi(struct webnet_session* session, int event)
  200. {
  201. struct webnet_request* request;
  202. /* check parameter */
  203. RT_ASSERT(session != RT_NULL);
  204. request = session->request;
  205. RT_ASSERT(request != RT_NULL);
  206. if (event == WEBNET_EVENT_URI_POST)
  207. {
  208. int fd;
  209. int index;
  210. /* check whether a ssi file */
  211. index = 0;
  212. while (ssi_extension[index] != RT_NULL)
  213. {
  214. if (strstr(request->path, ssi_extension[index]) != RT_NULL)
  215. {
  216. /* try to open this file */
  217. fd = open(request->path, O_RDONLY, 0);
  218. if ( fd >= 0)
  219. {
  220. _webnet_ssi_dofile(session, fd);
  221. close(fd);
  222. return WEBNET_MODULE_FINISHED;
  223. }
  224. else
  225. {
  226. /* no this file */
  227. request->result_code = 404;
  228. return WEBNET_MODULE_FINISHED;
  229. }
  230. }
  231. index ++;
  232. }
  233. /* no this file, try index.shtm */
  234. {
  235. char *ssi_filename;
  236. ssi_filename = (char*) wn_malloc (WEBNET_PATH_MAX);
  237. if (ssi_filename != RT_NULL)
  238. {
  239. rt_snprintf(ssi_filename, WEBNET_PATH_MAX, "%s/index.shtm", request->path);
  240. fd = open(ssi_filename, O_RDONLY, 0);
  241. if (fd >= 0)
  242. {
  243. wn_free(ssi_filename);
  244. _webnet_ssi_dofile(session, fd);
  245. close(fd);
  246. return WEBNET_MODULE_FINISHED;
  247. }
  248. }
  249. wn_free(ssi_filename);
  250. }
  251. }
  252. return WEBNET_MODULE_CONTINUE;
  253. }
  254. #if defined(WEBNET_USING_SSI_VIRTUAL_HANDLER)
  255. void webnet_ssi_virtual_register(const char* name, void (*handler)(struct webnet_session* session))
  256. {
  257. if (_ssi_virtual_items == RT_NULL)
  258. {
  259. _ssi_virtual_count = 1;
  260. _ssi_virtual_items = (struct webnet_ssi_virtual_item*) wn_malloc (sizeof(struct webnet_ssi_virtual_item) * _ssi_virtual_count);
  261. }
  262. else
  263. {
  264. _ssi_virtual_count += 1;
  265. _ssi_virtual_items = (struct webnet_ssi_virtual_item*) wn_realloc (_ssi_virtual_items, sizeof(struct webnet_ssi_virtual_item) * _ssi_virtual_count);
  266. }
  267. RT_ASSERT(_ssi_virtual_items != RT_NULL);
  268. _ssi_virtual_items[_ssi_virtual_count - 1].name = name;
  269. _ssi_virtual_items[_ssi_virtual_count - 1].handler = handler;
  270. }
  271. RTM_EXPORT(webnet_ssi_virtual_register);
  272. #endif
  273. #endif