mirror of
https://github.com/transmission/transmission
synced 2024-12-24 16:52:39 +00:00
* add some #ifdefs to fix -DNO_SSI
* remove the Win CE stuff for now, since we don't support Windows yet.
This commit is contained in:
parent
788ccd60d3
commit
3f93fa1f2e
11 changed files with 14 additions and 2817 deletions
67
third-party/shttpd/Makefile
vendored
67
third-party/shttpd/Makefile
vendored
|
@ -1,67 +0,0 @@
|
|||
SRCS= string.c shttpd.c log.c auth.c md5.c cgi.c config.c io_ssi.c \
|
||||
io_file.c io_socket.c io_ssl.c io_emb.c io_dir.c io_cgi.c
|
||||
HDRS= defs.h llist.h shttpd.h std_includes.h io.h md5.h ssl.h \
|
||||
compat_unix.h compat_win32.h compat_rtems.h config.h
|
||||
OBJS= $(SRCS:%.c=%.o)
|
||||
PROG= shttpd
|
||||
|
||||
# Possible flags: (in brackets are rough numbers for 'gcc -O2' on i386)
|
||||
# -DHAVE_MD5 - use system md5 library (-2kb)
|
||||
# -DNDEBUG - strip off all debug code (-5kb)
|
||||
# -D_DEBUG - build debug version (very noisy) (+6kb)
|
||||
# -DNO_CGI - disable CGI support (-5kb)
|
||||
# -DNO_SSL - disable SSL functionality (-2kb)
|
||||
# -DNO_AUTH - disable authorization support (-4kb)
|
||||
# -DCONFIG=\"file\" - use `file' as the default config file
|
||||
# -DNO_SSI - disable SSI support (-4kb)
|
||||
|
||||
# XXX Note for the windows users. In order to build shttpd, MSVS6 is needed.
|
||||
# Follow these steps:
|
||||
# 1. Add c:\path_to_msvs6\bin to the system Path environment variable.
|
||||
# 2. Add two new system environment variables:
|
||||
# LIB=c:\path_to_msvs6\lib
|
||||
# INCLUDE=c:\path_to_msvs6\include
|
||||
# 3. start console, go to shttpd-VERSION\src\ directory
|
||||
# 4. type "nmake msvc"
|
||||
# 5. go to shttpd-VERSION\examples , type "nmake msvc"
|
||||
|
||||
|
||||
VC6= ..\..\.. # MSVC installation path
|
||||
CL_FLAGS= /MD /TC /nologo /DNDEBUG /Os # MSVC compiler flags
|
||||
|
||||
all:
|
||||
@echo "make (unix|msvc|mingw|rtems)"
|
||||
@echo on Linux, do \'LIBS=-ldl make unix\'
|
||||
|
||||
.c.o:
|
||||
$(CC) -c $(CFLAGS) $< -o $@
|
||||
|
||||
unix: $(OBJS)
|
||||
$(AR) -r lib$(PROG).a $(OBJS) && ranlib lib$(PROG).a
|
||||
$(CC) $(CFLAGS) compat_unix.c standalone.c \
|
||||
-o $(PROG) $(LIBS) -L. -l$(PROG)
|
||||
|
||||
rtems:
|
||||
$(CC) -c $(CFLAGS) -DEMBEDDED $(SRCS) compat_rtems.c
|
||||
$(AR) -r lib$(PROG).a *.o && ranlib lib$(PROG).a
|
||||
|
||||
#cl $(SRCS) compat_win32.c /c $(CL_FLAGS) /DEMBEDDED
|
||||
#lib *.obj /out:shttpd.lib
|
||||
|
||||
msvc:
|
||||
$(VC6)\bin\cl /I $(VC6)\include \
|
||||
$(SRCS) compat_win32.c standalone.c $(CL_FLAGS) \
|
||||
/link /out:$(PROG).exe /LIBPATH:$(VC6)\lib ws2_32.lib user32.lib
|
||||
|
||||
mingw:
|
||||
$(CC) -c $(CFLAGS) -DEMBEDDED $(SRCS) compat_win32.c
|
||||
$(AR) -r lib$(PROG).a *.o && ranlib lib$(PROG).a
|
||||
$(CC) $(CFLAGS) $(SRCS) compat_win32.c standalone.c \
|
||||
-o $(PROG) $(LIBS) -lws2_32 -lcomdlg32 -lcomctl32
|
||||
|
||||
man:
|
||||
cat shttpd.1 | tbl | groff -man -Tascii | col -b > shttpd.1.txt
|
||||
cat shttpd.1 | tbl | groff -man -Tascii | less
|
||||
|
||||
clean:
|
||||
rm -rf *.o *.core $(PROG) lib$(PROG).a
|
8
third-party/shttpd/Makefile.am
vendored
8
third-party/shttpd/Makefile.am
vendored
|
@ -1,16 +1,16 @@
|
|||
|
||||
# FIXME: build the compat_*.c files conditionally
|
||||
|
||||
noinst_LIBRARIES = libshttpd.a
|
||||
|
||||
AM_CPPFLAGS = -DEMBEDDED -DNDEBUG -DNO_CGI -DNO_SSI
|
||||
|
||||
libshttpd_a_SOURCES = \
|
||||
string.c shttpd.c log.c auth.c md5.c cgi.c config.c io_ssi.c \
|
||||
string.c shttpd.c log.c auth.c md5.c cgi.c config.c \
|
||||
io_file.c io_socket.c io_ssl.c io_emb.c io_dir.c io_cgi.c \
|
||||
compat_unix.c
|
||||
|
||||
noinst_HEADERS = \
|
||||
defs.h llist.h shttpd.h std_includes.h io.h md5.h ssl.h \
|
||||
compat_unix.h compat_win32.h compat_rtems.h config.h
|
||||
compat_unix.h compat_rtems.h config.h
|
||||
|
||||
extra_DIST = \
|
||||
README \
|
||||
|
|
442
third-party/shttpd/compat_win32.c
vendored
442
third-party/shttpd/compat_win32.c
vendored
|
@ -1,442 +0,0 @@
|
|||
/*
|
||||
* Copyright (c) 2004-2005 Sergey Lyubka <valenok@gmail.com>
|
||||
* All rights reserved
|
||||
*
|
||||
* "THE BEER-WARE LICENSE" (Revision 42):
|
||||
* Sergey Lyubka wrote this file. As long as you retain this notice you
|
||||
* can do whatever you want with this stuff. If we meet some day, and you think
|
||||
* this stuff is worth it, you can buy me a beer in return.
|
||||
*/
|
||||
|
||||
#include "defs.h"
|
||||
|
||||
static void
|
||||
fix_directory_separators(char *path)
|
||||
{
|
||||
for (; *path != '\0'; path++) {
|
||||
if (*path == '/')
|
||||
*path = '\\';
|
||||
if (*path == '\\')
|
||||
while (path[1] == '\\' || path[1] == '/')
|
||||
(void) memmove(path + 1,
|
||||
path + 2, strlen(path + 2) + 1);
|
||||
}
|
||||
}
|
||||
|
||||
static int
|
||||
protect_against_code_disclosure(const char *path)
|
||||
{
|
||||
WIN32_FIND_DATA data;
|
||||
HANDLE handle;
|
||||
const char *p;
|
||||
|
||||
/*
|
||||
* Protect against CGI code disclosure under Windows.
|
||||
* This is very nasty hole. Windows happily opens files with
|
||||
* some garbage in the end of file name. So fopen("a.cgi ", "r")
|
||||
* actually opens "a.cgi", and does not return an error! And since
|
||||
* "a.cgi " does not have valid CGI extension, this leads to
|
||||
* the CGI code disclosure.
|
||||
* To protect, here we delete all fishy characters from the
|
||||
* end of file name.
|
||||
*/
|
||||
|
||||
if ((handle = FindFirstFile(path, &data)) == INVALID_HANDLE_VALUE)
|
||||
return (FALSE);
|
||||
|
||||
FindClose(handle);
|
||||
|
||||
for (p = path + strlen(path); p > path && p[-1] != '\\';)
|
||||
p--;
|
||||
|
||||
if (!(data.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) &&
|
||||
strcmp(data.cFileName, p) != 0)
|
||||
return (FALSE);
|
||||
|
||||
return (TRUE);
|
||||
}
|
||||
|
||||
int
|
||||
my_open(const char *path, int flags, int mode)
|
||||
{
|
||||
char buf[FILENAME_MAX];
|
||||
wchar_t wbuf[FILENAME_MAX];
|
||||
|
||||
my_strlcpy(buf, path, sizeof(buf));
|
||||
fix_directory_separators(buf);
|
||||
MultiByteToWideChar(CP_UTF8, 0, buf, -1, wbuf, sizeof(wbuf));
|
||||
|
||||
if (protect_against_code_disclosure(buf) == FALSE)
|
||||
return (-1);
|
||||
|
||||
return (_wopen(wbuf, flags));
|
||||
}
|
||||
|
||||
int
|
||||
my_stat(const char *path, struct stat *stp)
|
||||
{
|
||||
char buf[FILENAME_MAX], *p;
|
||||
wchar_t wbuf[FILENAME_MAX];
|
||||
|
||||
my_strlcpy(buf, path, sizeof(buf));
|
||||
fix_directory_separators(buf);
|
||||
|
||||
p = buf + strlen(buf) - 1;
|
||||
while (p > buf && *p == '\\' && p[-1] != ':')
|
||||
*p-- = '\0';
|
||||
|
||||
MultiByteToWideChar(CP_UTF8, 0, buf, -1, wbuf, sizeof(wbuf));
|
||||
|
||||
return (_wstat(wbuf, (struct _stat *) stp));
|
||||
}
|
||||
|
||||
int
|
||||
my_remove(const char *path)
|
||||
{
|
||||
char buf[FILENAME_MAX];
|
||||
wchar_t wbuf[FILENAME_MAX];
|
||||
|
||||
my_strlcpy(buf, path, sizeof(buf));
|
||||
fix_directory_separators(buf);
|
||||
|
||||
MultiByteToWideChar(CP_UTF8, 0, buf, -1, wbuf, sizeof(wbuf));
|
||||
|
||||
return (_wremove(wbuf));
|
||||
}
|
||||
|
||||
int
|
||||
my_rename(const char *path1, const char *path2)
|
||||
{
|
||||
char buf1[FILENAME_MAX];
|
||||
char buf2[FILENAME_MAX];
|
||||
wchar_t wbuf1[FILENAME_MAX];
|
||||
wchar_t wbuf2[FILENAME_MAX];
|
||||
|
||||
my_strlcpy(buf1, path1, sizeof(buf1));
|
||||
my_strlcpy(buf2, path2, sizeof(buf2));
|
||||
fix_directory_separators(buf1);
|
||||
fix_directory_separators(buf2);
|
||||
|
||||
MultiByteToWideChar(CP_UTF8, 0, buf1, -1, wbuf1, sizeof(wbuf1));
|
||||
MultiByteToWideChar(CP_UTF8, 0, buf2, -1, wbuf2, sizeof(wbuf2));
|
||||
|
||||
return (_wrename(wbuf1, wbuf2));
|
||||
}
|
||||
|
||||
int
|
||||
my_mkdir(const char *path, int mode)
|
||||
{
|
||||
char buf[FILENAME_MAX];
|
||||
wchar_t wbuf[FILENAME_MAX];
|
||||
|
||||
my_strlcpy(buf, path, sizeof(buf));
|
||||
fix_directory_separators(buf);
|
||||
|
||||
MultiByteToWideChar(CP_UTF8, 0, buf, -1, wbuf, sizeof(wbuf));
|
||||
|
||||
return (_wmkdir(wbuf));
|
||||
}
|
||||
|
||||
static char *
|
||||
wide_to_utf8(const wchar_t *str)
|
||||
{
|
||||
char *buf = NULL;
|
||||
if (str) {
|
||||
int nchar = WideCharToMultiByte(CP_UTF8, 0, str, -1, NULL, 0, NULL, NULL);
|
||||
if (nchar > 0) {
|
||||
buf = malloc(nchar);
|
||||
if (!buf)
|
||||
errno = ENOMEM;
|
||||
else if (!WideCharToMultiByte(CP_UTF8, 0, str, -1, buf, nchar, NULL, NULL)) {
|
||||
free(buf);
|
||||
buf = NULL;
|
||||
errno = EINVAL;
|
||||
}
|
||||
} else
|
||||
errno = EINVAL;
|
||||
} else
|
||||
errno = EINVAL;
|
||||
return buf;
|
||||
}
|
||||
|
||||
char *
|
||||
my_getcwd(char *buffer, int maxlen)
|
||||
{
|
||||
char *result = NULL;
|
||||
wchar_t *wbuffer, *wresult;
|
||||
|
||||
if (buffer) {
|
||||
/* User-supplied buffer */
|
||||
wbuffer = malloc(maxlen * sizeof(wchar_t));
|
||||
if (wbuffer == NULL)
|
||||
return NULL;
|
||||
} else
|
||||
/* Dynamically allocated buffer */
|
||||
wbuffer = NULL;
|
||||
wresult = _wgetcwd(wbuffer, maxlen);
|
||||
if (wresult) {
|
||||
int err = errno;
|
||||
if (buffer) {
|
||||
/* User-supplied buffer */
|
||||
int n = WideCharToMultiByte(CP_UTF8, 0, wresult, -1, buffer, maxlen, NULL, NULL);
|
||||
if (n == 0)
|
||||
err = ERANGE;
|
||||
free(wbuffer);
|
||||
result = buffer;
|
||||
} else {
|
||||
/* Buffer allocated by _wgetcwd() */
|
||||
result = wide_to_utf8(wresult);
|
||||
err = errno;
|
||||
free(wresult);
|
||||
}
|
||||
errno = err;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
DIR *
|
||||
opendir(const char *name)
|
||||
{
|
||||
DIR *dir = NULL;
|
||||
char path[FILENAME_MAX];
|
||||
wchar_t wpath[FILENAME_MAX];
|
||||
|
||||
if (name == NULL || name[0] == '\0') {
|
||||
errno = EINVAL;
|
||||
} else if ((dir = malloc(sizeof(*dir))) == NULL) {
|
||||
errno = ENOMEM;
|
||||
} else {
|
||||
my_snprintf(path, sizeof(path), "%s/*", name);
|
||||
fix_directory_separators(path);
|
||||
MultiByteToWideChar(CP_UTF8, 0, path, -1, wpath, sizeof(wpath));
|
||||
dir->handle = FindFirstFileW(wpath, &dir->info);
|
||||
|
||||
if (dir->handle != INVALID_HANDLE_VALUE) {
|
||||
dir->result.d_name[0] = '\0';
|
||||
} else {
|
||||
free(dir);
|
||||
dir = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
return (dir);
|
||||
}
|
||||
|
||||
int
|
||||
closedir(DIR *dir)
|
||||
{
|
||||
int result = -1;
|
||||
|
||||
if (dir != NULL) {
|
||||
if (dir->handle != INVALID_HANDLE_VALUE)
|
||||
result = FindClose(dir->handle) ? 0 : -1;
|
||||
|
||||
free(dir);
|
||||
}
|
||||
|
||||
if (result == -1)
|
||||
errno = EBADF;
|
||||
|
||||
return (result);
|
||||
}
|
||||
|
||||
struct dirent *
|
||||
readdir(DIR *dir)
|
||||
{
|
||||
struct dirent *result = 0;
|
||||
|
||||
if (dir && dir->handle != INVALID_HANDLE_VALUE) {
|
||||
if(!dir->result.d_name ||
|
||||
FindNextFileW(dir->handle, &dir->info)) {
|
||||
result = &dir->result;
|
||||
|
||||
WideCharToMultiByte(CP_UTF8, 0, dir->info.cFileName,
|
||||
-1, result->d_name,
|
||||
sizeof(result->d_name), NULL, NULL);
|
||||
}
|
||||
} else {
|
||||
errno = EBADF;
|
||||
}
|
||||
|
||||
return (result);
|
||||
}
|
||||
|
||||
int
|
||||
set_non_blocking_mode(int fd)
|
||||
{
|
||||
unsigned long on = 1;
|
||||
|
||||
return (ioctlsocket(fd, FIONBIO, &on));
|
||||
}
|
||||
|
||||
void
|
||||
set_close_on_exec(int fd)
|
||||
{
|
||||
fd = 0; /* Do nothing. There is no FD_CLOEXEC on Windows */
|
||||
}
|
||||
|
||||
#if !defined(NO_CGI)
|
||||
|
||||
struct threadparam {
|
||||
SOCKET s;
|
||||
HANDLE hPipe;
|
||||
big_int_t content_len;
|
||||
};
|
||||
|
||||
/*
|
||||
* Thread function that reads POST data from the socket pair
|
||||
* and writes it to the CGI process.
|
||||
*/
|
||||
static void//DWORD WINAPI
|
||||
stdoutput(void *arg)
|
||||
{
|
||||
struct threadparam *tp = arg;
|
||||
int n, sent, stop = 0;
|
||||
big_int_t total = 0;
|
||||
DWORD k;
|
||||
char buf[BUFSIZ];
|
||||
size_t max_recv;
|
||||
|
||||
max_recv = min(sizeof(buf), tp->content_len - total);
|
||||
while (!stop && max_recv > 0 && (n = recv(tp->s, buf, max_recv, 0)) > 0) {
|
||||
for (sent = 0; !stop && sent < n; sent += k)
|
||||
if (!WriteFile(tp->hPipe, buf + sent, n - sent, &k, 0))
|
||||
stop++;
|
||||
total += n;
|
||||
max_recv = min(sizeof(buf), tp->content_len - total);
|
||||
}
|
||||
|
||||
CloseHandle(tp->hPipe); /* Suppose we have POSTed everything */
|
||||
free(tp);
|
||||
}
|
||||
|
||||
/*
|
||||
* Thread function that reads CGI output and pushes it to the socket pair.
|
||||
*/
|
||||
static void
|
||||
stdinput(void *arg)
|
||||
{
|
||||
struct threadparam *tp = arg;
|
||||
static int ntotal;
|
||||
int k, stop = 0;
|
||||
DWORD n, sent;
|
||||
char buf[BUFSIZ];
|
||||
|
||||
while (!stop && ReadFile(tp->hPipe, buf, sizeof(buf), &n, NULL)) {
|
||||
ntotal += n;
|
||||
for (sent = 0; !stop && sent < n; sent += k)
|
||||
if ((k = send(tp->s, buf + sent, n - sent, 0)) <= 0)
|
||||
stop++;
|
||||
}
|
||||
CloseHandle(tp->hPipe);
|
||||
|
||||
/*
|
||||
* Windows is a piece of crap. When this thread closes its end
|
||||
* of the socket pair, the other end (get_cgi() function) may loose
|
||||
* some data. I presume, this happens if get_cgi() is not fast enough,
|
||||
* and the data written by this end does not "push-ed" to the other
|
||||
* end socket buffer. So after closesocket() the remaining data is
|
||||
* gone. If I put shutdown() before closesocket(), that seems to
|
||||
* fix the problem, but I am not sure this is the right fix.
|
||||
* XXX (submitted by James Marshall) we do not do shutdown() on UNIX.
|
||||
* If fork() is called from user callback, shutdown() messes up things.
|
||||
*/
|
||||
shutdown(tp->s, 2);
|
||||
|
||||
closesocket(tp->s);
|
||||
free(tp);
|
||||
|
||||
_endthread();
|
||||
}
|
||||
|
||||
static void
|
||||
spawn_stdio_thread(int sock, HANDLE hPipe, void (*func)(void *),
|
||||
big_int_t content_len)
|
||||
{
|
||||
struct threadparam *tp;
|
||||
DWORD tid;
|
||||
|
||||
tp = malloc(sizeof(*tp));
|
||||
assert(tp != NULL);
|
||||
|
||||
tp->s = sock;
|
||||
tp->hPipe = hPipe;
|
||||
tp->content_len = content_len;
|
||||
_beginthread(func, 0, tp);
|
||||
}
|
||||
|
||||
int
|
||||
spawn_process(struct conn *c, const char *prog, char *envblk,
|
||||
char *envp[], int sock, const char *dir)
|
||||
{
|
||||
HANDLE a[2], b[2], h[2], me;
|
||||
DWORD flags;
|
||||
char *p, cmdline[FILENAME_MAX], line[FILENAME_MAX];
|
||||
FILE *fp;
|
||||
STARTUPINFOA si;
|
||||
PROCESS_INFORMATION pi;
|
||||
|
||||
me = GetCurrentProcess();
|
||||
flags = DUPLICATE_CLOSE_SOURCE | DUPLICATE_SAME_ACCESS;
|
||||
|
||||
/* FIXME add error checking code here */
|
||||
CreatePipe(&a[0], &a[1], NULL, 0);
|
||||
CreatePipe(&b[0], &b[1], NULL, 0);
|
||||
DuplicateHandle(me, a[0], me, &h[0], 0, TRUE, flags);
|
||||
DuplicateHandle(me, b[1], me, &h[1], 0, TRUE, flags);
|
||||
|
||||
(void) memset(&si, 0, sizeof(si));
|
||||
(void) memset(&pi, 0, sizeof(pi));
|
||||
|
||||
/* XXX redirect CGI errors to the error log file */
|
||||
si.cb = sizeof(si);
|
||||
si.dwFlags = STARTF_USESTDHANDLES | STARTF_USESHOWWINDOW;
|
||||
si.wShowWindow = SW_HIDE;
|
||||
si.hStdOutput = si.hStdError = h[1];
|
||||
si.hStdInput = h[0];
|
||||
|
||||
/* If CGI file is a script, try to read the interpreter line */
|
||||
if (c->ctx->options[OPT_CGI_INTERPRETER] == NULL) {
|
||||
if ((fp = fopen(prog, "r")) != NULL) {
|
||||
(void) fgets(line, sizeof(line), fp);
|
||||
if (memcmp(line, "#!", 2) != 0)
|
||||
line[2] = '\0';
|
||||
/* Trim whitespaces from interpreter name */
|
||||
for (p = &line[strlen(line) - 1]; p > line &&
|
||||
isspace(*p); p--)
|
||||
*p = '\0';
|
||||
(void) fclose(fp);
|
||||
}
|
||||
(void) my_snprintf(cmdline, sizeof(cmdline), "%s%s%s",
|
||||
line + 2, line[2] == '\0' ? "" : " ", prog);
|
||||
} else {
|
||||
(void) my_snprintf(cmdline, sizeof(cmdline), "%s %s",
|
||||
c->ctx->options[OPT_CGI_INTERPRETER], prog);
|
||||
}
|
||||
|
||||
(void) my_snprintf(line, sizeof(line), "%s", dir);
|
||||
fix_directory_separators(line);
|
||||
fix_directory_separators(cmdline);
|
||||
|
||||
/*
|
||||
* Spawn reader & writer threads before we create CGI process.
|
||||
* Otherwise CGI process may die too quickly, loosing the data
|
||||
*/
|
||||
spawn_stdio_thread(sock, b[0], stdinput, 0);
|
||||
spawn_stdio_thread(sock, a[1], stdoutput, c->rem.content_len);
|
||||
|
||||
if (CreateProcessA(NULL, cmdline, NULL, NULL, TRUE,
|
||||
CREATE_NEW_PROCESS_GROUP, envblk, line, &si, &pi) == 0) {
|
||||
elog(E_LOG, c,"redirect: CreateProcess(%s): %d",cmdline,ERRNO);
|
||||
return (-1);
|
||||
} else {
|
||||
CloseHandle(h[0]);
|
||||
CloseHandle(h[1]);
|
||||
CloseHandle(pi.hThread);
|
||||
CloseHandle(pi.hProcess);
|
||||
}
|
||||
|
||||
return (0);
|
||||
}
|
||||
|
||||
#endif /* !NO_CGI */
|
83
third-party/shttpd/compat_win32.h
vendored
83
third-party/shttpd/compat_win32.h
vendored
|
@ -1,83 +0,0 @@
|
|||
/*
|
||||
* Copyright (c) 2004-2007 Sergey Lyubka <valenok@gmail.com>
|
||||
* All rights reserved
|
||||
*
|
||||
* "THE BEER-WARE LICENSE" (Revision 42):
|
||||
* Sergey Lyubka wrote this file. As long as you retain this notice you
|
||||
* can do whatever you want with this stuff. If we meet some day, and you think
|
||||
* this stuff is worth it, you can buy me a beer in return.
|
||||
*/
|
||||
|
||||
/* Tip from Justin Maximilian, suppress errors from winsock2.h */
|
||||
#define _WINSOCKAPI_
|
||||
|
||||
#include <windows.h>
|
||||
#include <winsock2.h>
|
||||
#include <commctrl.h>
|
||||
#include <winnls.h>
|
||||
#include <shlobj.h>
|
||||
#include <shellapi.h>
|
||||
|
||||
#ifndef _WIN32_WCE
|
||||
|
||||
#include <process.h>
|
||||
#include <direct.h>
|
||||
#include <io.h>
|
||||
|
||||
#else /* _WIN32_WCE */
|
||||
|
||||
/* Windows CE-specific definitions */
|
||||
#define NO_CGI /* WinCE has no pipes */
|
||||
#define NO_GUI /* temporarily until it is fixed */
|
||||
#pragma comment(lib,"ws2")
|
||||
/* WinCE has both Unicode and ANSI versions of GetProcAddress */
|
||||
#undef GetProcAddress
|
||||
#define GetProcAddress GetProcAddressA
|
||||
#include "compat_wince.h"
|
||||
|
||||
#endif /* _WIN32_WCE */
|
||||
|
||||
#define ERRNO GetLastError()
|
||||
#define NO_SOCKLEN_T
|
||||
#define SSL_LIB L"libssl32.dll"
|
||||
#define DIRSEP '\\'
|
||||
#define IS_DIRSEP_CHAR(c) ((c) == '/' || (c) == '\\')
|
||||
#define O_NONBLOCK 0
|
||||
#define EWOULDBLOCK WSAEWOULDBLOCK
|
||||
#define snprintf _snprintf
|
||||
#define vsnprintf _vsnprintf
|
||||
#define mkdir(x,y) _mkdir(x)
|
||||
#define popen(x,y) _popen(x, y)
|
||||
#define pclose(x) _pclose(x)
|
||||
#define dlopen(x,y) LoadLibraryW(x)
|
||||
#define dlsym(x,y) (void *) GetProcAddress(x,y)
|
||||
#define _POSIX_
|
||||
|
||||
#ifdef __LCC__
|
||||
#include <stdint.h>
|
||||
#endif /* __LCC__ */
|
||||
|
||||
#ifdef _MSC_VER /* MinGW already has these */
|
||||
typedef unsigned int uint32_t;
|
||||
typedef unsigned short uint16_t;
|
||||
typedef __int64 uint64_t;
|
||||
#define S_ISDIR(x) ((x) & _S_IFDIR)
|
||||
#endif /* _MSC_VER */
|
||||
|
||||
/*
|
||||
* POSIX dirent interface
|
||||
*/
|
||||
struct dirent {
|
||||
char d_name[FILENAME_MAX];
|
||||
};
|
||||
|
||||
typedef struct DIR {
|
||||
HANDLE handle;
|
||||
WIN32_FIND_DATAW info;
|
||||
struct dirent result;
|
||||
char *name;
|
||||
} DIR;
|
||||
|
||||
extern DIR *opendir(const char *name);
|
||||
extern int closedir(DIR *dir);
|
||||
extern struct dirent *readdir(DIR *dir);
|
1593
third-party/shttpd/compat_wince.c
vendored
1593
third-party/shttpd/compat_wince.c
vendored
File diff suppressed because it is too large
Load diff
145
third-party/shttpd/compat_wince.h
vendored
145
third-party/shttpd/compat_wince.h
vendored
|
@ -1,145 +0,0 @@
|
|||
|
||||
#ifndef INCLUDE_WINCE_COMPAT_H
|
||||
#define INCLUDE_WINCE_COMPAT_H
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/*** ANSI C library ***/
|
||||
|
||||
/* Missing ANSI C definitions */
|
||||
|
||||
#define BUFSIZ 4096
|
||||
|
||||
#define ENOMEM ERROR_NOT_ENOUGH_MEMORY
|
||||
#define EBADF ERROR_INVALID_HANDLE
|
||||
#define EINVAL ERROR_INVALID_PARAMETER
|
||||
#define ENOENT ERROR_FILE_NOT_FOUND
|
||||
#define ERANGE ERROR_INSUFFICIENT_BUFFER
|
||||
#define EINTR WSAEINTR
|
||||
|
||||
/*
|
||||
* Because we need a per-thread errno, we define a function
|
||||
* pointer that we can call to return a pointer to the errno
|
||||
* for the current thread. Then we define a macro for errno
|
||||
* that dereferences this function's result.
|
||||
*
|
||||
* This makes it syntactically just like the "real" errno.
|
||||
*
|
||||
* Using a function pointer allows us to use a very fast
|
||||
* function when there are no threads running and a slower
|
||||
* function when there are multiple threads running.
|
||||
*/
|
||||
void __WinCE_Errno_New_Thread(int *Errno_Pointer);
|
||||
void __WinCE_Errno_Thread_Exit(void);
|
||||
extern int *(*__WinCE_Errno_Pointer_Function)(void);
|
||||
|
||||
#define errno (*(*__WinCE_Errno_Pointer_Function)())
|
||||
|
||||
char *strerror(int errnum);
|
||||
|
||||
struct tm {
|
||||
int tm_sec; /* seconds after the minute - [0,59] */
|
||||
int tm_min; /* minutes after the hour - [0,59] */
|
||||
int tm_hour; /* hours since midnight - [0,23] */
|
||||
int tm_mday; /* day of the month - [1,31] */
|
||||
int tm_mon; /* months since January - [0,11] */
|
||||
int tm_year; /* years since 1900 */
|
||||
int tm_wday; /* days since Sunday - [0,6] */
|
||||
int tm_yday; /* days since January 1 - [0,365] */
|
||||
int tm_isdst; /* daylight savings time flag */
|
||||
};
|
||||
|
||||
struct tm *gmtime(const time_t *TimeP); /* for future use */
|
||||
struct tm *localtime(const time_t *TimeP);
|
||||
time_t mktime(struct tm *tm);
|
||||
time_t time(time_t *TimeP);
|
||||
|
||||
size_t strftime(char *s, size_t maxsize, const char *format, const struct tm *tim_p);
|
||||
|
||||
int _wrename(const wchar_t *oldname, const wchar_t *newname);
|
||||
int _wremove(const wchar_t *filename);
|
||||
|
||||
/* Environment variables are not supported */
|
||||
#define getenv(x) (NULL)
|
||||
|
||||
/* Redefine fileno so that it returns an integer */
|
||||
#undef fileno
|
||||
#define fileno(f) (int)_fileno(f)
|
||||
|
||||
/* Signals are not supported */
|
||||
#define signal(num, handler) (0)
|
||||
#define SIGTERM 0
|
||||
#define SIGINT 0
|
||||
|
||||
|
||||
/*** POSIX API ***/
|
||||
|
||||
/* Missing POSIX definitions */
|
||||
|
||||
#define FILENAME_MAX MAX_PATH
|
||||
|
||||
struct _stat {
|
||||
unsigned long st_size;
|
||||
unsigned long st_ino;
|
||||
int st_mode;
|
||||
unsigned long st_atime;
|
||||
unsigned long st_mtime;
|
||||
unsigned long st_ctime;
|
||||
unsigned short st_dev;
|
||||
unsigned short st_nlink;
|
||||
unsigned short st_uid;
|
||||
unsigned short st_gid;
|
||||
};
|
||||
|
||||
#define S_IFMT 0170000
|
||||
#define S_IFDIR 0040000
|
||||
#define S_IFREG 0100000
|
||||
#define S_IEXEC 0000100
|
||||
#define S_IWRITE 0000200
|
||||
#define S_IREAD 0000400
|
||||
|
||||
#define _S_IFDIR S_IFDIR /* MSVCRT compatibilit */
|
||||
|
||||
int _fstat(int handle, struct _stat *buffer);
|
||||
int _wstat(const wchar_t *path, struct _stat *buffer);
|
||||
|
||||
#define stat _stat /* NOTE: applies to _stat() and also struct _stat */
|
||||
#define fstat _fstat
|
||||
|
||||
#define O_RDWR (1<<0)
|
||||
#define O_RDONLY (2<<0)
|
||||
#define O_WRONLY (3<<0)
|
||||
#define O_MODE_MASK (3<<0)
|
||||
#define O_TRUNC (1<<2)
|
||||
#define O_EXCL (1<<3)
|
||||
#define O_CREAT (1<<4)
|
||||
#define O_BINARY 0
|
||||
|
||||
int _wopen(const wchar_t *filename, int oflag, ...);
|
||||
int _close(int handle);
|
||||
int _write(int handle, const void *buffer, unsigned int count);
|
||||
int _read(int handle, void *buffer, unsigned int count);
|
||||
long _lseek(int handle, long offset, int origin);
|
||||
|
||||
#define close _close
|
||||
#define write _write
|
||||
#define read _read
|
||||
#define lseek _lseek
|
||||
|
||||
/* WinCE has only a Unicode version of this function */
|
||||
FILE *fdopen(int handle, const char *mode);
|
||||
|
||||
int _wmkdir(const wchar_t *dirname);
|
||||
|
||||
/* WinCE has no concept of current directory so we return a constant path */
|
||||
wchar_t *_wgetcwd(wchar_t *buffer, int maxlen);
|
||||
|
||||
#define freopen(path, mode, stream) assert(0)
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* INCLUDE_WINCE_COMPAT_H */
|
2
third-party/shttpd/config.c
vendored
2
third-party/shttpd/config.c
vendored
|
@ -296,7 +296,9 @@ struct shttpd_ctx *shttpd_init(void)
|
|||
LL_INIT(&ctx->registered_uris);
|
||||
LL_INIT(&ctx->error_handlers);
|
||||
LL_INIT(&ctx->acl);
|
||||
#if !defined(NO_SSI)
|
||||
LL_INIT(&ctx->ssi_funcs);
|
||||
#endif
|
||||
LL_INIT(&ctx->listeners);
|
||||
|
||||
#ifdef _WIN32
|
||||
|
|
3
third-party/shttpd/config.h
vendored
3
third-party/shttpd/config.h
vendored
|
@ -11,10 +11,11 @@
|
|||
#ifndef CONFIG_HEADER_DEFINED
|
||||
#define CONFIG_HEADER_DEFINED
|
||||
|
||||
#undef VERSION
|
||||
#define VERSION "1.39" /* Version */
|
||||
#define CONFIG_FILE "shttpd.conf" /* Configuration file */
|
||||
#define HTPASSWD ".htpasswd" /* Passwords file name */
|
||||
#define URI_MAX 16384 /* Default max request size */
|
||||
#define URI_MAX 65536 /* Default max request size */
|
||||
#define LISTENING_PORTS "80" /* Default listening ports */
|
||||
#define INDEX_FILES "index.html,index.htm,index.php,index.cgi"
|
||||
#define CGI_EXT "cgi,pl,php" /* Default CGI extensions */
|
||||
|
|
4
third-party/shttpd/defs.h
vendored
4
third-party/shttpd/defs.h
vendored
|
@ -241,7 +241,9 @@ struct shttpd_ctx {
|
|||
struct llhead registered_uris;/* User urls */
|
||||
struct llhead error_handlers; /* Embedded error handlers */
|
||||
struct llhead acl; /* Access control list */
|
||||
#if !defined(NO_SSI)
|
||||
struct llhead ssi_funcs; /* SSI callback functions */
|
||||
#endif
|
||||
struct llhead listeners; /* Listening sockets */
|
||||
|
||||
FILE *access_log; /* Access log stream */
|
||||
|
@ -358,8 +360,10 @@ extern void ssl_handshake(struct stream *stream);
|
|||
extern void setup_embedded_stream(struct conn *, union variant, void *);
|
||||
extern struct registered_uri *is_registered_uri(struct shttpd_ctx *,
|
||||
const char *uri);
|
||||
#if !defined(NO_SSI)
|
||||
extern void do_ssi(struct conn *);
|
||||
extern void ssi_func_destructor(struct llhead *lp);
|
||||
#endif
|
||||
|
||||
/*
|
||||
* auth.c
|
||||
|
|
482
third-party/shttpd/io_ssi.c
vendored
482
third-party/shttpd/io_ssi.c
vendored
|
@ -1,482 +0,0 @@
|
|||
/*
|
||||
* Copyright (c) 2006,2007 Steven Johnson <sjohnson@sakuraindustries.com>
|
||||
* Copyright (c) 2007 Sergey Lyubka <valenok@gmail.com>
|
||||
* All rights reserved
|
||||
*
|
||||
* "THE BEER-WARE LICENSE" (Revision 42):
|
||||
* Sergey Lyubka wrote this file. As long as you retain this notice you
|
||||
* can do whatever you want with this stuff. If we meet some day, and you think
|
||||
* this stuff is worth it, you can buy me a beer in return.
|
||||
*/
|
||||
|
||||
#include "defs.h"
|
||||
|
||||
#define CMDBUFSIZ 512 /* SSI command buffer size */
|
||||
#define NEST_MAX 6 /* Maximum nesting level */
|
||||
|
||||
struct ssi_func {
|
||||
struct llhead link;
|
||||
void *user_data;
|
||||
char *name;
|
||||
shttpd_callback_t func;
|
||||
};
|
||||
|
||||
struct ssi_inc {
|
||||
int state; /* Buffering state */
|
||||
int cond; /* Conditional state */
|
||||
FILE *fp; /* Icluded file stream */
|
||||
char buf[CMDBUFSIZ]; /* SSI command buffer */
|
||||
size_t nbuf; /* Bytes in a command buffer */
|
||||
FILE *pipe; /* #exec stream */
|
||||
struct ssi_func func; /* #call function */
|
||||
};
|
||||
|
||||
struct ssi {
|
||||
struct conn *conn; /* Connection we belong to */
|
||||
int nest; /* Current nesting level */
|
||||
struct ssi_inc incs[NEST_MAX]; /* Nested includes */
|
||||
};
|
||||
|
||||
enum { SSI_PASS, SSI_BUF, SSI_EXEC, SSI_CALL };
|
||||
enum { SSI_GO, SSI_STOP }; /* Conditional states */
|
||||
|
||||
static const struct vec st = {"<!--#", 5};
|
||||
|
||||
void
|
||||
shttpd_register_ssi_func(struct shttpd_ctx *ctx, const char *name,
|
||||
shttpd_callback_t func, void *user_data)
|
||||
{
|
||||
struct ssi_func *e;
|
||||
|
||||
if ((e = malloc(sizeof(*e))) != NULL) {
|
||||
e->name = my_strdup(name);
|
||||
e->func = func;
|
||||
e->user_data = user_data;
|
||||
LL_TAIL(&ctx->ssi_funcs, &e->link);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
ssi_func_destructor(struct llhead *lp)
|
||||
{
|
||||
struct ssi_func *e = LL_ENTRY(lp, struct ssi_func, link);
|
||||
|
||||
free(e->name);
|
||||
free(e);
|
||||
}
|
||||
|
||||
static const struct ssi_func *
|
||||
find_ssi_func(struct ssi *ssi, const char *name)
|
||||
{
|
||||
struct ssi_func *e;
|
||||
struct llhead *lp;
|
||||
|
||||
LL_FOREACH(&ssi->conn->ctx->ssi_funcs, lp) {
|
||||
e = LL_ENTRY(lp, struct ssi_func, link);
|
||||
if (!strcmp(name, e->name))
|
||||
return (e);
|
||||
}
|
||||
|
||||
return (NULL);
|
||||
}
|
||||
|
||||
static void
|
||||
call(struct ssi *ssi, const char *name,
|
||||
struct shttpd_arg *arg, char *buf, int len)
|
||||
{
|
||||
const struct ssi_func *ssi_func;
|
||||
|
||||
(void) memset(arg, 0, sizeof(*arg));
|
||||
|
||||
/*
|
||||
* SSI function may be called with parameters. These parameters
|
||||
* are passed as arg->in.buf, arg->in.len vector.
|
||||
*/
|
||||
arg->in.buf = strchr(name, ' ');
|
||||
if (arg->in.buf != NULL) {
|
||||
*arg->in.buf++ = '\0';
|
||||
arg->in.len = strlen(arg->in.buf);
|
||||
}
|
||||
|
||||
if ((ssi_func = find_ssi_func(ssi, name)) != NULL) {
|
||||
arg->priv = ssi->conn;
|
||||
arg->user_data = ssi_func->user_data;
|
||||
arg->out.buf = buf;
|
||||
arg->out.len = len;
|
||||
ssi_func->func(arg);
|
||||
}
|
||||
}
|
||||
|
||||
static int
|
||||
evaluate(struct ssi *ssi, const char *name)
|
||||
{
|
||||
struct shttpd_arg arg;
|
||||
|
||||
call(ssi, name, &arg, NULL, 0);
|
||||
|
||||
return (arg.flags & SHTTPD_SSI_EVAL_TRUE);
|
||||
}
|
||||
|
||||
static void
|
||||
pass(struct ssi_inc *inc, void *buf, int *n)
|
||||
{
|
||||
if (inc->cond == SSI_GO) {
|
||||
(void) memcpy(buf, inc->buf, inc->nbuf);
|
||||
(*n) += inc->nbuf;
|
||||
}
|
||||
inc->nbuf = 0;
|
||||
inc->state = SSI_PASS;
|
||||
}
|
||||
|
||||
static int
|
||||
get_path(struct conn *conn, const char *src,
|
||||
int src_len, char *dst, int dst_len)
|
||||
{
|
||||
static struct vec accepted[] = {
|
||||
{"\"", 1}, /* Relative to webserver CWD */
|
||||
{"file=\"", 6}, /* Relative to current URI */
|
||||
{"virtual=\"", 9}, /* Relative to document root */
|
||||
{NULL, 0},
|
||||
};
|
||||
struct vec *vec;
|
||||
const char *p, *root = conn->ctx->options[OPT_ROOT];
|
||||
int len;
|
||||
|
||||
for (vec = accepted; vec->len > 0; vec++)
|
||||
if (src_len > vec->len && !memcmp(src, vec->ptr, vec->len)) {
|
||||
src += vec->len;
|
||||
src_len -= vec->len;
|
||||
if ((p = memchr(src, '"', src_len)) == NULL)
|
||||
break;
|
||||
if (vec->len == 6) {
|
||||
len = my_snprintf(dst, dst_len, "%s%c%s",
|
||||
root, DIRSEP, conn->uri);
|
||||
while (len > 0 && dst[len] != '/')
|
||||
len--;
|
||||
dst += len;
|
||||
dst_len -= len;
|
||||
} else if (vec->len == 9) {
|
||||
len = my_snprintf(dst, dst_len, "%s%c",
|
||||
root, DIRSEP);
|
||||
dst += len;
|
||||
dst_len -= len;
|
||||
}
|
||||
url_decode(src, p - src, dst, dst_len);
|
||||
return (1);
|
||||
}
|
||||
|
||||
return (0);
|
||||
}
|
||||
|
||||
static void
|
||||
do_include(struct ssi *ssi)
|
||||
{
|
||||
struct ssi_inc *inc = ssi->incs + ssi->nest;
|
||||
char buf[FILENAME_MAX];
|
||||
FILE *fp;
|
||||
|
||||
assert(inc->nbuf >= 13);
|
||||
|
||||
if (inc->cond == SSI_STOP) {
|
||||
/* Do nothing - conditional FALSE */
|
||||
} else if (ssi->nest >= (int) NELEMS(ssi->incs) - 1) {
|
||||
elog(E_LOG, ssi->conn,
|
||||
"ssi: #include: maximum nested level reached");
|
||||
} else if (!get_path(ssi->conn,
|
||||
inc->buf + 13, inc->nbuf - 13, buf, sizeof(buf))) {
|
||||
elog(E_LOG, ssi->conn, "ssi: bad #include: [%.*s]",
|
||||
inc->nbuf, inc->buf);
|
||||
} else if ((fp = fopen(buf, "r")) == NULL) {
|
||||
elog(E_LOG, ssi->conn,
|
||||
"ssi: fopen(%s): %s", buf, strerror(errno));
|
||||
} else {
|
||||
ssi->nest++;
|
||||
ssi->incs[ssi->nest].fp = fp;
|
||||
ssi->incs[ssi->nest].nbuf = 0;
|
||||
ssi->incs[ssi->nest].cond = SSI_GO;
|
||||
}
|
||||
}
|
||||
|
||||
static char *
|
||||
trim_spaces(struct ssi_inc *inc)
|
||||
{
|
||||
char *p = inc->buf + inc->nbuf - 2;
|
||||
|
||||
/* Trim spaces from the right */
|
||||
*p-- = '\0';
|
||||
while (isspace(* (unsigned char *) p))
|
||||
*p-- = '\0';
|
||||
|
||||
/* Shift pointer to the start of attributes */
|
||||
for (p = inc->buf; !isspace(* (unsigned char *) p); p++);
|
||||
while (*p && isspace(* (unsigned char *) p)) p++;
|
||||
|
||||
return (p);
|
||||
}
|
||||
|
||||
static void
|
||||
do_if(struct ssi *ssi)
|
||||
{
|
||||
struct ssi_inc *inc = ssi->incs + ssi->nest;
|
||||
char *name = trim_spaces(inc);
|
||||
|
||||
inc->cond = evaluate(ssi, name) ? SSI_GO : SSI_STOP;
|
||||
}
|
||||
|
||||
static void
|
||||
do_elif(struct ssi *ssi)
|
||||
{
|
||||
struct ssi_inc *inc = ssi->incs + ssi->nest;
|
||||
char *name = trim_spaces(inc);
|
||||
|
||||
if (inc->cond == SSI_STOP && evaluate(ssi, name))
|
||||
inc->cond = SSI_GO;
|
||||
else
|
||||
inc->cond = SSI_STOP;
|
||||
}
|
||||
static void
|
||||
do_endif(struct ssi *ssi)
|
||||
{
|
||||
ssi->incs[ssi->nest].cond = SSI_GO;
|
||||
}
|
||||
|
||||
static void
|
||||
do_else(struct ssi *ssi)
|
||||
{
|
||||
struct ssi_inc *inc = ssi->incs + ssi->nest;
|
||||
|
||||
inc->cond = inc->cond == SSI_GO ? SSI_STOP : SSI_GO;
|
||||
}
|
||||
|
||||
static void
|
||||
do_call2(struct ssi *ssi, char *buf, int len, int *n)
|
||||
{
|
||||
struct ssi_inc *inc = ssi->incs + ssi->nest;
|
||||
struct shttpd_arg arg;
|
||||
|
||||
call(ssi, inc->buf, &arg, buf, len);
|
||||
(*n) += arg.out.num_bytes;
|
||||
if (arg.flags & SHTTPD_END_OF_OUTPUT)
|
||||
inc->state = SSI_PASS;
|
||||
}
|
||||
|
||||
static void
|
||||
do_call(struct ssi *ssi, char *buf, int len, int *n)
|
||||
{
|
||||
struct ssi_inc *inc = ssi->incs + ssi->nest;
|
||||
char *name = trim_spaces(inc);
|
||||
|
||||
if (inc->cond == SSI_GO) {
|
||||
(void) memmove(inc->buf, name, strlen(name) + 1);
|
||||
inc->state = SSI_CALL;
|
||||
do_call2(ssi, buf, len, n);
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
do_exec2(struct ssi *ssi, char *buf, int len, int *n)
|
||||
{
|
||||
struct ssi_inc *inc = ssi->incs + ssi->nest;
|
||||
int i, ch;
|
||||
|
||||
for (i = 0; i < len; i++) {
|
||||
if ((ch = fgetc(inc->pipe)) == EOF) {
|
||||
inc->state = SSI_PASS;
|
||||
(void) pclose(inc->pipe);
|
||||
inc->pipe = NULL;
|
||||
break;
|
||||
}
|
||||
*buf++ = ch;
|
||||
(*n)++;
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
do_exec(struct ssi *ssi, char *buf, int len, int *n)
|
||||
{
|
||||
struct ssi_inc *inc = ssi->incs + ssi->nest;
|
||||
char cmd[sizeof(inc->buf)], *e, *p;
|
||||
|
||||
p = trim_spaces(inc);
|
||||
|
||||
if (inc->cond == SSI_STOP) {
|
||||
/* Do nothing - conditional FALSE */
|
||||
} else if (*p != '"' || (e = strchr(p + 1, '"')) == NULL) {
|
||||
elog(E_LOG, ssi->conn, "ssi: bad exec(%s)", p);
|
||||
} else if (!url_decode(p + 1, e - p - 1, cmd, sizeof(cmd))) {
|
||||
elog(E_LOG, ssi->conn, "ssi: cannot url_decode: exec(%s)", p);
|
||||
} else if ((inc->pipe = popen(cmd, "r")) == NULL) {
|
||||
elog(E_LOG, ssi->conn, "ssi: popen(%s)", cmd);
|
||||
} else {
|
||||
inc->state = SSI_EXEC;
|
||||
do_exec2(ssi, buf, len, n);
|
||||
}
|
||||
}
|
||||
|
||||
static const struct ssi_cmd {
|
||||
struct vec vec;
|
||||
void (*func)();
|
||||
} known_ssi_commands [] = {
|
||||
{{"include ", 8}, do_include },
|
||||
{{"if ", 3}, do_if },
|
||||
{{"elif ", 5}, do_elif },
|
||||
{{"else", 4}, do_else },
|
||||
{{"endif", 5}, do_endif },
|
||||
{{"call ", 5}, do_call },
|
||||
{{"exec ", 5}, do_exec },
|
||||
{{NULL, 0}, NULL }
|
||||
};
|
||||
|
||||
static void
|
||||
do_command(struct ssi *ssi, char *buf, size_t len, int *n)
|
||||
{
|
||||
struct ssi_inc *inc = ssi->incs + ssi->nest;
|
||||
const struct ssi_cmd *cmd;
|
||||
|
||||
assert(len > 0);
|
||||
assert(inc->nbuf <= len);
|
||||
inc->state = SSI_PASS;
|
||||
|
||||
for (cmd = known_ssi_commands; cmd->func != NULL; cmd++)
|
||||
if (inc->nbuf > (size_t) st.len + cmd->vec.len &&
|
||||
!memcmp(inc->buf + st.len, cmd->vec.ptr, cmd->vec.len)) {
|
||||
cmd->func(ssi, buf, len, n);
|
||||
break;
|
||||
}
|
||||
|
||||
if (cmd->func == NULL)
|
||||
pass(inc, buf, n);
|
||||
|
||||
inc->nbuf = 0;
|
||||
}
|
||||
|
||||
static int
|
||||
read_ssi(struct stream *stream, void *vbuf, size_t len)
|
||||
{
|
||||
struct ssi *ssi = stream->conn->ssi;
|
||||
struct ssi_inc *inc = ssi->incs + ssi->nest;
|
||||
char *buf = vbuf;
|
||||
int ch = EOF, n = 0;
|
||||
|
||||
again:
|
||||
|
||||
if (inc->state == SSI_CALL)
|
||||
do_call2(ssi, buf, len, &n);
|
||||
else if (inc->state == SSI_EXEC)
|
||||
do_exec2(ssi, buf, len, &n);
|
||||
|
||||
while (n + inc->nbuf < len && (ch = fgetc(inc->fp)) != EOF)
|
||||
|
||||
switch (inc->state) {
|
||||
|
||||
case SSI_PASS:
|
||||
if (ch == '<') {
|
||||
inc->nbuf = 0;
|
||||
inc->buf[inc->nbuf++] = ch;
|
||||
inc->state = SSI_BUF;
|
||||
} else if (inc->cond == SSI_GO) {
|
||||
buf[n++] = ch;
|
||||
}
|
||||
break;
|
||||
|
||||
/*
|
||||
* We are buffering whole SSI command, until closing "-->".
|
||||
* That means that when do_command() is called, we can rely
|
||||
* on that full command with arguments is buffered in and
|
||||
* there is no need for streaming.
|
||||
* Restrictions:
|
||||
* 1. The command must fit in CMDBUFSIZ
|
||||
* 2. HTML comments inside the command ? Not sure about this.
|
||||
*/
|
||||
case SSI_BUF:
|
||||
if (inc->nbuf >= sizeof(inc->buf) - 1) {
|
||||
pass(inc, buf + n, &n);
|
||||
} else if (ch == '>' &&
|
||||
!memcmp(inc->buf + inc->nbuf - 2, "--", 2)) {
|
||||
do_command(ssi, buf + n, len - n, &n);
|
||||
inc = ssi->incs + ssi->nest;
|
||||
} else {
|
||||
inc->buf[inc->nbuf++] = ch;
|
||||
|
||||
/* If not SSI tag, pass it */
|
||||
if (inc->nbuf <= (size_t) st.len &&
|
||||
memcmp(inc->buf, st.ptr, inc->nbuf) != 0)
|
||||
pass(inc, buf + n, &n);
|
||||
}
|
||||
break;
|
||||
|
||||
case SSI_EXEC:
|
||||
case SSI_CALL:
|
||||
break;
|
||||
|
||||
default:
|
||||
/* Never happens */
|
||||
abort();
|
||||
break;
|
||||
}
|
||||
|
||||
if (ssi->nest > 0 && n + inc->nbuf < len && ch == EOF) {
|
||||
(void) fclose(inc->fp);
|
||||
inc->fp = NULL;
|
||||
ssi->nest--;
|
||||
inc--;
|
||||
goto again;
|
||||
}
|
||||
|
||||
return (n);
|
||||
}
|
||||
|
||||
static void
|
||||
close_ssi(struct stream *stream)
|
||||
{
|
||||
struct ssi *ssi = stream->conn->ssi;
|
||||
size_t i;
|
||||
|
||||
for (i = 0; i < NELEMS(ssi->incs); i++) {
|
||||
if (ssi->incs[i].fp != NULL)
|
||||
(void) fclose(ssi->incs[i].fp);
|
||||
if (ssi->incs[i].pipe != NULL)
|
||||
(void) pclose(ssi->incs[i].pipe);
|
||||
}
|
||||
|
||||
free(ssi);
|
||||
}
|
||||
|
||||
void
|
||||
do_ssi(struct conn *c)
|
||||
{
|
||||
char date[64];
|
||||
struct ssi *ssi;
|
||||
|
||||
(void) strftime(date, sizeof(date), "%a, %d %b %Y %H:%M:%S GMT",
|
||||
localtime(¤t_time));
|
||||
|
||||
c->loc.io.head = c->loc.headers_len = my_snprintf(c->loc.io.buf,
|
||||
c->loc.io.size,
|
||||
"HTTP/1.1 200 OK\r\n"
|
||||
"Date: %s\r\n"
|
||||
"Content-Type: text/html\r\n"
|
||||
"Connection: close\r\n\r\n",
|
||||
date);
|
||||
|
||||
c->status = 200;
|
||||
c->loc.io_class = &io_ssi;
|
||||
c->loc.flags |= FLAG_R | FLAG_ALWAYS_READY;
|
||||
|
||||
if (c->method == METHOD_HEAD) {
|
||||
stop_stream(&c->loc);
|
||||
} else if ((ssi = calloc(1, sizeof(struct ssi))) == NULL) {
|
||||
send_server_error(c, 500, "Cannot allocate SSI descriptor");
|
||||
} else {
|
||||
ssi->incs[0].fp = fdopen(c->loc.chan.fd, "r");
|
||||
ssi->conn = c;
|
||||
c->ssi = ssi;
|
||||
}
|
||||
}
|
||||
|
||||
const struct io_class io_ssi = {
|
||||
"ssi",
|
||||
read_ssi,
|
||||
NULL,
|
||||
close_ssi
|
||||
};
|
2
third-party/shttpd/shttpd.c
vendored
2
third-party/shttpd/shttpd.c
vendored
|
@ -1205,7 +1205,9 @@ shttpd_fini(struct shttpd_ctx *ctx)
|
|||
free_list(&ctx->registered_uris, registered_uri_destructor);
|
||||
free_list(&ctx->acl, acl_destructor);
|
||||
free_list(&ctx->listeners, listener_destructor);
|
||||
#if !defined(NO_SSI)
|
||||
free_list(&ctx->ssi_funcs, ssi_func_destructor);
|
||||
#endif
|
||||
|
||||
for (i = 0; i < NELEMS(ctx->options); i++)
|
||||
if (ctx->options[i] != NULL)
|
||||
|
|
Loading…
Reference in a new issue