/*
* File : wn_module_ssi.c
* This file is part of RT-Thread RTOS
* COPYRIGHT (C) 2006 - 2018, RT-Thread Development Team
*
* This software is dual-licensed: you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation. For the terms of this
* license, see .
*
* You are free to use this software under the terms of the GNU General
* Public License, but WITHOUT ANY WARRANTY; without even the implied
* warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
* See the GNU General Public License for more details.
*
* Alternatively for commercial application, you can contact us
* by email for commercial license.
*
* Change Logs:
* Date Author Notes
* 2012-06-25 Bernard the first version
* 2023-12-10 RCSN add virtual handler
*/
#include
#include
#include
#include
#ifdef RT_USING_DFS
#if RT_VER_NUM >= 0x40100
#include /* fix SEEK_END */
#include /* fix O_RDONLY */
#include /* fix lseek */
#else
#include
#endif /*RT_VER_NUM >= 0x40100*/
#endif
#if defined(WEBNET_USING_SSI)
#define SSI_INCLUDE_STRING ""
#if defined(WEBNET_USING_SSI_VIRTUAL_HANDLER)
struct webnet_ssi_virtual_item
{
const char* name;
void (*handler)(struct webnet_session* session);
};
static struct webnet_ssi_virtual_item* _ssi_virtual_items = RT_NULL;
static rt_uint32_t _ssi_virtual_count = 0;
#endif
static void _webnet_ssi_sendfile(struct webnet_session* session, const char* filename)
{
int fd;
int file_length;
rt_size_t size, readbytes;
fd = open(filename, O_RDONLY, 0);
if (fd < 0) return; /* open file failed */
/* get file size */
file_length = lseek(fd, 0, SEEK_END);
/* seek to beginning of file */
lseek(fd, 0, SEEK_SET);
if (file_length <= 0)
{
close(fd);
return ;
}
while (file_length)
{
if (file_length > sizeof(session->buffer))
size = (rt_size_t) sizeof(session->buffer);
else
size = file_length;
readbytes = read(fd, session->buffer, size);
if (readbytes <= 0)
/* no more data */
break;
if (webnet_session_write(session, session->buffer, readbytes) == 0)
break;
file_length -= (long) readbytes;
}
/* close file */
close(fd);
}
static void _webnet_ssi_dofile(struct webnet_session* session, int fd)
{
char *ssi_begin, *ssi_end;
char *offset, *end;
char *buffer;
char *path;
rt_uint32_t length;
ssi_begin = ssi_end = RT_NULL;
offset = end = RT_NULL;
buffer = path = RT_NULL;
/* get file length */
length = lseek(fd, 0, SEEK_END);
lseek(fd, 0, SEEK_SET);
/* allocate ssi include file path */
path = (char*) wn_malloc(WEBNET_PATH_MAX);
/* allocate read buffer */
buffer = (char*) wn_malloc (length);
if (path == RT_NULL || buffer == RT_NULL)
{
session->request->result_code = 500;
goto __exit;
}
/* write page header */
webnet_session_set_header(session, "text/html", 200, "OK", -1);
/* read file to buffer */
if (read(fd, buffer, length) != length) /* read failed */
{
session->request->result_code = 500;
close(fd);
goto __exit;
}
/* close file */
close(fd);
offset = buffer;
end = buffer + length;
while (offset < end)
{
/* get beginning of ssi */
ssi_begin = strstr(offset, SSI_INCLUDE_STRING);
if (ssi_begin == RT_NULL)
{
/* write content directly */
webnet_session_write(session, (const rt_uint8_t*)offset, end - offset);
break;
}
/* get end of ssi */
ssi_end = strstr(ssi_begin, "\" -->");
if (ssi_end == RT_NULL)
{
/* write content directly */
webnet_session_write(session, (const rt_uint8_t*)offset, end - offset);
break;
}
else
{
char *include_begin, *include_end;
char *filename;
/* write content */
webnet_session_write(session, (const rt_uint8_t*)offset, ssi_begin - offset);
offset = ssi_begin + sizeof(SSI_INCLUDE_STRING) - 1;
include_begin = strstr(ssi_begin, SSI_VIRTUAL_STRING);
if (include_begin != RT_NULL)
{
filename = include_begin + sizeof(SSI_VIRTUAL_STRING) - 1;
include_end = strstr(filename, "\"");
*include_end = '\0';
#if defined(WEBNET_USING_SSI_VIRTUAL_HANDLER)
rt_uint32_t index;
for (index = 0; index < _ssi_virtual_count; index++)
{
if ((strlen(filename) == strlen(_ssi_virtual_items[index].name))
&& strncasecmp(filename, _ssi_virtual_items[index].name, strlen(_ssi_virtual_items[index].name)) == 0)
{
/* found it */
_ssi_virtual_items[index].handler(session);
}
}
#else
if (webnet_session_get_physical_path(session, filename, path) == 0)
{
_webnet_ssi_sendfile(session, path);
}
#endif
}
else
{
include_begin = strstr(ssi_begin, SSI_FILE_STRING);
if (include_begin != RT_NULL)
{
filename = include_begin + sizeof(SSI_FILE_STRING) - 1;
include_end = strstr(filename, "\"");
*include_end = '\0';
_webnet_ssi_sendfile(session, filename);
}
}
offset = ssi_end + sizeof(SSI_END_STRING) - 1;
}
}
/* exit and release buffer buffer */
__exit:
if (path != RT_NULL) wn_free(path);
if (buffer != RT_NULL) wn_free(buffer);
}
static const char* ssi_extension[] =
{
".shtm",
".SHTM",
".shtml",
".SHTML",
".stm",
".STM",
RT_NULL
};
int webnet_module_ssi(struct webnet_session* session, int event)
{
struct webnet_request* request;
/* check parameter */
RT_ASSERT(session != RT_NULL);
request = session->request;
RT_ASSERT(request != RT_NULL);
if (event == WEBNET_EVENT_URI_POST)
{
int fd;
int index;
/* check whether a ssi file */
index = 0;
while (ssi_extension[index] != RT_NULL)
{
if (strstr(request->path, ssi_extension[index]) != RT_NULL)
{
/* try to open this file */
fd = open(request->path, O_RDONLY, 0);
if ( fd >= 0)
{
_webnet_ssi_dofile(session, fd);
close(fd);
return WEBNET_MODULE_FINISHED;
}
else
{
/* no this file */
request->result_code = 404;
return WEBNET_MODULE_FINISHED;
}
}
index ++;
}
/* no this file, try index.shtm */
{
char *ssi_filename;
ssi_filename = (char*) wn_malloc (WEBNET_PATH_MAX);
if (ssi_filename != RT_NULL)
{
rt_snprintf(ssi_filename, WEBNET_PATH_MAX, "%s/index.shtm", request->path);
fd = open(ssi_filename, O_RDONLY, 0);
if (fd >= 0)
{
wn_free(ssi_filename);
_webnet_ssi_dofile(session, fd);
close(fd);
return WEBNET_MODULE_FINISHED;
}
}
wn_free(ssi_filename);
}
}
return WEBNET_MODULE_CONTINUE;
}
#if defined(WEBNET_USING_SSI_VIRTUAL_HANDLER)
void webnet_ssi_virtual_register(const char* name, void (*handler)(struct webnet_session* session))
{
if (_ssi_virtual_items == RT_NULL)
{
_ssi_virtual_count = 1;
_ssi_virtual_items = (struct webnet_ssi_virtual_item*) wn_malloc (sizeof(struct webnet_ssi_virtual_item) * _ssi_virtual_count);
}
else
{
_ssi_virtual_count += 1;
_ssi_virtual_items = (struct webnet_ssi_virtual_item*) wn_realloc (_ssi_virtual_items, sizeof(struct webnet_ssi_virtual_item) * _ssi_virtual_count);
}
RT_ASSERT(_ssi_virtual_items != RT_NULL);
_ssi_virtual_items[_ssi_virtual_count - 1].name = name;
_ssi_virtual_items[_ssi_virtual_count - 1].handler = handler;
}
RTM_EXPORT(webnet_ssi_virtual_register);
#endif
#endif