summaryrefslogtreecommitdiff
path: root/nuttx/netutils
diff options
context:
space:
mode:
authorpatacongo <patacongo@42af7a65-404d-4744-a932-0658087f49c3>2009-09-15 19:48:13 +0000
committerpatacongo <patacongo@42af7a65-404d-4744-a932-0658087f49c3>2009-09-15 19:48:13 +0000
commitfdc11d13043299e79dcd88c4269a2f56f2e565d9 (patch)
tree8f40228885950a06e103dd33b2e8625f1b7611c1 /nuttx/netutils
parent24dc19ee6caa08a5c67b4cfa519632b3ec17c085 (diff)
downloadpx4-nuttx-fdc11d13043299e79dcd88c4269a2f56f2e565d9.tar.gz
px4-nuttx-fdc11d13043299e79dcd88c4269a2f56f2e565d9.tar.bz2
px4-nuttx-fdc11d13043299e79dcd88c4269a2f56f2e565d9.zip
CGI needs to copy httpd_conn because it is volatile
git-svn-id: svn://svn.code.sf.net/p/nuttx/code/trunk@2058 42af7a65-404d-4744-a932-0658087f49c3
Diffstat (limited to 'nuttx/netutils')
-rw-r--r--nuttx/netutils/thttpd/config.h8
-rwxr-xr-xnuttx/netutils/thttpd/thttpd_cgi.c281
2 files changed, 172 insertions, 117 deletions
diff --git a/nuttx/netutils/thttpd/config.h b/nuttx/netutils/thttpd/config.h
index 213a1fa2c..dbbddaec2 100644
--- a/nuttx/netutils/thttpd/config.h
+++ b/nuttx/netutils/thttpd/config.h
@@ -156,6 +156,14 @@
# define CONFIG_THTTPD_MAXREALLOC 4096
# endif
+# ifndef CONFIG_THTTPD_CGIINBUFFERSIZE
+# define CONFIG_THTTPD_CGIINBUFFERSIZE 512 /* Size of buffer to interpose input */
+# endif
+
+# ifndef CONFIG_THTTPD_CGIOUTBUFFERSIZE
+# define CONFIG_THTTPD_CGIOUTBUFFERSIZE 512 /* Size of buffer to interpose output */
+# endif
+
# if CONFIG_THTTPD_IOBUFFERSIZE > 65535
# error "Can't use uint16 for buffer size"
# endif
diff --git a/nuttx/netutils/thttpd/thttpd_cgi.c b/nuttx/netutils/thttpd/thttpd_cgi.c
index 8a2125a9e..27ec2a267 100755
--- a/nuttx/netutils/thttpd/thttpd_cgi.c
+++ b/nuttx/netutils/thttpd/thttpd_cgi.c
@@ -67,6 +67,14 @@
* Pre-processor Definitions
****************************************************************************/
+/* CONFIG_THTTPD_CGIDUMP will dump the contents of each transfer to and from the CGI task. */
+
+#ifdef CONFIG_THTTPD_CGIDUMP
+# define cgi_dumppacket(m,a,n) lib_dumpbuffer(m,a,n)
+#else
+# define cgi_dumppacket(m,a,n)
+#endif
+
/****************************************************************************
* Private Types
****************************************************************************/
@@ -88,15 +96,35 @@ struct cgi_outbuffer_s
size_t len; /* Amount of valid data in the allocated buffer */
};
+struct cgi_inbuffer_s
+{
+ int contentlength; /* Size of content to send to CGI task */
+ int nbytes; /* Number of bytes sent */
+ char buffer[CONFIG_THTTPD_CGIINBUFFERSIZE]; /* Fixed size input buffer */
+};
+
+struct cgi_conn_s
+{
+ /* Descriptors */
+
+ int connfd; /* Socket connect to CGI client */
+ int rdfd; /* Pipe read fd */
+ int wrfd; /* Pipe write fd */
+
+ /* Buffering */
+
+ struct cgi_outbuffer_s outbuf; /* Dynamically sized output buffer */
+ struct cgi_inbuffer_s inbuf; /* Fixed size input 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 inline int cgi_interpose_input(struct cgi_conn_s *cc);
+static inline int cgi_interpose_output(struct cgi_conn_s *cc);
static int cgi_child(int argc, char **argv);
/****************************************************************************
@@ -329,28 +357,18 @@ static FAR char **make_argp(httpd_conn *hc)
* 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)
+static inline int cgi_interpose_input(struct cgi_conn_s *cc)
{
- size_t nbytes;
ssize_t nbytes_read;
ssize_t nbytes_written;
- nbytes = hc->read_idx - hc->checked_idx;
- llvdbg("nbytes: %d contentlength: %d\n", nbytes, hc->contentlength);
- if (nbytes > 0)
- {
- if (httpd_write(wfd, &(hc->read_buf[hc->checked_idx]), nbytes) != nbytes)
- {
- lldbg("httpd_write failed\n");
- return 1;
- }
- }
-
- if (nbytes < hc->contentlength)
+ llvdbg("nbytes: %d contentlength: %d\n", cc->inbuf.nbytes, cc->inbuf.contentlength);
+ if (cc->inbuf.nbytes < cc->inbuf.contentlength)
{
do
{
- nbytes_read = read(hc->conn_fd, buffer, MIN(sizeof(buffer), hc->contentlength - nbytes));
+ nbytes_read = read(cc->connfd, cc->inbuf.buffer,
+ MIN(CONFIG_THTTPD_CGIINBUFFERSIZE, cc->inbuf.contentlength - cc->inbuf.nbytes));
llvdbg("nbytes_read: %d\n", nbytes_read);
if (nbytes_read < 0)
{
@@ -365,17 +383,20 @@ static inline int cgi_interpose_input(httpd_conn *hc, int wfd, char *buffer)
if (nbytes_read > 0)
{
- nbytes_written = httpd_write(wfd, buffer, nbytes_read);
+ nbytes_written = httpd_write(cc->wrfd, cc->inbuf.buffer, nbytes_read);
llvdbg("nbytes_written: %d\n", nbytes_written);
if (nbytes_written != nbytes_read)
{
lldbg("httpd_write failed\n");
return 1;
}
+ cgi_dumppacket("Sent to CGI:", cc->inbuf.buffer, nbytes_written);
}
+
+ cc->inbuf.nbytes += nbytes_read;
}
- if (nbytes >= hc->contentlength)
+ if (cc->inbuf.nbytes >= cc->inbuf.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
@@ -388,11 +409,11 @@ static inline int cgi_interpose_input(httpd_conn *hc, int wfd, char *buffer)
/* Turn on no-delay mode in case we previously cleared it. */
- httpd_set_ndelay(hc->conn_fd);
+ httpd_set_ndelay(cc->connfd);
/* And read up to 2 bytes. */
- (void)read(hc->conn_fd, buffer, sizeof(buffer));
+ (void)read(cc->connfd, cc->inbuf.buffer, CONFIG_THTTPD_CGIINBUFFERSIZE);
return 1;
}
return 0;
@@ -406,8 +427,7 @@ static inline int cgi_interpose_input(httpd_conn *hc, int wfd, char *buffer)
* 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)
+static inline int cgi_interpose_output(struct cgi_conn_s *cc)
{
ssize_t nbytes_read;
char *br = NULL;
@@ -419,12 +439,12 @@ static inline int cgi_interpose_output(httpd_conn *hc, int rfd, char *inbuffer,
* blocking, but we might as well be sure.
*/
- httpd_clear_ndelay(hc->conn_fd);
+ httpd_clear_ndelay(cc->connfd);
/* Loop while there are things we can do without waiting for more input */
- llvdbg("state: %d\n", hdr->state);
- switch (hdr->state)
+ llvdbg("state: %d\n", cc->outbuf.state);
+ switch (cc->outbuf.state)
{
case CGI_OUTBUFFER_READHEADER:
{
@@ -436,8 +456,8 @@ static inline int cgi_interpose_output(httpd_conn *hc, int rfd, char *inbuffer,
* EAGAIN is not an error, but it is still cause to return.
*/
- nbytes_read = read(hc->conn_fd, inbuffer, sizeof(inbuffer));
- nllvdbg("Read %d bytes from fd %d\n", nbytes_read, hc->conn_fd);
+ nbytes_read = read(cc->rdfd, cc->inbuf.buffer, CONFIG_THTTPD_CGIINBUFFERSIZE);
+ nllvdbg("Read %d bytes from fd %d\n", nbytes_read, cc->rdfd);
if (nbytes_read < 0)
{
@@ -450,6 +470,10 @@ static inline int cgi_interpose_output(httpd_conn *hc, int rfd, char *inbuffer,
return 1;
}
}
+ else
+ {
+ cgi_dumppacket("Received from CGI:", cc->inbuf.buffer, nbytes_read);
+ }
}
while (nbytes_read < 0);
@@ -458,26 +482,26 @@ static inline int cgi_interpose_output(httpd_conn *hc, int rfd, char *inbuffer,
if (nbytes_read <= 0)
{
nllvdbg("End-of-file\n");
- br = &(hdr->buffer[hdr->len]);
- hdr->state = CGI_OUTBUFFER_HEADERREAD;
+ br = &(cc->outbuf.buffer[cc->outbuf.len]);
+ cc->outbuf.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';
- nllvdbg("Header bytes accumulated: %d\n", hdr->len);
+ httpd_realloc_str(&cc->outbuf.buffer, &cc->outbuf.size, cc->outbuf.len + nbytes_read);
+ (void)memcpy(&(cc->outbuf.buffer[cc->outbuf.len]), cc->inbuf.buffer, nbytes_read);
+ cc->outbuf.len += nbytes_read;
+ cc->outbuf.buffer[cc->outbuf.len] = '\0';
+ nllvdbg("Header bytes accumulated: %d\n", cc->outbuf.len);
/* Check for end of header */
- if ((br = strstr(hdr->buffer, "\r\n\r\n")) != NULL ||
- (br = strstr(hdr->buffer, "\012\012")) != NULL)
+ if ((br = strstr(cc->outbuf.buffer, "\r\n\r\n")) != NULL ||
+ (br = strstr(cc->outbuf.buffer, "\012\012")) != NULL)
{
nllvdbg("End-of-header\n");
- hdr->state = CGI_OUTBUFFER_HEADERREAD;
+ cc->outbuf.state = CGI_OUTBUFFER_HEADERREAD;
}
else
{
@@ -495,9 +519,9 @@ static inline int cgi_interpose_output(httpd_conn *hc, int rfd, char *inbuffer,
{
/* If there were no headers, bail. */
- if (hdr->buffer[0] == '\0')
+ if (cc->outbuf.buffer[0] == '\0')
{
- hdr->state = CGI_OUTBUFFER_DONE;
+ cc->outbuf.state = CGI_OUTBUFFER_DONE;
return 1;
}
@@ -506,23 +530,23 @@ static inline int cgi_interpose_output(httpd_conn *hc, int rfd, char *inbuffer,
*/
status = 200;
- if (strncmp(hdr->buffer, "HTTP/", 5) == 0)
+ if (strncmp(cc->outbuf.buffer, "HTTP/", 5) == 0)
{
- cp = hdr->buffer;
- cp += strcspn(cp, " \t");
+ cp = cc->outbuf.buffer;
+ cp += strcspn(cp, " \t");
status = atoi(cp);
}
- if ((cp = strstr(hdr->buffer, "Status:")) != NULL &&
- cp < br && (cp == hdr->buffer || *(cp - 1) == '\012'))
+ if ((cp = strstr(cc->outbuf.buffer, "Status:")) != NULL &&
+ cp < br && (cp == cc->outbuf.buffer || *(cp - 1) == '\012'))
{
- cp += 7;
- cp += strspn(cp, " \t");
+ cp += 7;
+ cp += strspn(cp, " \t");
status = atoi(cp);
}
- if ((cp = strstr(hdr->buffer, "Location:")) != NULL &&
- cp < br && (cp == hdr->buffer || *(cp - 1) == '\012'))
+ if ((cp = strstr(cc->outbuf.buffer, "Location:")) != NULL &&
+ cp < br && (cp == cc->outbuf.buffer || *(cp - 1) == '\012'))
{
status = 302;
}
@@ -586,12 +610,12 @@ static inline int cgi_interpose_output(httpd_conn *hc, int rfd, char *inbuffer,
break;
}
- (void)snprintf(inbuffer, sizeof(inbuffer), "HTTP/1.0 %d %s\r\n", status, title);
- (void)httpd_write(hc->conn_fd, inbuffer, strlen(inbuffer));
+ (void)snprintf(cc->inbuf.buffer, CONFIG_THTTPD_CGIINBUFFERSIZE, "HTTP/1.0 %d %s\r\n", status, title);
+ (void)httpd_write(cc->connfd, cc->inbuf.buffer, strlen(cc->inbuf.buffer));
- /* Write the saved hdr->buffer to the client. */
+ /* Write the saved cc->outbuf.buffer to the client. */
- (void)httpd_write(hc->conn_fd, hdr->buffer, hdr->len);
+ (void)httpd_write(cc->connfd, cc->outbuf.buffer, cc->outbuf.len);
}
/* Then set up to read the data following the header from the CGI program and
@@ -599,7 +623,7 @@ static inline int cgi_interpose_output(httpd_conn *hc, int rfd, char *inbuffer,
* data is available on the pipe.
*/
- hdr->state = CGI_OUTBUFFER_READDATA;
+ cc->outbuf.state = CGI_OUTBUFFER_READDATA;
return 0;
case CGI_OUTBUFFER_READDATA:
@@ -612,8 +636,8 @@ static inline int cgi_interpose_output(httpd_conn *hc, int rfd, char *inbuffer,
* EAGAIN is not an error, but it is still cause to return.
*/
- nbytes_read = read(rfd, inbuffer, sizeof(inbuffer));
- nllvdbg("Read %d bytes from fd %d\n", nbytes_read, rfd);
+ nbytes_read = read(cc->rdfd, cc->inbuf.buffer, CONFIG_THTTPD_CGIINBUFFERSIZE);
+ nllvdbg("Read %d bytes from fd %d\n", nbytes_read, cc->rdfd);
if (nbytes_read < 0)
{
@@ -634,16 +658,16 @@ static inline int cgi_interpose_output(httpd_conn *hc, int rfd, char *inbuffer,
if (nbytes_read == 0)
{
nllvdbg("End-of-file\n");
- close(hc->conn_fd);
- close(rfd);
- hdr->state = CGI_OUTBUFFER_DONE;
+ close(cc->connfd);
+ close(cc->rdfd);
+ cc->outbuf.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));
+ (void)httpd_write(cc->connfd, cc->inbuf.buffer, strlen(cc->inbuf.buffer));
}
}
break;
@@ -664,20 +688,18 @@ static int cgi_child(int argc, char **argv)
ClientData client_data;
#endif
FAR char **argp;
- struct cgi_outbuffer_s hdr;
- struct fdwatch_s *fw;
- char *buffer;
- char *directory;
- char *dupname;
- boolean indone;
- boolean outdone;
- int child;
- int pipefd[2];
- int wfd = -1;
- int rfd = -1;
- int fd;
- int ret;
- int err = 1;
+ FAR struct cgi_conn_s *cc;
+ FAR struct fdwatch_s *fw;
+ FAR char *directory;
+ FAR char *dupname;
+ boolean indone;
+ boolean outdone;
+ int child;
+ int pipefd[2];
+ int nbytes;
+ int fd;
+ int ret;
+ int err = 1;
/* Use low-level debug out (because the low-level output may survive closing
* all file descriptors
@@ -685,6 +707,21 @@ static int cgi_child(int argc, char **argv)
nllvdbg("Started: %s\n", argv[1]);
+ /* Allocate memory and initialize memory for interposing */
+
+ cc = (FAR struct cgi_conn_s*)httpd_malloc(sizeof(struct cgi_conn_s));
+ if (!cc)
+ {
+ nlldbg("cgi_conn allocation failed\n");
+ close(hc->conn_fd);
+ goto errout;
+ }
+
+ cc->connfd = hc->conn_fd;
+ cc->wrfd = -1;
+ cc->rdfd = -1;
+ memset(&cc->outbuf, 0, sizeof(struct cgi_outbuffer_s));
+
/* Update all of the environment variable settings, these will be inherited
* by the CGI task.
*/
@@ -724,7 +761,7 @@ static int cgi_child(int argc, char **argv)
if (ret < 0)
{
nlldbg("STDIN pipe: %d\n", errno);
- goto errout_with_descriptors;
+ goto errout_with_cgiconn;
}
else
{
@@ -733,15 +770,15 @@ static int cgi_child(int argc, char **argv)
*/
ret = dup2(pipefd[0], 0);
+
+ cc->wrfd = pipefd[1];
+ close(pipefd[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
@@ -764,15 +801,15 @@ static int cgi_child(int argc, char **argv)
*/
ret = dup2(pipefd[1], 1);
+
+ cc->rdfd = pipefd[0];
+ close(pipefd[1]);
+
if (ret < 0)
{
nlldbg("STDOUT dup2: %d\n", errno);
- close(pipefd[1]);
goto errout_with_descriptors;
}
-
- rfd = pipefd[0];
- close(pipefd[1]);
}
}
@@ -791,35 +828,27 @@ static int cgi_child(int argc, char **argv)
httpd_free(dupname);
}
- /* Allocate memory for buffering */
+ /* Allocate memory for output buffering */
- memset(&hdr, 0, sizeof(struct cgi_outbuffer_s));
- httpd_realloc_str(&hdr.buffer, &hdr.size, 500);
- if (!hdr.buffer)
+ httpd_realloc_str(&cc->outbuf.buffer, &cc->outbuf.size, CONFIG_THTTPD_CGIOUTBUFFERSIZE);
+ if (!cc->outbuf.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;
+ goto errout_with_outbuffer;
}
/* Run the CGI program. */
- nllvdbg("Starting CGI\n");
+ nllvdbg("Starting CGI: %s\n", hc->expnfilename);
child = exec(hc->expnfilename, (FAR const char **)argp, g_thttpdsymtab, g_thttpdnsymbols);
if (child < 0)
{
@@ -842,8 +871,24 @@ static int cgi_child(int argc, char **argv)
/* Add the read descriptors to the watch */
- fdwatch_add_fd(fw, hc->conn_fd, NULL);
- fdwatch_add_fd(fw, rfd, NULL);
+ fdwatch_add_fd(fw, cc->connfd, NULL);
+ fdwatch_add_fd(fw, cc->rdfd, NULL);
+
+ /* Send any data that is already buffer to the CGI task */
+
+ nbytes = hc->read_idx - hc->checked_idx;
+ llvdbg("nbytes: %d contentlength: %d\n", nbytes, hc->contentlength);
+ if (nbytes > 0)
+ {
+ if (httpd_write(cc->wrfd, &(hc->read_buf[hc->checked_idx]), nbytes) != nbytes)
+ {
+ lldbg("httpd_write failed\n");
+ return 1;
+ }
+ }
+
+ cc->inbuf.contentlength = hc->contentlength;
+ cc->inbuf.nbytes = nbytes;
/* Then perform the interposition */
@@ -851,29 +896,29 @@ static int cgi_child(int argc, char **argv)
outdone = FALSE;
nllvdbg("Interposing\n");
- cgi_semgive();
+ cgi_semgive(); /* Not safe to reference hc after this point */
do
{
(void)fdwatch(fw, 5000);
- if (!indone && fdwatch_check_fd(fw, hc->conn_fd))
+ if (!indone && fdwatch_check_fd(fw, cc->connfd))
{
/* Transfer data from the client to the CGI program (POST) */
nllvdbg("Interpose input\n");
- indone = cgi_interpose_input(hc, wfd, buffer);
+ indone = cgi_interpose_input(cc);
if (indone)
{
- fdwatch_del_fd(fw, hc->conn_fd);
+ fdwatch_del_fd(fw, cc->connfd);
}
}
- if (fdwatch_check_fd(fw, rfd))
+ if (fdwatch_check_fd(fw, cc->rdfd))
{
/* Handle receipt of headers and CGI program response (GET) */
nllvdbg("Interpose output\n");
- outdone = cgi_interpose_output(hc, rfd, buffer, &hdr);
+ outdone = cgi_interpose_output(cc);
}
}
while (!outdone);
@@ -884,27 +929,29 @@ static int cgi_child(int argc, char **argv)
errout_with_watch:
fdwatch_uninitialize(fw);
- /* Free memory */
+ /* Free output buffer memory */
-errout_with_buffer:
- httpd_free(buffer);
-errout_with_header:
- httpd_free(hdr.buffer);
+errout_with_outbuffer:
+ httpd_free(cc->outbuf.buffer);
/* Close all descriptors */
errout_with_descriptors:
- close(wfd);
- close(rfd);
- close(hc->conn_fd);
+ close(cc->wrfd);
+ close(cc->rdfd);
- INTERNALERROR("errout");
- httpd_send_err(hc, 500, err500title, "", err500form, hc->encodedurl);
- httpd_write_response(hc);
- nllvdbg("Return %d\n", ret);
+errout_with_cgiconn:
+ close(cc->connfd);
+ httpd_free(cc);
+errout:
+ nllvdbg("Return %d\n", err);
if (err != 0)
{
+ INTERNALERROR("errout");
+ httpd_send_err(hc, 500, err500title, "", err500form, hc->encodedurl);
+ httpd_write_response(hc);
+
cgi_semgive();
}
return err;