summaryrefslogtreecommitdiff
path: root/nuttx/netutils/webserver/httpd.c
diff options
context:
space:
mode:
authorpatacongo <patacongo@42af7a65-404d-4744-a932-0658087f49c3>2007-11-19 18:17:23 +0000
committerpatacongo <patacongo@42af7a65-404d-4744-a932-0658087f49c3>2007-11-19 18:17:23 +0000
commitbefc37ada0b901ad7c315e4089976508396d496b (patch)
tree44818265dc09577601c19bf81b3576109f31a534 /nuttx/netutils/webserver/httpd.c
parent6f5479c267e1ed09e85461464ae73b4cbfd3d486 (diff)
downloadpx4-nuttx-befc37ada0b901ad7c315e4089976508396d496b.tar.gz
px4-nuttx-befc37ada0b901ad7c315e4089976508396d496b.tar.bz2
px4-nuttx-befc37ada0b901ad7c315e4089976508396d496b.zip
uIP webserver now uses listen/accept
git-svn-id: svn://svn.code.sf.net/p/nuttx/code/trunk@386 42af7a65-404d-4744-a932-0658087f49c3
Diffstat (limited to 'nuttx/netutils/webserver/httpd.c')
-rw-r--r--nuttx/netutils/webserver/httpd.c218
1 files changed, 143 insertions, 75 deletions
diff --git a/nuttx/netutils/webserver/httpd.c b/nuttx/netutils/webserver/httpd.c
index 57e60f872..2db3436d7 100644
--- a/nuttx/netutils/webserver/httpd.c
+++ b/nuttx/netutils/webserver/httpd.c
@@ -45,11 +45,17 @@
* Included Files
****************************************************************************/
-#include <stdlib.h>
+#include <nuttx/config.h>
+
#include <sys/socket.h>
+
+#include <stdio.h>
+#include <stdlib.h>
#include <string.h>
+#include <debug.h>
#include <net/uip/uip.h>
+#include <net/uip/uip-lib.h>
#include <net/uip/httpd.h>
#include "httpd.h"
@@ -60,9 +66,6 @@
* Definitions
****************************************************************************/
-#define STATE_WAITING 0
-#define STATE_OUTPUT 1
-
#define ISO_nl 0x0a
#define ISO_space 0x20
#define ISO_bang 0x21
@@ -71,21 +74,50 @@
#define ISO_slash 0x2f
#define ISO_colon 0x3a
-#define SEND_STR(psock, str) psock_send(psock, str, strlen(str))
+#define CONFIG_NETUTILS_HTTPD_DUMPBUFFER 1
/****************************************************************************
* Private Functions
****************************************************************************/
-static inline int send_file(struct httpd_state *pstate)
+#ifdef CONFIG_NETUTILS_HTTPD_DUMPBUFFER
+static void httpd_dumpbuffer(struct httpd_state *pstate, ssize_t nbytes)
{
- return send(pstate->sockout, pstate->file.data, pstate->file.len, 0);
-}
+#ifdef CONFIG_DEBUG
+ char line[128];
+ int ch;
+ int i;
+ int j;
-static inline int send_part_of_file(struct httpd_state *pstate)
-{
- return send(pstate->sockout, pstate->file.data, pstate->len, 0);
+ for (i = 0; i < nbytes; i += 16)
+ {
+ sprintf(line, "%04x: ", i);
+ for ( j = 0; j < 16; j++)
+ {
+ if (i + j < nbytes)
+ {
+ sprintf(&line[strlen(line)], "%02x ", pstate->ht_buffer[i+j] );
+ }
+ else
+ {
+ strcpy(&line[strlen(line)], " ");
+ }
+ }
+ for ( j = 0; j < 16; j++)
+ {
+ if (i + j < nbytes)
+ {
+ ch = pstate->ht_buffer[i+j];
+ sprintf(&line[strlen(line)], "%c", ch >= 0x20 && ch <= 0x7e ? ch : '.');
+ }
+ }
+ dbg("%s", line);
+ }
+#endif
}
+#else
+# define httpd_dumpbuffer(pstate,nbytes)
+#endif
static void next_scriptstate(struct httpd_state *pstate)
{
@@ -95,35 +127,40 @@ static void next_scriptstate(struct httpd_state *pstate)
pstate->scriptptr = p;
}
-static void handle_script(struct httpd_state *pstate, struct uip_conn *conn)
+static void handle_script(struct httpd_state *pstate)
{
char *ptr;
while(pstate->file.len > 0) {
- /* Check if we should start executing a script. */
+ /* Check if we should start executing a script */
+
if (*pstate->file.data == ISO_percent &&
*(pstate->file.data + 1) == ISO_bang) {
pstate->scriptptr = pstate->file.data + 3;
pstate->scriptlen = pstate->file.len - 3;
- if (*(pstate->scriptptr - 1) == ISO_colon) {
- httpd_fs_open(pstate->scriptptr + 1, &pstate->file);
- send_file(pstate);
- } else {
- httpd_cgi(pstate->scriptptr)(pstate, pstate->scriptptr);
- }
+ if (*(pstate->scriptptr - 1) == ISO_colon)
+ {
+ httpd_fs_open(pstate->scriptptr + 1, &pstate->file);
+ send(pstate->sockfd, pstate->file.data, pstate->file.len, 0);
+ }
+ else
+ {
+ httpd_cgi(pstate->scriptptr)(pstate, pstate->scriptptr);
+ }
next_scriptstate(pstate);
/* The script is over, so we reset the pointers and continue
- sending the rest of the file. */
+ sending the rest of the file */
pstate->file.data = pstate->scriptptr;
pstate->file.len = pstate->scriptlen;
+
} else {
/* See if we find the start of script marker in the block of HTML
- to be sent. */
+ to be sent */
- if (pstate->file.len > uip_mss(conn)) {
- pstate->len = uip_mss(conn);
+ if (pstate->file.len > HTTPD_IOBUFFER_SIZE) {
+ pstate->len = HTTPD_IOBUFFER_SIZE;
} else {
pstate->len = pstate->file.len;
}
@@ -136,11 +173,11 @@ static void handle_script(struct httpd_state *pstate, struct uip_conn *conn)
if (ptr != NULL &&
ptr != pstate->file.data) {
pstate->len = (int)(ptr - pstate->file.data);
- if (pstate->len >= uip_mss(conn)) {
- pstate->len = uip_mss(conn);
+ if (pstate->len >= HTTPD_IOBUFFER_SIZE) {
+ pstate->len = HTTPD_IOBUFFER_SIZE;
}
}
- send_part_of_file(pstate);
+ send(pstate->sockfd, pstate->file.data, pstate->len, 0);
pstate->file.data += pstate->len;
pstate->file.len -= pstate->len;
}
@@ -152,41 +189,41 @@ static int send_headers(struct httpd_state *pstate, const char *statushdr)
char *ptr;
int ret;
- ret = send(pstate->sockout, statushdr, strlen(statushdr), 0);
+ ret = send(pstate->sockfd, statushdr, strlen(statushdr), 0);
ptr = strrchr(pstate->filename, ISO_period);
if (ptr == NULL)
{
- ret = send(pstate->sockout, http_content_type_binary, strlen(http_content_type_binary), 0);
+ ret = send(pstate->sockfd, http_content_type_binary, strlen(http_content_type_binary), 0);
}
else if (strncmp(http_html, ptr, 5) == 0 || strncmp(http_shtml, ptr, 6) == 0)
{
- ret = send(pstate->sockout, http_content_type_html, strlen(http_content_type_html), 0);
+ ret = send(pstate->sockfd, http_content_type_html, strlen(http_content_type_html), 0);
}
else if (strncmp(http_css, ptr, 4) == 0)
{
- ret = send(pstate->sockout, http_content_type_css, strlen(http_content_type_css), 0);
+ ret = send(pstate->sockfd, http_content_type_css, strlen(http_content_type_css), 0);
}
else if (strncmp(http_png, ptr, 4) == 0)
{
- ret = send(pstate->sockout, http_content_type_png, strlen(http_content_type_png), 0);
+ ret = send(pstate->sockfd, http_content_type_png, strlen(http_content_type_png), 0);
}
else if (strncmp(http_gif, ptr, 4) == 0)
{
- ret = send(pstate->sockout, http_content_type_gif, strlen(http_content_type_gif), 0);
+ ret = send(pstate->sockfd, http_content_type_gif, strlen(http_content_type_gif), 0);
}
else if (strncmp(http_jpg, ptr, 4) == 0)
{
- ret = send(pstate->sockout, http_content_type_jpg, strlen(http_content_type_jpg), 0);
+ ret = send(pstate->sockfd, http_content_type_jpg, strlen(http_content_type_jpg), 0);
}
else
{
- ret = send(pstate->sockout, http_content_type_plain, strlen(http_content_type_plain), 0);
+ ret = send(pstate->sockfd, http_content_type_plain, strlen(http_content_type_plain), 0);
}
return ret;
}
-static void handle_output(struct httpd_state *pstate, struct uip_conn *conn)
+static void httpd_sendfile(struct httpd_state *pstate)
{
char *ptr;
@@ -195,7 +232,7 @@ static void handle_output(struct httpd_state *pstate, struct uip_conn *conn)
httpd_fs_open(http_404_html, &pstate->file);
strcpy(pstate->filename, http_404_html);
send_headers(pstate, http_header_404);
- send_file(pstate);
+ send(pstate->sockfd, pstate->file.data, pstate->file.len, 0);
}
else
{
@@ -203,75 +240,102 @@ static void handle_output(struct httpd_state *pstate, struct uip_conn *conn)
ptr = strchr(pstate->filename, ISO_period);
if (ptr != NULL && strncmp(ptr, http_shtml, 6) == 0)
{
- handle_script(pstate, conn);
+ handle_script(pstate);
}
else
{
- send_file(pstate);
+ send(pstate->sockfd, pstate->file.data, pstate->file.len, 0);
}
}
}
-static int handle_input(struct httpd_state *pstate)
+static inline int httpd_cmd(struct httpd_state *pstate)
{
ssize_t recvlen;
+ int i;
+
+ /* Get the next HTTP command. We will handle only GET */
- if (recv(pstate->sockin, pstate->inputbuf, HTTPD_INBUFFER_SIZE, 0) < 0)
+ recvlen = recv(pstate->sockfd, pstate->ht_buffer, HTTPD_IOBUFFER_SIZE, 0);
+ if (recvlen < 0)
{
return ERROR;
}
+ httpd_dumpbuffer(pstate, recvlen);
- if (strncmp(pstate->inputbuf, http_get, 4) != 0)
- {
- return ERROR;
- }
+ /* We will handle only GET */
- recvlen = recv(pstate->sockin, pstate->inputbuf, HTTPD_INBUFFER_SIZE, 0);
- if (recvlen < 0)
+ if (strncmp(pstate->ht_buffer, http_get, 4) != 0)
{
return ERROR;
}
- if (pstate->inputbuf[0] != ISO_slash)
- {
- return ERROR;
- }
+ /* Get the name of the file to provide */
- if (pstate->inputbuf[1] == ISO_space)
+ if (pstate->ht_buffer[4] != ISO_slash)
+ {
+ return ERROR;
+ }
+ else if (pstate->ht_buffer[5] == ISO_space)
{
strncpy(pstate->filename, http_index_html, sizeof(pstate->filename));
}
else
{
- pstate->inputbuf[recvlen - 1] = 0;
- strncpy(pstate->filename, &pstate->inputbuf[0], sizeof(pstate->filename));
+ for (i = 5; i < sizeof(pstate->filename) + 5 && pstate->ht_buffer[5] != ISO_space; i++)
+ {
+ pstate->filename[i] = pstate->ht_buffer[i+5];
+ }
}
- pstate->state = STATE_OUTPUT;
+ /* Then send the file */
+
+ httpd_sendfile(pstate);
+ return OK;
+}
+
+/****************************************************************************
+ * Name: httpd_handler
+ *
+ * Description:
+ * Each time a new connection to port 80 is made, a new thread is created
+ * that begins at this entry point. There should be exactly one argument
+ * and it should be the socket descriptor (+1).
+ *
+ ****************************************************************************/
+
+static int httpd_handler(int argc, char *argv[])
+{
+ struct httpd_state *pstate = (struct httpd_state *)malloc(sizeof(struct httpd_state));
+ int sockfd = (int)argv[1] - 1;
+ int ret = ERROR;
+
+ /* Verify that the state structure was successfully allocated */
- while(1)
+ if (pstate)
{
- recvlen = recv(pstate->sockin, pstate->inputbuf, HTTPD_INBUFFER_SIZE, 0);
- if (recvlen < 0)
+ /* Loop processing each HTTP command */
+ do
{
- return ERROR;
- }
+ /* Re-initialize the thread state structure */
- if (strncmp(pstate->inputbuf, http_referer, 8) == 0)
- {
- pstate->inputbuf[recvlen - 2] = 0;
+ memset(pstate, 0, sizeof(struct httpd_state));
+ pstate->sockfd = sockfd;
+
+ /* Then handle the next httpd command */
+
+ ret = httpd_cmd(pstate);
}
- }
+ while (ret == OK);
- return OK;
-}
+ /* End of command processing -- Clean up and exit */
-static void handle_connection(struct httpd_state *pstate, struct uip_conn *conn)
-{
- handle_input(pstate);
- if (pstate->state == STATE_OUTPUT) {
- handle_output(pstate, conn);
+ free(pstate);
}
+
+ /* Exit the task */
+
+ return 0;
}
/****************************************************************************
@@ -288,20 +352,24 @@ static void handle_connection(struct httpd_state *pstate, struct uip_conn *conn)
int httpd_listen(void)
{
-#warning "this is all very broken at the moment"
- return OK;
+ /* Execute httpd_handler on each connection to port 80 */
+
+ uip_server(HTONS(80), httpd_handler, CONFIG_EXAMPLES_UIP_HTTPDSTACKSIZE);
+
+ /* uip_server only returns on errors */
+
+ return ERROR;
}
/****************************************************************************
* Name: httpd_init
*
* Description:
- * This function initializes the web server and should be called at system
- * boot-up.
+ * This function initializes the web server and should be called at system
+ * boot-up.
*
****************************************************************************/
void httpd_init(void)
{
- uip_listen(HTONS(80));
}