diff options
author | patacongo <patacongo@42af7a65-404d-4744-a932-0658087f49c3> | 2009-09-13 14:53:32 +0000 |
---|---|---|
committer | patacongo <patacongo@42af7a65-404d-4744-a932-0658087f49c3> | 2009-09-13 14:53:32 +0000 |
commit | 5abe9334aa6285784cc860385d6ae956d5f1a5d9 (patch) | |
tree | 3f032f233b676c9d2cba207637a592e6959a6dc9 /nuttx | |
parent | fda86dc1720d46a26badfc033efd6a2f25bbdff7 (diff) | |
download | px4-nuttx-5abe9334aa6285784cc860385d6ae956d5f1a5d9.tar.gz px4-nuttx-5abe9334aa6285784cc860385d6ae956d5f1a5d9.tar.bz2 px4-nuttx-5abe9334aa6285784cc860385d6ae956d5f1a5d9.zip |
move CGI logic to a separate file
git-svn-id: svn://svn.code.sf.net/p/nuttx/code/trunk@2044 42af7a65-404d-4744-a932-0658087f49c3
Diffstat (limited to 'nuttx')
-rw-r--r-- | nuttx/netutils/thttpd/Make.defs | 2 | ||||
-rw-r--r-- | nuttx/netutils/thttpd/fdwatch.c | 2 | ||||
-rw-r--r-- | nuttx/netutils/thttpd/libhttpd.c | 1011 | ||||
-rw-r--r-- | nuttx/netutils/thttpd/libhttpd.h | 7 | ||||
-rw-r--r-- | nuttx/netutils/thttpd/thttpd.c | 3 | ||||
-rwxr-xr-x | nuttx/netutils/thttpd/thttpd_alloc.c (renamed from nuttx/netutils/thttpd/httpd_alloc.c) | 4 | ||||
-rwxr-xr-x | nuttx/netutils/thttpd/thttpd_alloc.h (renamed from nuttx/netutils/thttpd/httpd_alloc.h) | 2 | ||||
-rwxr-xr-x | nuttx/netutils/thttpd/thttpd_cgi.c | 942 | ||||
-rwxr-xr-x | nuttx/netutils/thttpd/thttpd_cgi.h | 59 | ||||
-rwxr-xr-x | nuttx/netutils/thttpd/thttpd_strings.c | 179 | ||||
-rwxr-xr-x | nuttx/netutils/thttpd/thttpd_strings.h | 119 | ||||
-rw-r--r-- | nuttx/netutils/thttpd/timers.c | 2 |
12 files changed, 1314 insertions, 1018 deletions
diff --git a/nuttx/netutils/thttpd/Make.defs b/nuttx/netutils/thttpd/Make.defs index 532ab4719..9bc86cab1 100644 --- a/nuttx/netutils/thttpd/Make.defs +++ b/nuttx/netutils/thttpd/Make.defs @@ -34,5 +34,5 @@ ############################################################################ THTTPD_ASRCS = -THTTPD_CSRCS = thttpd.c libhttpd.c httpd_alloc.c timers.c fdwatch.c tdate_parse.c +THTTPD_CSRCS = thttpd.c libhttpd.c thttpd_cgi.c thttpd_alloc.c thttpd_strings.c timers.c fdwatch.c tdate_parse.c diff --git a/nuttx/netutils/thttpd/fdwatch.c b/nuttx/netutils/thttpd/fdwatch.c index 1933d1d6d..71e81c2b2 100644 --- a/nuttx/netutils/thttpd/fdwatch.c +++ b/nuttx/netutils/thttpd/fdwatch.c @@ -47,7 +47,7 @@ #include <debug.h> #include "config.h" -#include "httpd_alloc.h" +#include "thttpd_alloc.h" #include "fdwatch.h" #ifdef CONFIG_THTTPD diff --git a/nuttx/netutils/thttpd/libhttpd.c b/nuttx/netutils/thttpd/libhttpd.c index ee2a74e81..d3703586b 100644 --- a/nuttx/netutils/thttpd/libhttpd.c +++ b/nuttx/netutils/thttpd/libhttpd.c @@ -57,13 +57,13 @@ #include <debug.h> #include <nuttx/regex.h> -#include <nuttx/symtab.h> -#include <nuttx/binfmt.h> #include <net/uip/thttpd.h> #include "config.h" #include "libhttpd.h" -#include "httpd_alloc.h" +#include "thttpd_alloc.h" +#include "thttpd_strings.h" +#include "thttpd_cgi.h" #include "timers.h" #include "tdate_parse.h" #include "fdwatch.h" @@ -112,25 +112,6 @@ extern char *crypt(const char *key, const char *setting); * Private Types ****************************************************************************/ -#ifdef CONFIG_THTTPD_CGI_PATTERN -enum cgi_outbuffer_e -{ - CGI_OUTBUFFER_READHEADER = 0, /* Reading header from HTTP client */ - CGI_OUTBUFFER_HEADERREAD, /* Header has been read */ - CGI_OUTBUFFER_HEADERSENT, /* Header has been sent to the CGI program */ - CGI_OUTBUFFER_READDATA, /* Transferring data from CGI to client */ - CGI_OUTBUFFER_DONE, /* Finished */ -}; - -struct cgi_outbuffer_s -{ - enum cgi_outbuffer_e state; /* State of the transfer */ - char *buffer; /* Allocated I/O buffer */ - size_t size; /* Size of the allocation */ - size_t len; /* Amount of valid data in the allocated buffer */ -}; -#endif - /**************************************************************************** * Private Function Prototypes ****************************************************************************/ @@ -155,11 +136,6 @@ static int auth_check(httpd_conn *hc, char *dirname); static int auth_check2(httpd_conn *hc, char *dirname); #endif static void send_dirredirect(httpd_conn *hc); -static int hexit(char c); -static void strdecode(char *to, char *from); -#ifdef CONFIG_THTTPD_GENERATE_INDICES -static void strencode(char *to, int tosize, char *from); -#endif #ifdef CONFIG_THTTPD_TILDE_MAP1 static int httpd_tilde_map1(httpd_conn *hc); #endif @@ -186,18 +162,6 @@ static int ls(httpd_conn *hc); static char *hostname_map(char *hostname); #endif -/* CGI Support */ - -#ifdef CONFIG_THTTPD_CGI_PATTERN -static void create_environment(httpd_conn *hc); -static char **make_argp(httpd_conn *hc); -static inline int cgi_interpose_input(httpd_conn *hc, int wfd, char *buffer); -static inline int cgi_interpose_output(httpd_conn *hc, int rfd, char *inbuffer, - struct cgi_outbuffer_s *hdr); -static int cgi_child(int argc, char **argv); -static int cgi(httpd_conn *hc); -#endif - static int check_referer(httpd_conn *hc); #ifdef CONFIG_THTTPD_URLPATTERN static int really_check_referer(httpd_conn *hc); @@ -222,65 +186,13 @@ static size_t sockaddr_len(httpd_sockaddr *saP); * of a hack but it seems to do the right thing. */ -static pid_t main_thread; - -/* This is the 'root' of the Filesystem as seen by the HTTP client */ - -static const char httpd_root[] = CONFIG_THTTPD_PATH; +static pid_t main_thread; /* Include MIME encodings and types */ #include "mime_types.h" -/**************************************************************************** - * HTTP Strings - ****************************************************************************/ - -static const char ok200title[] = "OK"; -static const char ok206title[] = "Partial Content"; - -static const char err302title[] = "Found"; -static const char err302form[] = "The actual URL is '%s'.\n"; - -static const char err304title[] = "Not Modified"; - -const char httpd_err400title[] = "Bad Request"; -const char httpd_err400form[] = "Your request has bad syntax or is inherently impossible to satisfy.\n"; - -#ifdef CONFIG_THTTPD_AUTH_FILE -static const char err401title[] = "Unauthorized"; -static const char err401form[] = "Authorization required for the URL '%s'.\n"; -#endif - -static const char err403title[] = "Forbidden"; -#ifndef EXPLICIT_ERROR_PAGES -static const char err403form[] = "You do not have permission to get URL '%s' from this server.\n"; -#endif - -static const char err404title[] = "Not Found"; -static const char err404form[] = "The requested URL '%s' was not found on this server.\n"; - -const char httpd_err408title[] = "Request Timeout"; -const char httpd_err408form[] = "No request appeared within a reasonable time period.\n"; - -static const char err500title[] = "Internal Error"; -static const char err500form[] = "There was an unusual problem serving the requested URL '%s'.\n"; - -static const char err501title[] = "Not Implemented"; -static const char err501form[] = "The requested method '%s' is not implemented by this server.\n"; - -static const char httpd_err503title[] = "Service Temporarily Overloaded"; -static const char httpd_err503form[] = "The requested URL '%s' is temporarily overloaded. Please try again later.\n"; - -static const char html_crlf[] = "\r\n"; -static const char html_html[] = "<HTML>\r\n"; -static const char html_endhtml[] = "</HTML>\r\n"; -static const char html_hdtitle[] = "<HEAD><TITLE>"; -static const char html_titlehd[] = "</TITLE></HEAD>\r\n"; -static const char html_body[] = "<BODY BGCOLOR=\"#99cc99\" TEXT=\"#000000\" LINK=\"#2020ff\" VLINK=\"#4040cc\">\r\n"; -static const char html_endbody[] = "</BODY>\r\n"; -static const char html_hdr2[] = "<H2>"; -static const char html_endhdr2[] = "</H2>"; +/* Names for index file */ static const char *index_names[] = { CONFIG_THTTPD_INDEX_NAMES }; @@ -972,70 +884,6 @@ static void send_dirredirect(httpd_conn *hc) send_response(hc, 302, err302title, header, err302form, location); } -static int hexit(char nibble) -{ - if (nibble >= '0' && nibble <= '9') - { - return nibble - '0'; - } - else if (nibble >= 'a' && nibble <= 'f') - { - return nibble - 'a' + 10; - } - else if (nibble >= 'A' && nibble <= 'F') - { - return nibble - 'A' + 10; - } - return 0; -} - -/* Copies and decodes a string. It's ok for from and to to be the - * same string. - */ - -static void strdecode(char *to, char *from) -{ - for (; *from != '\0'; ++to, ++from) - { - if (from[0] == '%' && isxdigit(from[1]) && isxdigit(from[2])) - { - *to = hexit(from[1]) * 16 + hexit(from[2]); - from += 2; - } - else - { - *to = *from; - } - } - *to = '\0'; -} - -/* Copies and encodes a string. */ - -#ifdef CONFIG_THTTPD_GENERATE_INDICES -static void strencode(char *to, int tosize, char *from) -{ - int tolen; - - for (tolen = 0; *from != '\0' && tolen + 4 < tosize; ++from) - { - if (isalnum(*from) || strchr("/_.-~", *from) != NULL) - { - *to = *from; - ++to; - ++tolen; - } - else - { - (void)sprintf(to, "%%%02x", (int)*from & 0xff); - to += 3; - tolen += 3; - } - } - *to = '\0'; -} -#endif /* CONFIG_THTTPD_GENERATE_INDICES */ - /* Map a ~username/whatever URL into <prefix>/username. */ #ifdef CONFIG_THTTPD_TILDE_MAP1 @@ -1863,7 +1711,7 @@ static void ls_child(int argc, char **argv) } httpd_realloc_str(&encrname, &maxencrname, 3 * strlen(rname) + 1); - strencode(encrname, maxencrname, rname); + httpd_strencode(encrname, maxencrname, rname); if (stat(name, &sb) < 0 || lstat(name, &lsb) < 0) { @@ -2094,851 +1942,6 @@ static int ls(httpd_conn *hc) } #endif /* CONFIG_THTTPD_GENERATE_INDICES */ -/* Set up environment variables. Be real careful here to avoid - * letting malicious clients overrun a buffer. We don't have - * to worry about freeing stuff since we're a sub-task. - */ - -#ifdef CONFIG_THTTPD_CGI_PATTERN -static void create_environment(httpd_conn *hc) -{ - char *cp; - char buf[256]; - - setenv("PATH", CONFIG_THTTPD_CGI_PATH, TRUE); -#ifdef CGI_LD_LIBRARY_PATH - setenv("LD_LIBRARY_PATH", CGI_LD_LIBRARY_PATH, TRUE); -#endif /* CGI_LD_LIBRARY_PATH */ - - setenv("SERVER_SOFTWARE", CONFIG_THTTPD_SERVER_SOFTWARE, TRUE); - - /* If vhosting, use that server-name here. */ -#ifdef CONFIG_THTTPD_VHOST - if (hc->vhostname) - { - cp = hc->vhostname; - } - else -#endif - { - cp = hc->hs->hostname; - } - - if (cp) - { - setenv("SERVER_NAME", cp, TRUE); - } - - setenv("GATEWAY_INTERFACE", "CGI/1.1", TRUE); - setenv("SERVER_PROTOCOL", hc->protocol, TRUE); - - (void)snprintf(buf, sizeof(buf), "%d", (int)CONFIG_THTTPD_PORT); - setenv("SERVER_PORT", buf, TRUE); - - setenv("REQUEST_METHOD", httpd_method_str(hc->method), TRUE); - - if (hc->pathinfo[0] != '\0') - { - char *cp2; - size_t l; - - (void)snprintf(buf, sizeof(buf), "/%s", hc->pathinfo); - setenv("PATH_INFO", buf, TRUE); - - l = strlen(httpd_root) + strlen(hc->pathinfo) + 1; - cp2 = NEW(char, l); - if (cp2) - { - (void)snprintf(cp2, l, "%s%s", httpd_root, hc->pathinfo); - setenv("PATH_TRANSLATED", cp2, TRUE); - } - } - - (void)snprintf(buf, sizeof(buf), "/%s",strcmp(hc->origfilename, ".") == 0 ? "" : hc->origfilename); - setenv("SCRIPT_NAME", buf, TRUE); - - if (hc->query[0] != '\0') - { - setenv("QUERY_STRING", hc->query, TRUE); - } - - setenv("REMOTE_ADDR", httpd_ntoa(&hc->client_addr), TRUE); - if (hc->referer[0] != '\0') - { - setenv("HTTP_REFERER", hc->referer, TRUE); - } - - if (hc->useragent[0] != '\0') - { - setenv("HTTP_USER_AGENT", hc->useragent, TRUE); - } - - if (hc->accept[0] != '\0') - { - setenv("HTTP_ACCEPT", hc->accept, TRUE); - } - - if (hc->accepte[0] != '\0') - { - setenv("HTTP_ACCEPT_ENCODING", hc->accepte, TRUE); - } - - if (hc->acceptl[0] != '\0') - { - setenv("HTTP_ACCEPT_LANGUAGE", hc->acceptl, TRUE); - } - - if (hc->cookie[0] != '\0') - { - setenv("HTTP_COOKIE", hc->cookie, TRUE); - } - - if (hc->contenttype[0] != '\0') - { - setenv("CONTENT_TYPE", hc->contenttype, TRUE); - } - - if (hc->hdrhost[0] != '\0') - { - setenv("HTTP_HOST", hc->hdrhost, TRUE); - } - - if (hc->contentlength != -1) - { - (void)snprintf(buf, sizeof(buf), "%lu", (unsigned long)hc->contentlength); - setenv("CONTENT_LENGTH", buf, TRUE); - } - - if (hc->remoteuser[0] != '\0') - { - setenv("REMOTE_USER", hc->remoteuser, TRUE); - } - - if (hc->authorization[0] != '\0') - { - setenv("AUTH_TYPE", "Basic", TRUE); - } - - /* We only support Basic auth at the moment. */ - - if (getenv("TZ") != NULL) - { - setenv("TZ", getenv("TZ"), TRUE); - } - - setenv("CGI_PATTERN", CONFIG_THTTPD_CGI_PATTERN, TRUE); -} -#endif - -/* Set up argument vector */ - -#ifdef CONFIG_THTTPD_CGI_PATTERN -static FAR char **make_argp(httpd_conn *hc) -{ - FAR char **argp; - int argn; - char *cp1; - char *cp2; - - /* By allocating an arg slot for every character in the query, plus one - * for the filename and one for the NULL, we are guaranteed to have - * enough. We could actually use strlen/2. - */ - - argp = NEW(char *, strlen(hc->query) + 2); - if (!argp) - { - return NULL; - } - - argp[0] = strrchr(hc->expnfilename, '/'); - if (argp[0]) - { - ++argp[0]; - } - else - { - argp[0] = hc->expnfilename; - } - argn = 1; - - /* According to the CGI spec at http://hoohoo.ncsa.uiuc.edu/cgi/cl.html, - * "The server should search the query information for a non-encoded = - * character to determine if the command line is to be used, if it finds - * one, the command line is not to be used." - */ - - if (strchr(hc->query, '=') == NULL) - { - for (cp1 = cp2 = hc->query; *cp2 != '\0'; ++cp2) - { - if (*cp2 == '+') - { - *cp2 = '\0'; - strdecode(cp1, cp1); - argp[argn++] = cp1; - cp1 = cp2 + 1; - } - } - - if (cp2 != cp1) - { - strdecode(cp1, cp1); - argp[argn++] = cp1; - } - } - - argp[argn] = NULL; - return argp; -} -#endif - -/* Data is available from the client socket. This routine is used only for POST - * requests. It reads the data from the client and sends it to the child thread. - */ - -#ifdef CONFIG_THTTPD_CGI_PATTERN -static inline int cgi_interpose_input(httpd_conn *hc, int wfd, char *buffer) -{ - size_t nbytes; - ssize_t nbytes_read; - ssize_t nbytes_written; - - nbytes = hc->read_idx - hc->checked_idx; - if (nbytes > 0) - { - if (httpd_write(wfd, &(hc->read_buf[hc->checked_idx]), nbytes) != nbytes) - { - return 1; - } - } - - if (nbytes < hc->contentlength) - { - do - { - nbytes_read = read(hc->conn_fd, buffer, MIN(sizeof(buffer), hc->contentlength - nbytes)); - if (nbytes_read < 0) - { - if (errno != EINTR) - { - return 1; - } - } - } - while (nbytes_read < 0); - - if (nbytes_read > 0) - { - nbytes_written = httpd_write(wfd, buffer, nbytes_read); - if (nbytes_written != nbytes_read) - { - return 1; - } - } - } - - if (nbytes >= hc->contentlength) - { - /* Special hack to deal with broken browsers that send a LF or CRLF - * after POST data, causing TCP resets - we just read and discard up - * to 2 bytes. Unfortunately this doesn't fix the problem for CGIs - * which avoid the interposer task due to their POST data being - * short. Creating an interposer task for all POST CGIs is - * unacceptably expensive. The eventual fix will come when interposing - * gets integrated into the main loop as a tasklet instead of a task. - */ - - /* Turn on no-delay mode in case we previously cleared it. */ - - httpd_set_ndelay(hc->conn_fd); - - /* And read up to 2 bytes. */ - - (void)read(hc->conn_fd, buffer, sizeof(buffer)); - return 1; - } - return 0; -} -#endif - -/* This routine is used for parsed-header CGIs. The idea here is that the - * CGI can return special headers such as "Status:" and "Location:" which - * change the return status of the response. Since the return status has to - * be the very first line written out, we have to accumulate all the headers - * and check for the special ones before writing the status. Then we write - * out the saved headers and proceed to echo the rest of the response. - */ - -#ifdef CONFIG_THTTPD_CGI_PATTERN -static inline int cgi_interpose_output(httpd_conn *hc, int rfd, char *inbuffer, - struct cgi_outbuffer_s *hdr) -{ - ssize_t nbytes_read; - char *br = NULL; - int status; - const char *title; - char *cp; - - /* Make sure the connection is in blocking mode. It should already be - * blocking, but we might as well be sure. - */ - - httpd_clear_ndelay(hc->conn_fd); - - /* Loop while there are things we can do without waiting for more input */ - - switch (hdr->state) - { - case CGI_OUTBUFFER_READHEADER: - { - /* Slurp in all headers as they become available from the client. */ - - do - { - /* Read until we successfully read data or until an error occurs. - * EAGAIN is not an error, but it is still cause to return. - */ - - nbytes_read = read(hc->conn_fd, inbuffer, sizeof(inbuffer)); - nvdbg("Read %d bytes from fd %d\n", nbytes_read, hc->conn_fd); - - if (nbytes_read < 0) - { - if (errno != EINTR) - { - if (errno != EAGAIN) - { - ndbg("read: %d\n", errno); - } - return 1; - } - } - } - while (nbytes_read < 0); - - /* Check for end-of-file */ - - if (nbytes_read <= 0) - { - nvdbg("End-of-file\n"); - br = &(hdr->buffer[hdr->len]); - hdr->state = CGI_OUTBUFFER_HEADERREAD; - } - else - { - /* Accumulate more header data */ - - httpd_realloc_str(&hdr->buffer, &hdr->size, hdr->len + nbytes_read); - (void)memcpy(&(hdr->buffer[hdr->len]), inbuffer, nbytes_read); - hdr->len += nbytes_read; - hdr->buffer[hdr->len] = '\0'; - nvdbg("Header bytes accumulated: %d\n", hdr->len); - - /* Check for end of header */ - - if ((br = strstr(hdr->buffer, "\r\n\r\n")) != NULL || - (br = strstr(hdr->buffer, "\012\012")) != NULL) - { - nvdbg("End-of-header\n"); - hdr->state = CGI_OUTBUFFER_HEADERREAD; - } - else - { - /* Return. We will be called again when more data is available - * on the socket. - */ - - return 0; - } - } - } - break; - - case CGI_OUTBUFFER_HEADERREAD: - { - /* If there were no headers, bail. */ - - if (hdr->buffer[0] == '\0') - { - hdr->state = CGI_OUTBUFFER_DONE; - return 1; - } - - /* Figure out the status. Look for a Status: or Location: header; else if - * there's an HTTP header line, get it from there; else default to 200. - */ - - status = 200; - if (strncmp(hdr->buffer, "HTTP/", 5) == 0) - { - cp = hdr->buffer; - cp += strcspn(cp, " \t"); - status = atoi(cp); - } - - if ((cp = strstr(hdr->buffer, "Status:")) != NULL && - cp < br && (cp == hdr->buffer || *(cp - 1) == '\012')) - { - cp += 7; - cp += strspn(cp, " \t"); - status = atoi(cp); - } - - if ((cp = strstr(hdr->buffer, "Location:")) != NULL && - cp < br && (cp == hdr->buffer || *(cp - 1) == '\012')) - { - status = 302; - } - - /* Write the status line. */ - - nvdbg("Status: %d\n", status); - switch (status) - { - case 200: - title = ok200title; - break; - - case 302: - title = err302title; - break; - - case 304: - title = err304title; - break; - - case 400: - BADREQUEST("status"); - title = httpd_err400title; - break; - -#ifdef CONFIG_THTTPD_AUTH_FILE - case 401: - title = err401title; - break; -#endif - - case 403: - title = err403title; - break; - - case 404: - title = err404title; - break; - - case 408: - title = httpd_err408title; - break; - - case 500: - INTERNALERROR("status"); - title = err500title; - break; - - case 501: - NOTIMPLEMENTED("status"); - title = err501title; - break; - - case 503: - title = httpd_err503title; - break; - - default: - title = "Something"; - break; - } - - (void)snprintf(inbuffer, sizeof(inbuffer), "HTTP/1.0 %d %s\r\n", status, title); - (void)httpd_write(hc->conn_fd, inbuffer, strlen(inbuffer)); - - /* Write the saved hdr->buffer to the client. */ - - (void)httpd_write(hc->conn_fd, hdr->buffer, hdr->len); - } - - /* Then set up to read the data following the header from the CGI program and - * pass it back to the client. We return now; we will be called again when - * data is available on the pipe. - */ - - hdr->state = CGI_OUTBUFFER_READDATA; - return 0; - - case CGI_OUTBUFFER_READDATA: - { - /* Read data from the pipe. */ - - do - { - /* Read until we successfully read data or until an error occurs. - * EAGAIN is not an error, but it is still cause to return. - */ - - nbytes_read = read(rfd, inbuffer, sizeof(inbuffer)); - nvdbg("Read %d bytes from fd %d\n", nbytes_read, rfd); - - if (nbytes_read < 0) - { - if (errno != EINTR) - { - if (errno != EAGAIN) - { - ndbg("read: %d\n", errno); - } - return 1; - } - } - } - while (nbytes_read < 0); - - /* Check for end of file */ - - if (nbytes_read == 0) - { - nvdbg("End-of-file\n"); - close(hc->conn_fd); - close(rfd); - hdr->state = CGI_OUTBUFFER_DONE; - return 1; - } - else - { - /* Forward the data from the CGI program to the client */ - - (void)httpd_write(hc->conn_fd, inbuffer, strlen(inbuffer)); - } - } - break; - - case CGI_OUTBUFFER_DONE: - default: - return 1; - } - return 0; -} -#endif - -/* CGI child task. */ - -#ifdef CONFIG_THTTPD_CGI_PATTERN -static int cgi_child(int argc, char **argv) -{ - FAR httpd_conn *hc = (FAR httpd_conn*)strtoul(argv[1], NULL, 16); -#if CONFIG_THTTPD_CGI_TIMELIMIT > 0 - ClientData client_data; -#endif - FAR char **argp; - struct cgi_outbuffer_s hdr; - struct fdwatch_s *fw; - char *buffer; - char *binary; - char *directory; - boolean indone; - boolean outdone; - int child; - int pipefd[2]; - int wfd = -1; - int rfd = -1; - int fd; - int ret; - int err = 1; - - /* Use low-level debug out (because the low-level output may survive closing - * all file descriptors - */ - - nllvdbg("Started: %s\n", argv[1]); - - /* Update all of the environment variable settings, these will be inherited - * by the CGI task. - */ - - create_environment(hc); - - /* Make the argument vector. */ - - argp = make_argp(hc); - - /* Close all file descriptors (including stdio, stdin, stdout) EXCEPT for - * stderr and hc->conn_fd - */ - - nllvdbg("Closing all descriptors\n"); - for (fd = 0; fd < (CONFIG_NFILE_DESCRIPTORS + CONFIG_NSOCKET_DESCRIPTORS); fd++) - { - /* Keep stderr open for debug; keep hc->conn_fd open for obvious reasons */ - - if (fd != 2 && fd != hc->conn_fd) - { - close(fd); - } - } - - /* Create pipes that will be interposed between the CGI task's stdin or - * stdout and the socket. - * - * Setup up the STDIN pipe - a pipe to transfer data received on the - * socket to the CGI program. - */ - - nllvdbg("Create STDIN pipe\n"); - ret = pipe(pipefd); - if (ret < 0) - { - nlldbg("STDIN pipe: %d\n", errno); - goto errout_with_descriptors; - } - else - { - /* Then map the receiving end the pipe to stdin, save the sending end, and - * closing the original receiving end - */ - - ret = dup2(pipefd[0], 0); - if (ret < 0) - { - nlldbg("STDIN dup2: %d\n", errno); - close(pipefd[1]); - goto errout_with_descriptors; - } - - wfd = pipefd[1]; - close(pipefd[0]); - } - - /* Set up the STDOUT pipe - a pipe to transfer data received from the CGI program - * to the client. - */ - - if (ret == 0) - { - nllvdbg("Create STDOUT pipe\n"); - ret = pipe(pipefd); - if (ret < 0) - { - nlldbg("STDOUT pipe: %d\n", errno); - goto errout_with_descriptors; - } - else - { - /* Then map the sending end the pipe to stdout, save the receiving end, and - * closing the original sending end - */ - - ret = dup2(pipefd[1], 1); - if (ret < 0) - { - nlldbg("STDOUT dup2: %d\n", errno); - close(pipefd[1]); - goto errout_with_descriptors; - } - - rfd = pipefd[0]; - close(pipefd[1]); - } - } - - /* Split the program into directory and binary, so we can chdir() to the - * program's own directory. This isn't in the CGI 1.1 spec, but it's what - * other HTTP servers do. - */ - - directory = strdup(hc->expnfilename); - if (!directory) - { - binary = hc->expnfilename; /* ignore errors */ - } - else - { - binary = strrchr(directory, '/'); - if (!binary) - { - binary = hc->expnfilename; - } - else - { - *binary++ = '\0'; - (void)chdir(directory); /* ignore errors */ - } - } - - /* Allocate memory for buffering */ - - memset(&hdr, 0, sizeof(struct cgi_outbuffer_s)); - httpd_realloc_str(&hdr.buffer, &hdr.size, 500); - if (!hdr.buffer) - { - nlldbg("hdr allocation failed\n"); - goto errout_with_descriptors; - } - - buffer = (char*)httpd_malloc(CONFIG_THTTPD_IOBUFFERSIZE); - if (!buffer) - { - nlldbg("buffer allocation failed\n"); - goto errout_with_header; - } - - /* Create fdwatch structures */ - - fw = fdwatch_initialize(2); - if (!fw) - { - nlldbg("fdwatch allocation failed\n"); - goto errout_with_buffer; - } - - /* Run the CGI program. */ - - nllvdbg("Starting CGI\n"); - child = exec(binary, (FAR const char **)argp, g_thttpdsymtab, g_thttpdnsymbols); - if (child < 0) - { - /* Something went wrong. */ - - nlldbg("execve %s: %d\n", hc->expnfilename, errno); - goto errout_with_watch; - } - - /* Schedule a kill for the child task in case it runs too long. */ - -#if CONFIG_THTTPD_CGI_TIMELIMIT > 0 - client_data.i = child; - if (tmr_create(NULL, cgi_kill, client_data, CONFIG_THTTPD_CGI_TIMELIMIT * 1000L, 0) == NULL) - { - nlldbg("tmr_create(cgi_kill child) failed\n"); - goto errout_with_watch; - } -#endif - - /* Add the read descriptors to the watch */ - - fdwatch_add_fd(fw, hc->conn_fd, NULL); - fdwatch_add_fd(fw, rfd, NULL); - - /* Then perform the interposition */ - - indone = FALSE; - outdone = FALSE; - - nllvdbg("Interposing\n"); - do - { - (void)fdwatch(fw, 5000); - - if (!indone && fdwatch_check_fd(fw, hc->conn_fd)) - { - /* Transfer data from the client to the CGI program (POST) */ - - nllvdbg("Interpose input\n"); - indone = cgi_interpose_input(hc, wfd, buffer); - if (indone) - { - fdwatch_del_fd(fw, hc->conn_fd); - } - } - - if (fdwatch_check_fd(fw, rfd)) - { - /* Handle receipt of headers and CGI program response (GET) */ - - nllvdbg("Interpose output\n"); - outdone = cgi_interpose_output(hc, rfd, buffer, &hdr); - } - } - while (!outdone); - err = 0; - - /* Get rid of watch structures */ - -errout_with_watch: - fdwatch_uninitialize(fw); - - /* Free memory */ - -errout_with_buffer: - httpd_free(buffer); -errout_with_header: - httpd_free(hdr.buffer); - - /* Close all descriptors */ - -errout_with_descriptors: - close(wfd); - close(rfd); - close(hc->conn_fd); - - INTERNALERROR("errout"); - httpd_send_err(hc, 500, err500title, "", err500form, hc->encodedurl); - httpd_write_response(hc); - nllvdbg("Return %d\n", ret); - return err; -} -#endif /* CONFIG_THTTPD_CGI_PATTERN */ - -#ifdef CONFIG_THTTPD_CGI_PATTERN -static int cgi(httpd_conn *hc) -{ - char arg[16]; - char *argv[1]; - pid_t child; - - if (hc->method == METHOD_GET || hc->method == METHOD_POST) - { -#ifdef CONFIG_THTTPD_CGILIMIT - if (hc->hs->cgi_count >= CONFIG_THTTPD_CGILIMIT) - { - httpd_send_err(hc, 503, httpd_err503title, "", httpd_err503form, - hc->encodedurl); - return -1; - } -#endif - ++hc->hs->cgi_count; - httpd_clear_ndelay(hc->conn_fd); - - /* Start the child task. We use a trampoline task here so that we can - * safely muck with the file descriptors before actually started the CGI - * task. - */ - - snprintf(arg, 16, "%p", hc); /* task_create doesn't handle binary arguments. */ - argv[0] = arg; - -#ifndef CONFIG_CUSTOM_STACK - child = task_create("CGI child", CONFIG_THTTPD_CGI_PRIORITY, - CONFIG_THTTPD_CGI_STACKSIZE, - (main_t)cgi_child, (const char **)argv); -#else - child = task_create("CGI child", CONFIG_THTTPD_CGI_PRIORITY, - (main_t)cgi_child, (const char **)argv); -#endif - if (child < 0) - { - ndbg("task_create: %d\n", errno); - INTERNALERROR("task_create"); - httpd_send_err(hc, 500, err500title, "", err500form, hc->encodedurl); - return -1; - } - - ndbg("Started CGI task %d for file '%s'\n", child, hc->expnfilename); - - hc->status = 200; - hc->bytes_sent = CONFIG_THTTPD_CGI_BYTECOUNT; - hc->should_linger = FALSE; - } - else - { - NOTIMPLEMENTED("CGI"); - httpd_send_err(hc, 501, err501title, "", err501form, httpd_method_str(hc->method)); - return -1; - } - - return 0; -} -#endif - /* Returns 1 if ok to serve the url, 0 if not. */ static int check_referer(httpd_conn *hc) @@ -3750,7 +2753,7 @@ int httpd_parse_request(httpd_conn *hc) hc->encodedurl = url; httpd_realloc_str(&hc->decodedurl, &hc->maxdecodedurl, strlen(hc->encodedurl)); - strdecode(hc->decodedurl, hc->encodedurl); + httpd_strdecode(hc->decodedurl, hc->encodedurl); httpd_realloc_str(&hc->origfilename, &hc->maxorigfilename, strlen(hc->decodedurl)); (void)strcpy(hc->origfilename, &hc->decodedurl[1]); diff --git a/nuttx/netutils/thttpd/libhttpd.h b/nuttx/netutils/thttpd/libhttpd.h index 6b1ee0d7d..662f5011c 100644 --- a/nuttx/netutils/thttpd/libhttpd.h +++ b/nuttx/netutils/thttpd/libhttpd.h @@ -311,13 +311,6 @@ extern void httpd_destroy_conn(httpd_conn *hc); extern void httpd_send_err(httpd_conn *hc, int status, const char *title, const char *extraheads, const char *form, const char *arg); -/* Some error messages. */ - -extern const char httpd_err400title[]; -extern const char httpd_err400form[]; -extern const char httpd_err408title[]; -extern const char httpd_err408form[]; - /* Generate a string representation of a method number. */ extern const char *httpd_method_str(int method); diff --git a/nuttx/netutils/thttpd/thttpd.c b/nuttx/netutils/thttpd/thttpd.c index 693e141eb..84507bce9 100644 --- a/nuttx/netutils/thttpd/thttpd.c +++ b/nuttx/netutils/thttpd/thttpd.c @@ -59,7 +59,8 @@ #include "config.h" #include "fdwatch.h" #include "libhttpd.h" -#include "httpd_alloc.h" +#include "thttpd_alloc.h" +#include "thttpd_strings.h" #include "timers.h" #ifdef CONFIG_THTTPD diff --git a/nuttx/netutils/thttpd/httpd_alloc.c b/nuttx/netutils/thttpd/thttpd_alloc.c index f3504993f..85f79adc4 100755 --- a/nuttx/netutils/thttpd/httpd_alloc.c +++ b/nuttx/netutils/thttpd/thttpd_alloc.c @@ -1,5 +1,5 @@ /**************************************************************************** - * netutils/thttpd/httpd_alloc.c + * netutils/thttpd/thttpd_alloc.c * * Copyright (C) 2009 Gregory Nutt. All rights reserved. * Author: Gregory Nutt <spudmonkey@racsa.co.cr> @@ -45,7 +45,7 @@ #include <errno.h> #include "config.h" -#include "httpd_alloc.h" +#include "thttpd_alloc.h" #ifdef CONFIG_THTTPD diff --git a/nuttx/netutils/thttpd/httpd_alloc.h b/nuttx/netutils/thttpd/thttpd_alloc.h index c3b3eb27e..c20834965 100755 --- a/nuttx/netutils/thttpd/httpd_alloc.h +++ b/nuttx/netutils/thttpd/thttpd_alloc.h @@ -1,5 +1,5 @@ /**************************************************************************** - * netutils/thttpd/httpd_alloc.h + * netutils/thttpd/thttpd_alloc.h * * Copyright (C) 2009 Gregory Nutt. All rights reserved. * Author: Gregory Nutt <spudmonkey@racsa.co.cr> diff --git a/nuttx/netutils/thttpd/thttpd_cgi.c b/nuttx/netutils/thttpd/thttpd_cgi.c new file mode 100755 index 000000000..247a71d0b --- /dev/null +++ b/nuttx/netutils/thttpd/thttpd_cgi.c @@ -0,0 +1,942 @@ +/****************************************************************************
+ * netutils/thttpd/thttpd_cgi.c
+ * CGI support
+ *
+ * Copyright (C) 2009 Gregory Nutt. All rights reserved.
+ * Author: Gregory Nutt <spudmonkey@racsa.co.cr>
+ *
+ * Derived from the file libhttpd.c in the original THTTPD package:
+ *
+ * Copyright © 1995,1998,1999,2000,2001 by Jef Poskanzer <jef@mail.acme.com>.
+ * 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.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR 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 AUTHOR 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.
+ *
+ ****************************************************************************/
+
+/****************************************************************************
+ * Included Files
+ ****************************************************************************/
+
+#include <nuttx/config.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <string.h>
+#include <errno.h>
+#include <debug.h>
+
+#include <nuttx/symtab.h>
+#include <nuttx/binfmt.h>
+#include <net/uip/thttpd.h>
+
+#include "config.h"
+#include "libhttpd.h"
+#include "thttpd_alloc.h"
+#include "thttpd_strings.h"
+#include "timers.h"
+#include "fdwatch.h"
+
+#if defined(CONFIG_THTTPD) && defined(CONFIG_THTTPD_CGI_PATTERN)
+
+/****************************************************************************
+ * Pre-processor Definitions
+ ****************************************************************************/
+
+/****************************************************************************
+ * Private Types
+ ****************************************************************************/
+
+enum cgi_outbuffer_e
+{
+ CGI_OUTBUFFER_READHEADER = 0, /* Reading header from HTTP client */
+ CGI_OUTBUFFER_HEADERREAD, /* Header has been read */
+ CGI_OUTBUFFER_HEADERSENT, /* Header has been sent to the CGI program */
+ CGI_OUTBUFFER_READDATA, /* Transferring data from CGI to client */
+ CGI_OUTBUFFER_DONE, /* Finished */
+};
+
+struct cgi_outbuffer_s
+{
+ enum cgi_outbuffer_e state; /* State of the transfer */
+ char *buffer; /* Allocated I/O buffer */
+ size_t size; /* Size of the allocation */
+ size_t len; /* Amount of valid data in the allocated buffer */
+};
+
+/****************************************************************************
+ * Private Function Prototypes
+ ****************************************************************************/
+
+static void create_environment(httpd_conn *hc);
+static char **make_argp(httpd_conn *hc);
+static inline int cgi_interpose_input(httpd_conn *hc, int wfd, char *buffer);
+static inline int cgi_interpose_output(httpd_conn *hc, int rfd, char *inbuffer,
+ struct cgi_outbuffer_s *hdr);
+static int cgi_child(int argc, char **argv);
+
+/****************************************************************************
+ * Private Functions
+ ****************************************************************************/
+
+/* Set up environment variables. Be real careful here to avoid
+ * letting malicious clients overrun a buffer. We don't have
+ * to worry about freeing stuff since we're a sub-task.
+ */
+
+static void create_environment(httpd_conn *hc)
+{
+ char *cp;
+ char buf[256];
+
+ setenv("PATH", CONFIG_THTTPD_CGI_PATH, TRUE);
+#ifdef CGI_LD_LIBRARY_PATH
+ setenv("LD_LIBRARY_PATH", CGI_LD_LIBRARY_PATH, TRUE);
+#endif /* CGI_LD_LIBRARY_PATH */
+
+ setenv("SERVER_SOFTWARE", CONFIG_THTTPD_SERVER_SOFTWARE, TRUE);
+
+ /* If vhosting, use that server-name here. */
+#ifdef CONFIG_THTTPD_VHOST
+ if (hc->vhostname)
+ {
+ cp = hc->vhostname;
+ }
+ else
+#endif
+ {
+ cp = hc->hs->hostname;
+ }
+
+ if (cp)
+ {
+ setenv("SERVER_NAME", cp, TRUE);
+ }
+
+ setenv("GATEWAY_INTERFACE", "CGI/1.1", TRUE);
+ setenv("SERVER_PROTOCOL", hc->protocol, TRUE);
+
+ (void)snprintf(buf, sizeof(buf), "%d", (int)CONFIG_THTTPD_PORT);
+ setenv("SERVER_PORT", buf, TRUE);
+
+ setenv("REQUEST_METHOD", httpd_method_str(hc->method), TRUE);
+
+ if (hc->pathinfo[0] != '\0')
+ {
+ char *cp2;
+ size_t l;
+
+ (void)snprintf(buf, sizeof(buf), "/%s", hc->pathinfo);
+ setenv("PATH_INFO", buf, TRUE);
+
+ l = strlen(httpd_root) + strlen(hc->pathinfo) + 1;
+ cp2 = NEW(char, l);
+ if (cp2)
+ {
+ (void)snprintf(cp2, l, "%s%s", httpd_root, hc->pathinfo);
+ setenv("PATH_TRANSLATED", cp2, TRUE);
+ }
+ }
+
+ (void)snprintf(buf, sizeof(buf), "/%s",strcmp(hc->origfilename, ".") == 0 ? "" : hc->origfilename);
+ setenv("SCRIPT_NAME", buf, TRUE);
+
+ if (hc->query[0] != '\0')
+ {
+ setenv("QUERY_STRING", hc->query, TRUE);
+ }
+
+ setenv("REMOTE_ADDR", httpd_ntoa(&hc->client_addr), TRUE);
+ if (hc->referer[0] != '\0')
+ {
+ setenv("HTTP_REFERER", hc->referer, TRUE);
+ }
+
+ if (hc->useragent[0] != '\0')
+ {
+ setenv("HTTP_USER_AGENT", hc->useragent, TRUE);
+ }
+
+ if (hc->accept[0] != '\0')
+ {
+ setenv("HTTP_ACCEPT", hc->accept, TRUE);
+ }
+
+ if (hc->accepte[0] != '\0')
+ {
+ setenv("HTTP_ACCEPT_ENCODING", hc->accepte, TRUE);
+ }
+
+ if (hc->acceptl[0] != '\0')
+ {
+ setenv("HTTP_ACCEPT_LANGUAGE", hc->acceptl, TRUE);
+ }
+
+ if (hc->cookie[0] != '\0')
+ {
+ setenv("HTTP_COOKIE", hc->cookie, TRUE);
+ }
+
+ if (hc->contenttype[0] != '\0')
+ {
+ setenv("CONTENT_TYPE", hc->contenttype, TRUE);
+ }
+
+ if (hc->hdrhost[0] != '\0')
+ {
+ setenv("HTTP_HOST", hc->hdrhost, TRUE);
+ }
+
+ if (hc->contentlength != -1)
+ {
+ (void)snprintf(buf, sizeof(buf), "%lu", (unsigned long)hc->contentlength);
+ setenv("CONTENT_LENGTH", buf, TRUE);
+ }
+
+ if (hc->remoteuser[0] != '\0')
+ {
+ setenv("REMOTE_USER", hc->remoteuser, TRUE);
+ }
+
+ if (hc->authorization[0] != '\0')
+ {
+ setenv("AUTH_TYPE", "Basic", TRUE);
+ }
+
+ /* We only support Basic auth at the moment. */
+
+ if (getenv("TZ") != NULL)
+ {
+ setenv("TZ", getenv("TZ"), TRUE);
+ }
+
+ setenv("CGI_PATTERN", CONFIG_THTTPD_CGI_PATTERN, TRUE);
+}
+
+/* Set up argument vector */
+
+static FAR char **make_argp(httpd_conn *hc)
+{
+ FAR char **argp;
+ int argn;
+ char *cp1;
+ char *cp2;
+
+ /* By allocating an arg slot for every character in the query, plus one
+ * for the filename and one for the NULL, we are guaranteed to have
+ * enough. We could actually use strlen/2.
+ */
+
+ argp = NEW(char *, strlen(hc->query) + 2);
+ if (!argp)
+ {
+ return NULL;
+ }
+
+ argp[0] = strrchr(hc->expnfilename, '/');
+ if (argp[0])
+ {
+ ++argp[0];
+ }
+ else
+ {
+ argp[0] = hc->expnfilename;
+ }
+ argn = 1;
+
+ /* According to the CGI spec at http://hoohoo.ncsa.uiuc.edu/cgi/cl.html,
+ * "The server should search the query information for a non-encoded =
+ * character to determine if the command line is to be used, if it finds
+ * one, the command line is not to be used."
+ */
+
+ if (strchr(hc->query, '=') == NULL)
+ {
+ for (cp1 = cp2 = hc->query; *cp2 != '\0'; ++cp2)
+ {
+ if (*cp2 == '+')
+ {
+ *cp2 = '\0';
+ httpd_strdecode(cp1, cp1);
+ argp[argn++] = cp1;
+ cp1 = cp2 + 1;
+ }
+ }
+
+ if (cp2 != cp1)
+ {
+ httpd_strdecode(cp1, cp1);
+ argp[argn++] = cp1;
+ }
+ }
+
+ argp[argn] = NULL;
+ return argp;
+}
+
+/* Data is available from the client socket. This routine is used only for POST
+ * requests. It reads the data from the client and sends it to the child thread.
+ */
+
+static inline int cgi_interpose_input(httpd_conn *hc, int wfd, char *buffer)
+{
+ size_t nbytes;
+ ssize_t nbytes_read;
+ ssize_t nbytes_written;
+
+ nbytes = hc->read_idx - hc->checked_idx;
+ if (nbytes > 0)
+ {
+ if (httpd_write(wfd, &(hc->read_buf[hc->checked_idx]), nbytes) != nbytes)
+ {
+ return 1;
+ }
+ }
+
+ if (nbytes < hc->contentlength)
+ {
+ do
+ {
+ nbytes_read = read(hc->conn_fd, buffer, MIN(sizeof(buffer), hc->contentlength - nbytes));
+ if (nbytes_read < 0)
+ {
+ if (errno != EINTR)
+ {
+ return 1;
+ }
+ }
+ }
+ while (nbytes_read < 0);
+
+ if (nbytes_read > 0)
+ {
+ nbytes_written = httpd_write(wfd, buffer, nbytes_read);
+ if (nbytes_written != nbytes_read)
+ {
+ return 1;
+ }
+ }
+ }
+
+ if (nbytes >= hc->contentlength)
+ {
+ /* Special hack to deal with broken browsers that send a LF or CRLF
+ * after POST data, causing TCP resets - we just read and discard up
+ * to 2 bytes. Unfortunately this doesn't fix the problem for CGIs
+ * which avoid the interposer task due to their POST data being
+ * short. Creating an interposer task for all POST CGIs is
+ * unacceptably expensive. The eventual fix will come when interposing
+ * gets integrated into the main loop as a tasklet instead of a task.
+ */
+
+ /* Turn on no-delay mode in case we previously cleared it. */
+
+ httpd_set_ndelay(hc->conn_fd);
+
+ /* And read up to 2 bytes. */
+
+ (void)read(hc->conn_fd, buffer, sizeof(buffer));
+ return 1;
+ }
+ return 0;
+}
+
+/* This routine is used for parsed-header CGIs. The idea here is that the
+ * CGI can return special headers such as "Status:" and "Location:" which
+ * change the return status of the response. Since the return status has to
+ * be the very first line written out, we have to accumulate all the headers
+ * and check for the special ones before writing the status. Then we write
+ * out the saved headers and proceed to echo the rest of the response.
+ */
+
+static inline int cgi_interpose_output(httpd_conn *hc, int rfd, char *inbuffer,
+ struct cgi_outbuffer_s *hdr)
+{
+ ssize_t nbytes_read;
+ char *br = NULL;
+ int status;
+ const char *title;
+ char *cp;
+
+ /* Make sure the connection is in blocking mode. It should already be
+ * blocking, but we might as well be sure.
+ */
+
+ httpd_clear_ndelay(hc->conn_fd);
+
+ /* Loop while there are things we can do without waiting for more input */
+
+ switch (hdr->state)
+ {
+ case CGI_OUTBUFFER_READHEADER:
+ {
+ /* Slurp in all headers as they become available from the client. */
+
+ do
+ {
+ /* Read until we successfully read data or until an error occurs.
+ * EAGAIN is not an error, but it is still cause to return.
+ */
+
+ nbytes_read = read(hc->conn_fd, inbuffer, sizeof(inbuffer));
+ nvdbg("Read %d bytes from fd %d\n", nbytes_read, hc->conn_fd);
+
+ if (nbytes_read < 0)
+ {
+ if (errno != EINTR)
+ {
+ if (errno != EAGAIN)
+ {
+ ndbg("read: %d\n", errno);
+ }
+ return 1;
+ }
+ }
+ }
+ while (nbytes_read < 0);
+
+ /* Check for end-of-file */
+
+ if (nbytes_read <= 0)
+ {
+ nvdbg("End-of-file\n");
+ br = &(hdr->buffer[hdr->len]);
+ hdr->state = CGI_OUTBUFFER_HEADERREAD;
+ }
+ else
+ {
+ /* Accumulate more header data */
+
+ httpd_realloc_str(&hdr->buffer, &hdr->size, hdr->len + nbytes_read);
+ (void)memcpy(&(hdr->buffer[hdr->len]), inbuffer, nbytes_read);
+ hdr->len += nbytes_read;
+ hdr->buffer[hdr->len] = '\0';
+ nvdbg("Header bytes accumulated: %d\n", hdr->len);
+
+ /* Check for end of header */
+
+ if ((br = strstr(hdr->buffer, "\r\n\r\n")) != NULL ||
+ (br = strstr(hdr->buffer, "\012\012")) != NULL)
+ {
+ nvdbg("End-of-header\n");
+ hdr->state = CGI_OUTBUFFER_HEADERREAD;
+ }
+ else
+ {
+ /* Return. We will be called again when more data is available
+ * on the socket.
+ */
+
+ return 0;
+ }
+ }
+ }
+ break;
+
+ case CGI_OUTBUFFER_HEADERREAD:
+ {
+ /* If there were no headers, bail. */
+
+ if (hdr->buffer[0] == '\0')
+ {
+ hdr->state = CGI_OUTBUFFER_DONE;
+ return 1;
+ }
+
+ /* Figure out the status. Look for a Status: or Location: header; else if
+ * there's an HTTP header line, get it from there; else default to 200.
+ */
+
+ status = 200;
+ if (strncmp(hdr->buffer, "HTTP/", 5) == 0)
+ {
+ cp = hdr->buffer;
+ cp += strcspn(cp, " \t");
+ status = atoi(cp);
+ }
+
+ if ((cp = strstr(hdr->buffer, "Status:")) != NULL &&
+ cp < br && (cp == hdr->buffer || *(cp - 1) == '\012'))
+ {
+ cp += 7;
+ cp += strspn(cp, " \t");
+ status = atoi(cp);
+ }
+
+ if ((cp = strstr(hdr->buffer, "Location:")) != NULL &&
+ cp < br && (cp == hdr->buffer || *(cp - 1) == '\012'))
+ {
+ status = 302;
+ }
+
+ /* Write the status line. */
+
+ nvdbg("Status: %d\n", status);
+ switch (status)
+ {
+ case 200:
+ title = ok200title;
+ break;
+
+ case 302:
+ title = err302title;
+ break;
+
+ case 304:
+ title = err304title;
+ break;
+
+ case 400:
+ BADREQUEST("status");
+ title = httpd_err400title;
+ break;
+
+#ifdef CONFIG_THTTPD_AUTH_FILE
+ case 401:
+ title = err401title;
+ break;
+#endif
+
+ case 403:
+ title = err403title;
+ break;
+
+ case 404:
+ title = err404title;
+ break;
+
+ case 408:
+ title = httpd_err408title;
+ break;
+
+ case 500:
+ INTERNALERROR("status");
+ title = err500title;
+ break;
+
+ case 501:
+ NOTIMPLEMENTED("status");
+ title = err501title;
+ break;
+
+ case 503:
+ title = httpd_err503title;
+ break;
+
+ default:
+ title = "Something";
+ break;
+ }
+
+ (void)snprintf(inbuffer, sizeof(inbuffer), "HTTP/1.0 %d %s\r\n", status, title);
+ (void)httpd_write(hc->conn_fd, inbuffer, strlen(inbuffer));
+
+ /* Write the saved hdr->buffer to the client. */
+
+ (void)httpd_write(hc->conn_fd, hdr->buffer, hdr->len);
+ }
+
+ /* Then set up to read the data following the header from the CGI program and
+ * pass it back to the client. We return now; we will be called again when
+ * data is available on the pipe.
+ */
+
+ hdr->state = CGI_OUTBUFFER_READDATA;
+ return 0;
+
+ case CGI_OUTBUFFER_READDATA:
+ {
+ /* Read data from the pipe. */
+
+ do
+ {
+ /* Read until we successfully read data or until an error occurs.
+ * EAGAIN is not an error, but it is still cause to return.
+ */
+
+ nbytes_read = read(rfd, inbuffer, sizeof(inbuffer));
+ nvdbg("Read %d bytes from fd %d\n", nbytes_read, rfd);
+
+ if (nbytes_read < 0)
+ {
+ if (errno != EINTR)
+ {
+ if (errno != EAGAIN)
+ {
+ ndbg("read: %d\n", errno);
+ }
+ return 1;
+ }
+ }
+ }
+ while (nbytes_read < 0);
+
+ /* Check for end of file */
+
+ if (nbytes_read == 0)
+ {
+ nvdbg("End-of-file\n");
+ close(hc->conn_fd);
+ close(rfd);
+ hdr->state = CGI_OUTBUFFER_DONE;
+ return 1;
+ }
+ else
+ {
+ /* Forward the data from the CGI program to the client */
+
+ (void)httpd_write(hc->conn_fd, inbuffer, strlen(inbuffer));
+ }
+ }
+ break;
+
+ case CGI_OUTBUFFER_DONE:
+ default:
+ return 1;
+ }
+ return 0;
+}
+
+/* CGI child task. */
+
+static int cgi_child(int argc, char **argv)
+{
+ FAR httpd_conn *hc = (FAR httpd_conn*)strtoul(argv[1], NULL, 16);
+#if CONFIG_THTTPD_CGI_TIMELIMIT > 0
+ ClientData client_data;
+#endif
+ FAR char **argp;
+ struct cgi_outbuffer_s hdr;
+ struct fdwatch_s *fw;
+ char *buffer;
+ char *binary;
+ char *directory;
+ boolean indone;
+ boolean outdone;
+ int child;
+ int pipefd[2];
+ int wfd = -1;
+ int rfd = -1;
+ int fd;
+ int ret;
+ int err = 1;
+
+ /* Use low-level debug out (because the low-level output may survive closing
+ * all file descriptors
+ */
+
+ nllvdbg("Started: %s\n", argv[1]);
+
+ /* Update all of the environment variable settings, these will be inherited
+ * by the CGI task.
+ */
+
+ create_environment(hc);
+
+ /* Make the argument vector. */
+
+ argp = make_argp(hc);
+
+ /* Close all file descriptors (including stdio, stdin, stdout) EXCEPT for
+ * stderr and hc->conn_fd
+ */
+
+ nllvdbg("Closing all descriptors\n");
+ for (fd = 0; fd < (CONFIG_NFILE_DESCRIPTORS + CONFIG_NSOCKET_DESCRIPTORS); fd++)
+ {
+ /* Keep stderr open for debug; keep hc->conn_fd open for obvious reasons */
+
+ if (fd != 2 && fd != hc->conn_fd)
+ {
+ close(fd);
+ }
+ }
+
+ /* Create pipes that will be interposed between the CGI task's stdin or
+ * stdout and the socket.
+ *
+ * Setup up the STDIN pipe - a pipe to transfer data received on the
+ * socket to the CGI program.
+ */
+
+ nllvdbg("Create STDIN pipe\n");
+ ret = pipe(pipefd);
+ if (ret < 0)
+ {
+ nlldbg("STDIN pipe: %d\n", errno);
+ goto errout_with_descriptors;
+ }
+ else
+ {
+ /* Then map the receiving end the pipe to stdin, save the sending end, and
+ * closing the original receiving end
+ */
+
+ ret = dup2(pipefd[0], 0);
+ if (ret < 0)
+ {
+ nlldbg("STDIN dup2: %d\n", errno);
+ close(pipefd[1]);
+ goto errout_with_descriptors;
+ }
+
+ wfd = pipefd[1];
+ close(pipefd[0]);
+ }
+
+ /* Set up the STDOUT pipe - a pipe to transfer data received from the CGI program
+ * to the client.
+ */
+
+ if (ret == 0)
+ {
+ nllvdbg("Create STDOUT pipe\n");
+ ret = pipe(pipefd);
+ if (ret < 0)
+ {
+ nlldbg("STDOUT pipe: %d\n", errno);
+ goto errout_with_descriptors;
+ }
+ else
+ {
+ /* Then map the sending end the pipe to stdout, save the receiving end, and
+ * closing the original sending end
+ */
+
+ ret = dup2(pipefd[1], 1);
+ if (ret < 0)
+ {
+ nlldbg("STDOUT dup2: %d\n", errno);
+ close(pipefd[1]);
+ goto errout_with_descriptors;
+ }
+
+ rfd = pipefd[0];
+ close(pipefd[1]);
+ }
+ }
+
+ /* Split the program into directory and binary, so we can chdir() to the
+ * program's own directory. This isn't in the CGI 1.1 spec, but it's what
+ * other HTTP servers do.
+ */
+
+ directory = strdup(hc->expnfilename);
+ if (!directory)
+ {
+ binary = hc->expnfilename; /* ignore errors */
+ }
+ else
+ {
+ binary = strrchr(directory, '/');
+ if (!binary)
+ {
+ binary = hc->expnfilename;
+ }
+ else
+ {
+ *binary++ = '\0';
+ (void)chdir(directory); /* ignore errors */
+ }
+ }
+
+ /* Allocate memory for buffering */
+
+ memset(&hdr, 0, sizeof(struct cgi_outbuffer_s));
+ httpd_realloc_str(&hdr.buffer, &hdr.size, 500);
+ if (!hdr.buffer)
+ {
+ nlldbg("hdr allocation failed\n");
+ goto errout_with_descriptors;
+ }
+
+ buffer = (char*)httpd_malloc(CONFIG_THTTPD_IOBUFFERSIZE);
+ if (!buffer)
+ {
+ nlldbg("buffer allocation failed\n");
+ goto errout_with_header;
+ }
+
+ /* Create fdwatch structures */
+
+ fw = fdwatch_initialize(2);
+ if (!fw)
+ {
+ nlldbg("fdwatch allocation failed\n");
+ goto errout_with_buffer;
+ }
+
+ /* Run the CGI program. */
+
+ nllvdbg("Starting CGI\n");
+ child = exec(binary, (FAR const char **)argp, g_thttpdsymtab, g_thttpdnsymbols);
+ if (child < 0)
+ {
+ /* Something went wrong. */
+
+ nlldbg("execve %s: %d\n", hc->expnfilename, errno);
+ goto errout_with_watch;
+ }
+
+ /* Schedule a kill for the child task in case it runs too long. */
+
+#if CONFIG_THTTPD_CGI_TIMELIMIT > 0
+ client_data.i = child;
+ if (tmr_create(NULL, cgi_kill, client_data, CONFIG_THTTPD_CGI_TIMELIMIT * 1000L, 0) == NULL)
+ {
+ nlldbg("tmr_create(cgi_kill child) failed\n");
+ goto errout_with_watch;
+ }
+#endif
+
+ /* Add the read descriptors to the watch */
+
+ fdwatch_add_fd(fw, hc->conn_fd, NULL);
+ fdwatch_add_fd(fw, rfd, NULL);
+
+ /* Then perform the interposition */
+
+ indone = FALSE;
+ outdone = FALSE;
+
+ nllvdbg("Interposing\n");
+ do
+ {
+ (void)fdwatch(fw, 5000);
+
+ if (!indone && fdwatch_check_fd(fw, hc->conn_fd))
+ {
+ /* Transfer data from the client to the CGI program (POST) */
+
+ nllvdbg("Interpose input\n");
+ indone = cgi_interpose_input(hc, wfd, buffer);
+ if (indone)
+ {
+ fdwatch_del_fd(fw, hc->conn_fd);
+ }
+ }
+
+ if (fdwatch_check_fd(fw, rfd))
+ {
+ /* Handle receipt of headers and CGI program response (GET) */
+
+ nllvdbg("Interpose output\n");
+ outdone = cgi_interpose_output(hc, rfd, buffer, &hdr);
+ }
+ }
+ while (!outdone);
+ err = 0;
+
+ /* Get rid of watch structures */
+
+errout_with_watch:
+ fdwatch_uninitialize(fw);
+
+ /* Free memory */
+
+errout_with_buffer:
+ httpd_free(buffer);
+errout_with_header:
+ httpd_free(hdr.buffer);
+
+ /* Close all descriptors */
+
+errout_with_descriptors:
+ close(wfd);
+ close(rfd);
+ close(hc->conn_fd);
+
+ INTERNALERROR("errout");
+ httpd_send_err(hc, 500, err500title, "", err500form, hc->encodedurl);
+ httpd_write_response(hc);
+ nllvdbg("Return %d\n", ret);
+ return err;
+}
+
+/****************************************************************************
+ * Private Function Prototypes
+ ****************************************************************************/
+
+int cgi(httpd_conn *hc)
+{
+ char arg[16];
+ char *argv[1];
+ pid_t child;
+
+ if (hc->method == METHOD_GET || hc->method == METHOD_POST)
+ {
+#ifdef CONFIG_THTTPD_CGILIMIT
+ if (hc->hs->cgi_count >= CONFIG_THTTPD_CGILIMIT)
+ {
+ httpd_send_err(hc, 503, httpd_err503title, "", httpd_err503form,
+ hc->encodedurl);
+ return -1;
+ }
+#endif
+ ++hc->hs->cgi_count;
+ httpd_clear_ndelay(hc->conn_fd);
+
+ /* Start the child task. We use a trampoline task here so that we can
+ * safely muck with the file descriptors before actually started the CGI
+ * task.
+ */
+
+ snprintf(arg, 16, "%p", hc); /* task_create doesn't handle binary arguments. */
+ argv[0] = arg;
+
+#ifndef CONFIG_CUSTOM_STACK
+ child = task_create("CGI child", CONFIG_THTTPD_CGI_PRIORITY,
+ CONFIG_THTTPD_CGI_STACKSIZE,
+ (main_t)cgi_child, (const char **)argv);
+#else
+ child = task_create("CGI child", CONFIG_THTTPD_CGI_PRIORITY,
+ (main_t)cgi_child, (const char **)argv);
+#endif
+ if (child < 0)
+ {
+ ndbg("task_create: %d\n", errno);
+ INTERNALERROR("task_create");
+ httpd_send_err(hc, 500, err500title, "", err500form, hc->encodedurl);
+ return -1;
+ }
+
+ ndbg("Started CGI task %d for file '%s'\n", child, hc->expnfilename);
+
+ hc->status = 200;
+ hc->bytes_sent = CONFIG_THTTPD_CGI_BYTECOUNT;
+ hc->should_linger = FALSE;
+ }
+ else
+ {
+ NOTIMPLEMENTED("CGI");
+ httpd_send_err(hc, 501, err501title, "", err501form, httpd_method_str(hc->method));
+ return -1;
+ }
+
+ return 0;
+}
+
+#endif /* CONFIG_THTTPD && CONFIG_THTTPD_CGI_PATTERN */
\ No newline at end of file diff --git a/nuttx/netutils/thttpd/thttpd_cgi.h b/nuttx/netutils/thttpd/thttpd_cgi.h new file mode 100755 index 000000000..2d12d7269 --- /dev/null +++ b/nuttx/netutils/thttpd/thttpd_cgi.h @@ -0,0 +1,59 @@ +/****************************************************************************
+ * netutils/thttpd/thttpd_cgi.h
+ * CGI support
+ *
+ * Copyright (C) 2009 Gregory Nutt. All rights reserved.
+ * Author: Gregory Nutt <spudmonkey@racsa.co.cr>
+ *
+ * Derived from the file libhttpd.c in the original THTTPD package:
+ *
+ * Copyright © 1995,1998,1999,2000,2001 by Jef Poskanzer <jef@mail.acme.com>.
+ * 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.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR 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 AUTHOR 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.
+ *
+ ****************************************************************************/
+
+#ifndef __HTTPD_CGI_H
+#define __HTTPD_CGI_H
+
+/****************************************************************************
+ * Included Files
+ ****************************************************************************/
+
+#include <nuttx/config.h>
+#include <sys/types.h>
+
+#include "config.h"
+#include "libhttpd.h"
+
+#if defined(CONFIG_THTTPD) && defined(CONFIG_THTTPD_CGI_PATTERN)
+
+/****************************************************************************
+ * Public Function Prototypes
+ ****************************************************************************/
+
+extern int cgi(httpd_conn *hc);
+
+#endif /* CONFIG_THTTPD && CONFIG_THTTPD_CGI_PATTERN */
+#endif /* __HTTPD_CGI_H */
diff --git a/nuttx/netutils/thttpd/thttpd_strings.c b/nuttx/netutils/thttpd/thttpd_strings.c new file mode 100755 index 000000000..591f15665 --- /dev/null +++ b/nuttx/netutils/thttpd/thttpd_strings.c @@ -0,0 +1,179 @@ +/****************************************************************************
+ * netutils/thttpd/thttpd_strings.c
+ * HTTP strings
+ *
+ * Copyright (C) 2009 Gregory Nutt. All rights reserved.
+ * Author: Gregory Nutt <spudmonkey@racsa.co.cr>
+ *
+ * Derived from the file of the same name in the original THTTPD package:
+ *
+ * Copyright © 1995,1998,1999,2000,2001 by Jef Poskanzer <jef@mail.acme.com>.
+ * 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.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR 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 AUTHOR 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.
+ *
+ ****************************************************************************/
+
+/****************************************************************************
+ * Included Files
+ ****************************************************************************/
+
+#include <nuttx/config.h>
+
+#include <stdio.h>
+#include <string.h>
+#include <ctype.h>
+
+#include "config.h"
+#include "thttpd_strings.h"
+
+#ifdef CONFIG_THTTPD
+
+/****************************************************************************
+ * Public Data
+ ****************************************************************************/
+
+/* This is the 'root' of the Filesystem as seen by the HTTP client */
+
+const char httpd_root[] = CONFIG_THTTPD_PATH;
+
+/* HTPP status */
+
+const char ok200title[] = "OK";
+const char ok206title[] = "Partial Content";
+
+const char err302title[] = "Found";
+const char err302form[] = "The actual URL is '%s'.\n";
+
+const char err304title[] = "Not Modified";
+
+const char httpd_err400title[] = "Bad Request";
+const char httpd_err400form[] = "Your request has bad syntax or is inherently impossible to satisfy.\n";
+
+#ifdef CONFIG_THTTPD_AUTH_FILE
+const char err401title[] = "Unauthorized";
+const char err401form[] = "Authorization required for the URL '%s'.\n";
+#endif
+
+const char err403title[] = "Forbidden";
+#ifndef EXPLICIT_ERROR_PAGES
+const char err403form[] = "You do not have permission to get URL '%s' from this server.\n";
+#endif
+
+const char err404title[] = "Not Found";
+const char err404form[] = "The requested URL '%s' was not found on this server.\n";
+
+const char httpd_err408title[] = "Request Timeout";
+const char httpd_err408form[] = "No request appeared within a reasonable time period.\n";
+
+const char err500title[] = "Internal Error";
+const char err500form[] = "There was an unusual problem serving the requested URL '%s'.\n";
+
+const char err501title[] = "Not Implemented";
+const char err501form[] = "The requested method '%s' is not implemented by this server.\n";
+
+const char httpd_err503title[] = "Service Temporarily Overloaded";
+const char httpd_err503form[] = "The requested URL '%s' is temporarily overloaded. Please try again later.\n";
+
+/* HTML strings */
+
+const char html_crlf[] = "\r\n";
+const char html_html[] = "<HTML>\r\n";
+const char html_endhtml[] = "</HTML>\r\n";
+const char html_hdtitle[] = "<HEAD><TITLE>";
+const char html_titlehd[] = "</TITLE></HEAD>\r\n";
+const char html_body[] = "<BODY BGCOLOR=\"#99cc99\" TEXT=\"#000000\" LINK=\"#2020ff\" VLINK=\"#4040cc\">\r\n";
+const char html_endbody[] = "</BODY>\r\n";
+const char html_hdr2[] = "<H2>";
+const char html_endhdr2[] = "</H2>";
+
+/****************************************************************************
+ * Private Functions
+ ****************************************************************************/
+
+static int hexit(char nibble)
+{
+ if (nibble >= '0' && nibble <= '9')
+ {
+ return nibble - '0';
+ }
+ else if (nibble >= 'a' && nibble <= 'f')
+ {
+ return nibble - 'a' + 10;
+ }
+ else if (nibble >= 'A' && nibble <= 'F')
+ {
+ return nibble - 'A' + 10;
+ }
+ return 0;
+}
+
+/****************************************************************************
+ * Public Functions
+ ****************************************************************************/
+
+/* Copies and decodes a string. It's ok for from and to to be the same string. */
+
+void httpd_strdecode(char *to, char *from)
+{
+ for (; *from != '\0'; ++to, ++from)
+ {
+ if (from[0] == '%' && isxdigit(from[1]) && isxdigit(from[2]))
+ {
+ *to = hexit(from[1]) * 16 + hexit(from[2]);
+ from += 2;
+ }
+ else
+ {
+ *to = *from;
+ }
+ }
+ *to = '\0';
+}
+
+/* Copies and encodes a string. */
+
+#ifdef CONFIG_THTTPD_GENERATE_INDICES
+static void httpd_strencode(char *to, int tosize, char *from)
+{
+ int tolen;
+
+ for (tolen = 0; *from != '\0' && tolen + 4 < tosize; ++from)
+ {
+ if (isalnum(*from) || strchr("/_.-~", *from) != NULL)
+ {
+ *to = *from;
+ ++to;
+ ++tolen;
+ }
+ else
+ {
+ (void)sprintf(to, "%%%02x", (int)*from & 0xff);
+ to += 3;
+ tolen += 3;
+ }
+ }
+ *to = '\0';
+}
+#endif /* CONFIG_THTTPD_GENERATE_INDICES */
+#endif /* CONFIG_THTTPD */
\ No newline at end of file diff --git a/nuttx/netutils/thttpd/thttpd_strings.h b/nuttx/netutils/thttpd/thttpd_strings.h new file mode 100755 index 000000000..dbd22e4e0 --- /dev/null +++ b/nuttx/netutils/thttpd/thttpd_strings.h @@ -0,0 +1,119 @@ +/****************************************************************************
+ * netutils/thttpd/thttpd_strings.h
+ * HTTP strings
+ *
+ * Copyright (C) 2009 Gregory Nutt. All rights reserved.
+ * Author: Gregory Nutt <spudmonkey@racsa.co.cr>
+ *
+ * Derived from the file of the same name in the original THTTPD package:
+ *
+ * Copyright © 1995,1998,1999,2000,2001 by Jef Poskanzer <jef@mail.acme.com>.
+ * 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.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR 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 AUTHOR 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.
+ *
+ ****************************************************************************/
+
+/****************************************************************************
+ * Included Files
+ ****************************************************************************/
+
+#include <nuttx/config.h>
+
+#include "config.h"
+
+#ifdef CONFIG_THTTPD
+
+/****************************************************************************
+ * Public Data
+ ****************************************************************************/
+
+/* This is the 'root' of the Filesystem as seen by the HTTP client */
+
+extern const char httpd_root[];
+
+/* HTPP status */
+
+extern const char ok200title[];
+extern const char ok206title[];
+
+extern const char err302title[];
+extern const char err302form[];
+
+extern const char err304title[];
+
+extern const char httpd_err400title[];
+extern const char httpd_err400form[];
+
+#ifdef CONFIG_THTTPD_AUTH_FILE
+extern const char err401title[];
+extern const char err401form[];
+#endif
+
+extern const char err403title[];
+#ifndef EXPLICIT_ERROR_PAGES
+extern const char err403form[];
+#endif
+
+extern const char err404title[];
+extern const char err404form[];
+
+extern const char httpd_err408title[];
+extern const char httpd_err408form[];
+
+extern const char err500title[];
+extern const char err500form[];
+
+extern const char err501title[];
+extern const char err501form[];
+
+extern const char httpd_err503title[];
+extern const char httpd_err503form[];
+
+/* HTML strings */
+
+extern const char html_crlf[];
+extern const char html_html[];
+extern const char html_endhtml[];
+extern const char html_hdtitle[];
+extern const char html_titlehd[];
+extern const char html_body[];
+extern const char html_endbody[];
+extern const char html_hdr2[];
+extern const char html_endhdr2[];
+
+/****************************************************************************
+ * Public Functions
+ ****************************************************************************/
+
+/* Copies and decodes a string. It's ok for from and to to be the same string. */
+
+extern void httpd_strdecode(char *to, char *from);
+
+/* Copies and encodes a string. */
+
+#ifdef CONFIG_THTTPD_GENERATE_INDICES
+extern void httpd_strencode(char *to, int tosize, char *from);
+#endif
+
+#endif /* CONFIG_THTTPD */
\ No newline at end of file diff --git a/nuttx/netutils/thttpd/timers.c b/nuttx/netutils/thttpd/timers.c index e03570f6a..7e67e6cbe 100644 --- a/nuttx/netutils/thttpd/timers.c +++ b/nuttx/netutils/thttpd/timers.c @@ -45,7 +45,7 @@ #include <stdio.h> #include <debug.h> -#include "httpd_alloc.h" +#include "thttpd_alloc.h" #include "timers.h" /**************************************************************************** |