| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409 |
- /*
- * Copyright (C) 2012 by egnite GmbH
- * Copyright (C) 2001-2004 by Ole Reinhardt <ole.reinhardt@embedded-it.de>
- *
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- *
- * 1. Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in the
- * documentation and/or other materials provided with the distribution.
- * 3. Neither the name of the copyright holders nor the names of
- * contributors may be used to endorse or promote products derived
- * from this software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
- * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
- * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
- * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
- * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
- * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
- * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
- * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
- * THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
- * SUCH DAMAGE.
- *
- * For additional information see http://www.ethernut.de/
- */
- /*!
- * $Id$
- */
- #include <io.h>
- #include <fcntl.h>
- #include <sys/stat.h>
- #if !defined(HTTPD_EXCLUDE_DATE)
- #include <pro/rfctime.h>
- #endif
- #include <pro/uhttp/utils.h>
- #include <pro/uhttp/modules/mod_cgi_func.h>
- #include <pro/uhttp/modules/mod_ssi.h>
- #include <stdlib.h>
- #include <string.h>
- #include <ctype.h>
- #include <stdio.h>
- #include <memdebug.h>
- #define SSI_TYPE_FILE 0x01
- #define SSI_TYPE_VIRTUAL 0x02
- #define SSI_TYPE_EXEC 0x03
- #define SSI_TYPE_ECHO 0x04
- #define HTTP_SSI_CMD_INCLUDE 1
- #define HTTP_SSI_CMD_ECHO 2
- #define HTTP_SSI_CMD_CONFIG 3
- #define HTTP_SSI_CMD_SET 4
- #define HTTP_SSI_CMD_IF 5
- #define HTTP_SSI_CMD_ELIF 6
- #define HTTP_SSI_CMD_ELSE 7
- #define HTTP_SSI_CMD_ENDIF 8
- #define HTTP_SSI_CMD_BLOCK 9
- #define HTTP_SSI_CMD_ENDBLOCK 10
- static const char* HttpSsiVarHandler(HTTPD_SESSION *hs, const char *name);
- static HTTP_SSI_VARHANDLER ssivar_handler = HttpSsiVarHandler;
- int HttpSsiProcessFile(HTTPD_SESSION *hs, int fd);
- typedef struct _HTTP_SSI_PARAM HTTP_SSI_PARAM;
- struct _HTTP_SSI_PARAM {
- const char *ipar_name;
- int ipar_namelen;
- const char *ipar_value;
- int ipar_valuelen;
- };
- typedef int (*HTTP_SSICMD_HANDLER) (HTTPD_SESSION*, HTTP_SSI_PARAM*);
- int HttpSsiIncludeHandler(HTTPD_SESSION *hs, HTTP_SSI_PARAM *prm)
- {
- int fd;
- if (prm->ipar_valuelen) {
- char *path = NULL;
- if (prm->ipar_namelen == 4 && memcmp(prm->ipar_name, "file", 4) == 0) {
- path = AllocConcatStringLen("", prm->ipar_value, prm->ipar_valuelen);
- }
- else if (prm->ipar_namelen == 7 && memcmp(prm->ipar_name, "virtual", 7) == 0) {
- path = AllocConcatStringLen(HTTP_ROOT, prm->ipar_value, prm->ipar_valuelen);
- }
- if (path) {
- fd = _open(path, _O_BINARY | _O_RDONLY);
- if (fd != -1) {
- HttpSsiProcessFile(hs, fd);
- _close(fd);
- free(path);
- return 0;
- }
- free(path);
- }
- }
- return -1;
- }
- int HttpSsiExecHandler(HTTPD_SESSION *hs, HTTP_SSI_PARAM *prm)
- {
- char *path = NULL;
- char *args;
- char *argcpy = NULL;
- HTTP_REQUEST *orig_req;
- if (prm->ipar_valuelen) {
- if (prm->ipar_namelen == 3 && memcmp(prm->ipar_name, "cgi", 3) == 0) {
- path = AllocConcatStringLen("", prm->ipar_value, prm->ipar_valuelen);
- }
- if (path) {
- args = strchr(path, '?');
- if (args) {
- *args++ = '\0';
- }
- orig_req = malloc(sizeof(HTTP_REQUEST));
- if (orig_req) {
- memcpy(orig_req, &hs->s_req, sizeof(HTTP_REQUEST));
- hs->s_req.req_method = HTTP_METHOD_GET;
- hs->s_req.req_argn = NULL;
- #if HTTP_VERSION >= 0x10
- hs->s_req.req_length = 0;
- #endif
- if (args == NULL || hs->s_req.req_query == NULL) {
- hs->s_req.req_query = args;
- }
- else {
- char *qs = strstr(args, "$QUERY_STRING");
- if (qs) {
- int len;
- *qs = '\0';
- len = strlen(args) + strlen(hs->s_req.req_query) + strlen(qs + 13);
- argcpy = malloc(len + 1);
- if (argcpy) {
- strcpy(argcpy, args);
- strcat(argcpy, hs->s_req.req_query);
- strcat(argcpy, qs + 13);
- }
- hs->s_req.req_query = argcpy;
- } else {
- hs->s_req.req_query = args;
- }
- }
- HttpCgiFunctionHandler(hs, NULL, path);
- free(hs->s_req.req_argn);
- memcpy(&hs->s_req, orig_req, sizeof(HTTP_REQUEST));
- free(orig_req);
- free(argcpy);
- }
- free(path);
- }
- }
- return 0;
- }
- int HttpSsiEchoHandler(HTTPD_SESSION *hs, HTTP_SSI_PARAM *prm)
- {
- static char *varname;
- const char *value = NULL;
- varname = realloc(varname, prm->ipar_valuelen + 1);
- memcpy(varname, prm->ipar_value, prm->ipar_valuelen);
- *(varname + prm->ipar_valuelen) = '\0';
- value = (*ssivar_handler)(hs, varname);
- s_puts(value, hs->s_stream);
- return 0;
- }
- typedef struct _HTTP_SSI_COMMAND HTTP_SSI_COMMAND;
- struct _HTTP_SSI_COMMAND {
- char *icmd_name;
- int icmd_namelen;
- HTTP_SSICMD_HANDLER icmd_handler;
- };
- HTTP_SSI_COMMAND ssiCmdList[] = {
- //{ "set", 3, NULL },
- { "include", 7, HttpSsiIncludeHandler },
- //{ "if", 2, NULL },
- //{ "fsize", 5, NULL },
- //{ "flastmod", 8, NULL },
- { "exec", 4, HttpSsiExecHandler },
- //{ "endif", 5, NULL },
- //{ "else", 4, NULL },
- //{ "elif", 4, NULL },
- { "echo", 4, HttpSsiEchoHandler },
- //{ "config", 6, NULL }
- };
- #define HTTP_SSI_NUM_COMMANDS (sizeof(ssiCmdList) / sizeof(HTTP_SSI_COMMAND))
- int HttpSsiParse(HTTPD_SESSION *hs, const char *buf, int len)
- {
- int i;
- //const char *var_name;
- //int var_name_len;
- //const char *var_value;
- //int var_value_len;
- HTTP_SSI_COMMAND *ssiCmd = NULL;
- HTTP_SSI_PARAM ssiPrm;
- memset(&ssiPrm, 0, sizeof(ssiPrm));
- while (len && isspace((int)*buf)) {
- buf++;
- len--;
- }
- for (i = 0; i < (int)HTTP_SSI_NUM_COMMANDS; i++) {
- if (len > ssiCmdList[i].icmd_namelen &&
- strncasecmp(buf, ssiCmdList[i].icmd_name, ssiCmdList[i].icmd_namelen) == 0) {
- ssiCmd = &ssiCmdList[i];
- len -= ssiCmd->icmd_namelen;
- buf += ssiCmd->icmd_namelen;
- break;
- }
- }
- if (i == HTTP_SSI_NUM_COMMANDS) {
- return -1;
- }
- while (len && isspace((int)*buf)) {
- buf++;
- len--;
- }
- if (len) {
- ssiPrm.ipar_name = buf;
- i = len;
- while (len) {
- if (!isalpha((int)*buf)) {
- ssiPrm.ipar_namelen = i - len;
- break;
- }
- buf++;
- len--;
- }
- if (len) {
- while (len && *buf != '=') {
- buf++;
- len--;
- }
- while (len && *buf != '"') {
- buf++;
- len--;
- }
- if (len) {
- buf++;
- len--;
- ssiPrm.ipar_value = buf;
- i = len;
- while (len) {
- if (*buf == '"') {
- ssiPrm.ipar_valuelen = i - len;
- break;
- }
- buf++;
- len--;
- }
- }
- }
- }
- ssiCmd->icmd_handler(hs, &ssiPrm);
- return 0;
- }
- int HttpSsiProcessFile(HTTPD_SESSION *hs, int fd)
- {
- long avail;
- char *buf;
- char *bp = NULL;
- int bufsiz;
- int buflen;
- int off;
- char *csp;
- char *cep;
- int cmdlen;
- avail = _filelength(fd);
- bufsiz = avail < 1460 ? (int) avail : 1460;
- buf = malloc(bufsiz + 1);
- buflen = 0;
- do {
- if (buflen == 0) {
- bp = buf;
- buflen = _read(fd, bp, bufsiz);
- if (buflen <= 0) {
- break;
- }
- avail -= buflen;
- buf[buflen] = '\0';
- }
- /* Search for embedded SSI command. */
- csp = strstr(bp, "<!--#");
- if (csp) {
- /* Found SSI command start, send any preceding data. */
- off = (int) (csp - bp);
- if (off) {
- s_write(bp, 1, off, hs->s_stream);
- bp += off;
- buflen -= off;
- }
- /* Search end of SSI command. */
- cep = strstr(csp + 5, "-->");
- if (cep) {
- /* Found SSI command end, process it. */
- cmdlen = (int) (cep - csp) + 3;
- if (HttpSsiParse(hs, bp + 5, cmdlen - 3)) {
- /* Bad SSI command, send it unprocessed. */
- s_write(bp, 1, cmdlen, hs->s_stream);
- }
- buflen -= cmdlen;
- bp += cmdlen;
- }
- else {
- /* SSI command end not found. */
- if (csp != buf) {
- /* If the command start was not at the beginning of
- the buffer, then move the file pointer back to
- the start of the command. */
- _seek(fd, -strlen(csp), SEEK_CUR);
- } else {
- /* SSI command doesn't fit in our buffer, send it
- unprocessed. */
- s_write(bp, 1, buflen, hs->s_stream);
- }
- /* Discard the buffer. */
- buflen = 0;
- }
- } else {
- /* No SSI command found. */
- if (bp != buf) {
- /* If our search was not started at the beginning of
- the buffer, then read the last 4 bytes again. */
- off = buflen >= 4 ? 4 : buflen;
- _seek(fd, -off, SEEK_CUR);
- buflen -= off;
- }
- s_write(bp, 1, buflen, hs->s_stream);
- buflen = 0;
- }
- } while (1);
- s_flush(hs->s_stream);
- free(buf);
- return 0;
- }
- int HttpSsiHandler(HTTPD_SESSION *hs, const MEDIA_TYPE_ENTRY *mt, const char *filepath)
- {
- int fd;
- fd = _open(filepath, _O_BINARY | _O_RDONLY);
- if (fd == -1) {
- HttpSendError(hs, 404);
- return 0;
- }
- HttpSendHeaderTop(hs, 200);
- s_puts("Cache-Control: no-cache, must-revalidate\r\n", hs->s_stream);
- #if !defined(HTTPD_EXCLUDE_DATE)
- {
- time_t now = time(NULL);
- s_vputs(hs->s_stream, ct_Expires, ": ", Rfc1123TimeString(gmtime(&now)), " GMT\r\n", NULL);
- }
- #endif
- HttpSendHeaderBottom(hs, mt->media_type, mt->media_subtype ? mt->media_subtype : mt->media_ext, -1);
- HttpSsiProcessFile(hs, fd);
- _close(fd);
- return 0;
- }
- static const char* HttpSsiVarHandler(HTTPD_SESSION *hs, const char *name)
- {
- return name;
- }
- HTTP_SSI_VARHANDLER HttpRegisterSsiVarHandler(HTTP_SSI_VARHANDLER handler)
- {
- HTTP_SSI_VARHANDLER rc;
- rc = ssivar_handler;
- ssivar_handler = handler;
- return rc;
- }
|