www.pudn.com > lwip-1.3.0.rar > httpd.c
/* * Copyright (c) 2001-2003 Swedish Institute of Computer Science. * All rights reserved. * * Redistribution and use in source and binary forms, with or without modification, * are permitted provided that the following conditions are met: * * 1. Redistributions of source code must retain the above copyright notice, * this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright notice, * this list of conditions and the following disclaimer in the documentation * and/or other materials provided with the distribution. * 3. The name of the author may not be used to endorse or promote products * derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 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. * * This file is part of the lwIP TCP/IP stack. * * Author: Adam Dunkels* */ /* This file is modified from the original version (httpd.c) as shipped with * lwIP version 1.3.0. Changes have been made to allow support for a * rudimentary server-side-include facility which will replace tags of the form * in any file whose extension is .shtml with strings provided by * an include handler whose pointer is provided to the module via function * http_set_ssi_handler(). Additionally, a simple common gateway interface * (CGI) handling mechanism has been added to allow clients to hook functions * to particular request URIs. * * To enable SSI support, define label INCLUDE_HTTPD_SSI in lwipopts.h. * To enable CGI support, define label INCLUDE_HTTPD_CGI in lwipopts.h. * */ /* * Notes about valid SSI tags * -------------------------- * * The following assumptions are made about tags used in SSI markers: * * 1. No tag may contain '-' or whitespace characters within the tag name. * 2. Whitespace is allowed between the tag leadin "". * 3. The maximum tag name length is MAX_TAG_NAME_LEN, currently 8 characters. * * Notes on CGI usage * ------------------ * * The simple CGI support offered here works with GET method requests only * and can handle up to 16 parameters encoded into the URI. The handler * function may not write directly to the HTTP output but must return a * filename that the HTTP server will send to the browser as a response to * the incoming CGI request. * */ #include "lwip/debug.h" #include "lwip/stats.h" #include "httpd.h" #include "lwip/tcp.h" #include "fs.h" #include #include "../../../utils/ustdlib.h" #ifdef INCLUDE_HTTPD_DEBUG #include "../../../utils/uartstdio.h" #define DEBUG_PRINT UARTprintf #else #define DEBUG_PRINT while(0)((int (*)(char *, ...))0) #endif #ifndef true #define true ((u8_t)1) #endif #ifndef false #define false ((u8_t)0) #endif typedef struct { const char *name; u8_t shtml; } default_filename; const default_filename g_psDefaultFilenames[] = { {"/index.shtml", true }, {"/index.ssi", true }, {"/index.shtm", true }, {"/index.html", false }, {"/index.htm", false } }; #define NUM_DEFAULT_FILENAMES (sizeof(g_psDefaultFilenames) / \ sizeof(default_filename)) #ifdef INCLUDE_HTTPD_SSI const char *g_pcSSIExtensions[] = { ".shtml", ".shtm", ".ssi" }; #define NUM_SHTML_EXTENSIONS (sizeof(g_pcSSIExtensions) / sizeof(const char *)) enum tag_check_state { TAG_NONE, /* Not processing an SSI tag */ TAG_LEADIN, /* Tag lead in "" being processed */ TAG_SENDING /* Sending tag replacement string */ }; #endif /* INCLUDE_HTTPD_SSI */ struct http_state { struct fs_file *handle; char *file; /* Pointer to first unsent byte in buf. */ char *buf; /* File read buffer. */ #ifdef INCLUDE_HTTPD_SSI char *parsed; /* Pointer to the first unparsed byte in buf. */ char *tag_end; /* Pointer to char after the closing '>' of the tag. */ u32_t parse_left; /* Number of unparsed bytes in buf. */ #endif u32_t left; /* Number of unsent bytes in buf. */ int buf_len; /* Size of file read buffer, buf. */ u8_t retries; #ifdef INCLUDE_HTTPD_SSI u8_t tag_check; /* true if we are processing a .shtml file else false */ u8_t tag_index; /* Counter used by tag parsing state machine */ u8_t tag_insert_len; /* Length of insert in string tag_insert */ u8_t tag_name_len; /* Length of the tag name in string tag_name */ char tag_name[MAX_TAG_NAME_LEN + 1]; /* Last tag name extracted */ char tag_insert[MAX_TAG_INSERT_LEN + 1]; /* Insert string for tag_name */ enum tag_check_state tag_state; /* State of the tag processor */ #endif #ifdef INCLUDE_HTTPD_CGI char *params[MAX_CGI_PARAMETERS]; /* Params extracted from the request URI */ char *param_vals[MAX_CGI_PARAMETERS]; /* Values for each extracted param */ #endif }; #ifdef INCLUDE_HTTPD_SSI /* SSI insert handler function pointer. */ tSSIHandler g_pfnSSIHandler = NULL; int g_iNumTags = 0; const char **g_ppcTags = NULL; #define LEN_TAG_LEAD_IN 5 const char * const g_pcTagLeadIn = ""; #endif /* INCLUDE_HTTPD_SSI */ #ifdef INCLUDE_HTTPD_CGI /* CGI handler information */ const tCGI *g_pCGIs = NULL; int g_iNumCGIs = 0; #endif /* INCLUDE_HTTPD_CGI */ /*-----------------------------------------------------------------------------------*/ static void conn_err(void *arg, err_t err) { struct http_state *hs; LWIP_UNUSED_ARG(err); if(arg) { hs = arg; if(hs->handle) { fs_close(hs->handle); hs->handle = NULL; } if(hs->buf) { mem_free(hs->buf); } mem_free(hs); } } /*-----------------------------------------------------------------------------------*/ static void close_conn(struct tcp_pcb *pcb, struct http_state *hs) { DEBUG_PRINT("Closing connection 0x%08x\n", pcb); tcp_arg(pcb, NULL); tcp_sent(pcb, NULL); tcp_recv(pcb, NULL); if(hs->handle) { fs_close(hs->handle); hs->handle = NULL; } if(hs->buf) { mem_free(hs->buf); } mem_free(hs); tcp_close(pcb); } /*-----------------------------------------------------------------------------------*/ #ifdef INCLUDE_HTTPD_CGI static int extract_uri_parameters(struct http_state *hs, char *params) { char *pair; char *equals; int loop; /* If we have no parameters at all, return immediately. */ if(!params || (params[0] == '\0')) { return(0); } /* Get a pointer to our first parameter */ pair = params; /* * Parse up to MAX_CGI_PARAMETERS from the passed string and ignore the * remainder (if any) */ for(loop = 0; (loop < MAX_CGI_PARAMETERS) && pair; loop++) { /* Save the name of the parameter */ hs->params[loop] = pair; /* Remember the start of this name=value pair */ equals = pair; /* Find the start of the next name=value pair and replace the delimiter * with a 0 to terminate the previous pair string. */ pair = strchr(pair, '&'); if(pair) { *pair = '\0'; pair++; } /* Now find the '=' in the previous pair, replace it with '\0' and save * the parameter value string. */ equals = strchr(equals, '='); if(equals) { *equals = '\0'; hs->param_vals[loop] = equals + 1; } else { hs->param_vals[loop] = NULL; } } return(loop); } #endif /* INCLUDE_HTTPD_CGI */ /*-----------------------------------------------------------------------------------*/ #ifdef INCLUDE_HTTPD_SSI static void get_tag_insert(struct http_state *hs) { int loop; if(g_pfnSSIHandler && g_ppcTags && g_iNumTags) { /* Find this tag in the list we have been provided. */ for(loop = 0; loop < g_iNumTags; loop++) { if(strcmp(hs->tag_name, g_ppcTags[loop]) == 0) { hs->tag_insert_len = g_pfnSSIHandler(loop, hs->tag_insert, MAX_TAG_INSERT_LEN); return; } } } /* If we drop out, we were asked to serve a page which contains tags that * we don't have a handler for. Merely echo back the tags with an error * marker. */ usnprintf(hs->tag_insert, MAX_TAG_INSERT_LEN + 1, "***UNKNOWN TAG %s***", hs->tag_name); hs->tag_insert_len = strlen(hs->tag_insert); } #endif /* INCLUDE_HTTPD_SSI */ /*-----------------------------------------------------------------------------------*/ static void send_data(struct tcp_pcb *pcb, struct http_state *hs) { err_t err; u16_t len; u8_t data_to_send = false; /* Have we run out of file data to send? If so, we need to read the next * block from the file. */ if(hs->left == 0) { int count; /* Do we already have a send buffer allocated? */ if(hs->buf) { /* Yes - get the length of the buffer */ count = hs->buf_len; } else { /* We don't have a send buffer so allocate one up to 2*mss bytes long. */ count = 2*pcb->mss; do { hs->buf = mem_malloc(count); if(hs->buf) { hs->buf_len = count; break; } count = count / 2; }while (count > 100); /* Did we get a send buffer? If not, return immediately. */ if(hs->buf == NULL) { DEBUG_PRINT("No buff\n"); return; } } /* Do we have a valid file handle? */ if(hs->handle == NULL) { // // No - close the connection. // close_conn(pcb, hs); return; } /* Read a block of data from the file. */ DEBUG_PRINT("Trying to read %d bytes.\n", count); count = fs_read(hs->handle, hs->buf, count); if(count < 0) { /* We reached the end of the file so this request is done */ DEBUG_PRINT("End of file.\n"); fs_close(hs->handle); hs->handle = NULL; close_conn(pcb, hs); return; } /* Set up to send the block of data we just read */ DEBUG_PRINT("Read %d bytes.\n", count); hs->left = count; hs->file = hs->buf; #ifdef INCLUDE_HTTPD_SSI hs->parse_left = count; hs->parsed = hs->buf; #endif } #ifdef INCLUDE_HTTPD_SSI if(!hs->tag_check) { #endif /* We are not processing an SHTML file so no tag checking is necessary. * Just send the data as we received it from the file. */ /* We cannot send more data than space available in the send buffer. */ if (tcp_sndbuf(pcb) < hs->left) { len = tcp_sndbuf(pcb); } else { len = hs->left; LWIP_ASSERT("hs->left did not fit into u16_t!", (len == hs->left)); } if(len > (2*pcb->mss)) { len = 2*pcb->mss; } do { DEBUG_PRINT("Sending %d bytes\n", len); err = tcp_write(pcb, hs->file, len, 0); if (err == ERR_MEM) { len /= 2; } } while (err == ERR_MEM && len > 1); if (err == ERR_OK) { data_to_send = true; hs->file += len; hs->left -= len; } #ifdef INCLUDE_HTTPD_SSI } else { /* We are processing an SHTML file so need to scan for tags and replace * them with insert strings. We need to be careful here since a tag may * straddle the boundary of two blocks read from the file and we may also * have to split the insert string between two tcp_write operations. */ /* How much data could we send? */ len = tcp_sndbuf(pcb); /* Do we have remaining data to send before parsing more? */ if(hs->parsed > hs->file) { /* We cannot send more data than space available in the send buffer. */ if (tcp_sndbuf(pcb) < (hs->parsed - hs->file)) { len = tcp_sndbuf(pcb); } else { len = (hs->parsed - hs->file); LWIP_ASSERT("Data size did not fit into u16_t!", (hs->parsed - hs->file)); } if(len > (2*pcb->mss)) { len = 2*pcb->mss; } do { DEBUG_PRINT("Sending %d bytes\n", len); err = tcp_write(pcb, hs->file, len, 0); if (err == ERR_MEM) { len /= 2; } } while (err == ERR_MEM && len > 1); if (err == ERR_OK) { data_to_send = true; hs->file += len; hs->left -= len; } // // If the send buffer is full, return now. // if(tcp_sndbuf(pcb) == 0) { if(data_to_send) { tcp_output(pcb); DEBUG_PRINT("Output\n"); } return; } } DEBUG_PRINT("State %d, %d left\n", hs->tag_state, hs->parse_left); /* We have sent all the data that was already parsed so continue parsing * the buffer contents looking for SSI tags. */ while(hs->parse_left) { switch(hs->tag_state) { case TAG_NONE: /* We are not currently processing an SSI tag so scan for the * start of the lead-in marker. */ if(*hs->parsed == g_pcTagLeadIn[0]) { /* We found what could be the lead-in for a new tag so change * state appropriately. */ hs->tag_state = TAG_LEADIN; hs->tag_index = 1; } /* Move on to the next character in the buffer */ hs->parse_left--; hs->parsed++; break; case TAG_LEADIN: /* We are processing the lead-in marker, looking for the start of * the tag name. */ /* Have we reached the end of the leadin? */ if(hs->tag_index == LEN_TAG_LEAD_IN) { hs->tag_index = 0; hs->tag_state = TAG_FOUND; } else { /* Have we found the next character we expect for the tag leadin? */ if(*hs->parsed == g_pcTagLeadIn[hs->tag_index]) { /* Yes - move to the next one unless we have found the complete * leadin, in which case we start looking for the tag itself */ hs->tag_index++; } else { /* We found an unexpected character so this is not a tag. Move * back to idle state. */ hs->tag_state = TAG_NONE; } /* Move on to the next character in the buffer */ hs->parse_left--; hs->parsed++; } break; case TAG_FOUND: /* We are reading the tag name, looking for the start of the * lead-out marker and removing any whitespace found. */ /* Remove leading whitespace between the tag leading and the first * tag name character. */ if((hs->tag_index == 0) && ((*hs->parsed == ' ') || (*hs->parsed == '\t') || (*hs->parsed == '\n') || (*hs->parsed == '\r'))) { /* Move on to the next character in the buffer */ hs->parse_left--; hs->parsed++; break; } /* Have we found the end of the tag name? This is signalled by * us finding the first leadout character or whitespace */ if((*hs->parsed == g_pcTagLeadOut[0]) || (*hs->parsed == ' ') || (*hs->parsed == '\t') || (*hs->parsed == '\n') || (*hs->parsed == '\r')) { if(hs->tag_index == 0) { /* We read a zero length tag so ignore it. */ hs->tag_state = TAG_NONE; } else { /* We read a non-empty tag so go ahead and look for the * leadout string. */ hs->tag_state = TAG_LEADOUT; hs->tag_name_len = hs->tag_index; hs->tag_name[hs->tag_index] = '\0'; if(*hs->parsed == g_pcTagLeadOut[0]) { hs->tag_index = 1; } else { hs->tag_index = 0; } } } else { /* This character is part of the tag name so save it */ if(hs->tag_index < MAX_TAG_NAME_LEN) { hs->tag_name[hs->tag_index++] = *hs->parsed; } else { /* The tag was too long so ignore it. */ hs->tag_state = TAG_NONE; } } /* Move on to the next character in the buffer */ hs->parse_left--; hs->parsed++; break; /* * We are looking for the end of the lead-out marker. */ case TAG_LEADOUT: /* Remove leading whitespace between the tag leading and the first * tag leadout character. */ if((hs->tag_index == 0) && ((*hs->parsed == ' ') || (*hs->parsed == '\t') || (*hs->parsed == '\n') || (*hs->parsed == '\r'))) { /* Move on to the next character in the buffer */ hs->parse_left--; hs->parsed++; break; } /* Have we found the next character we expect for the tag leadout? */ if(*hs->parsed == g_pcTagLeadOut[hs->tag_index]) { /* Yes - move to the next one unless we have found the complete * leadout, in which case we need to call the client to process * the tag. */ /* Move on to the next character in the buffer */ hs->parse_left--; hs->parsed++; if(hs->tag_index == (LEN_TAG_LEAD_OUT - 1)) { /* Call the client to ask for the insert string for the * tag we just found. */ get_tag_insert(hs); /* Next time through, we are going to be sending data * immediately, either the end of the block we start * sending here or the insert string. */ hs->tag_index = 0; hs->tag_state = TAG_SENDING; hs->tag_end = hs->parsed; /* If there is any unsent data in the buffer prior to the * tag, we need to send it now. */ if(hs->tag_end > hs->file) { /* How much of the data can we send? */ if(len > hs->tag_end - hs->file) { len = hs->tag_end - hs->file; } do { DEBUG_PRINT("Sending %d bytes\n", len); err = tcp_write(pcb, hs->file, len, 0); if (err == ERR_MEM) { len /= 2; } } while (err == ERR_MEM && (len > 1)); if (err == ERR_OK) { data_to_send = true; hs->file += len; hs->left -= len; } } } else { hs->tag_index++; } } else { /* We found an unexpected character so this is not a tag. Move * back to idle state. */ hs->parse_left--; hs->parsed++; hs->tag_state = TAG_NONE; } break; /* * We have found a valid tag and are in the process of sending * data as a result of that discovery. We send either remaining data * from the file prior to the insert point or the insert string itself. */ case TAG_SENDING: /* Do we have any remaining file data to send from the buffer prior * to the tag? */ if(hs->tag_end > hs->file) { /* How much of the data can we send? */ if(len > hs->tag_end - hs->file) { len = hs->tag_end - hs->file; } do { DEBUG_PRINT("Sending %d bytes\n", len); err = tcp_write(pcb, hs->file, len, 0); if (err == ERR_MEM) { len /= 2; } } while (err == ERR_MEM && (len > 1)); if (err == ERR_OK) { data_to_send = true; hs->file += len; hs->left -= len; } } else { /* Do we still have insert data left to send? */ if(hs->tag_index < hs->tag_insert_len) { /* We are sending the insert string itself. How much of the * insert can we send? */ if(len > (hs->tag_insert_len - hs->tag_index)) { len = (hs->tag_insert_len - hs->tag_index); } do { DEBUG_PRINT("Sending %d bytes\n", len); /* * Note that we set the copy flag here since we only have a * single tag insert buffer per connection. If we don't do * this, insert corruption can occur if more than one insert * is processed before we call tcp_output. */ err = tcp_write(pcb, &(hs->tag_insert[hs->tag_index]), len, 1); if (err == ERR_MEM) { len /= 2; } } while (err == ERR_MEM && (len > 1)); if (err == ERR_OK) { data_to_send = true; hs->tag_index += len; return; } } else { /* We have sent all the insert data so go back to looking for * a new tag. */ DEBUG_PRINT("Everything sent.\n"); hs->tag_index = 0; hs->tag_state = TAG_NONE; } } } } /* * If we drop out of the end of the for loop, this implies we must have * file data to send so send it now. In TAG_SENDING state, we've already * handled this so skip the send if that's the case. */ if((hs->tag_state != TAG_SENDING) && (hs->parsed > hs->file)) { /* We cannot send more data than space available in the send buffer. */ if (tcp_sndbuf(pcb) < (hs->parsed - hs->file)) { len = tcp_sndbuf(pcb); } else { len = (hs->parsed - hs->file); LWIP_ASSERT("Data size did not fit into u16_t!", (hs->parsed - hs->file)); } if(len > (2*pcb->mss)) { len = 2*pcb->mss; } do { DEBUG_PRINT("Sending %d bytes\n", len); err = tcp_write(pcb, hs->file, len, 0); if (err == ERR_MEM) { len /= 2; } } while (err == ERR_MEM && len > 1); if (err == ERR_OK) { data_to_send = true; hs->file += len; hs->left -= len; } } } #endif /* INCLUDE_HTTPD_SSI */ /* If we wrote anything to be sent, go ahead and send it now. */ if(data_to_send) { DEBUG_PRINT("tcp_output\n"); tcp_output(pcb); } DEBUG_PRINT("send_data end.\n"); } /*-----------------------------------------------------------------------------------*/ static err_t http_poll(void *arg, struct tcp_pcb *pcb) { struct http_state *hs; hs = arg; DEBUG_PRINT("http_poll 0x%08x\n", pcb); /* printf("Polll\n");*/ if (hs == NULL) { /* printf("Null, close\n");*/ tcp_abort(pcb); return ERR_ABRT; } else { ++hs->retries; if (hs->retries == 4) { tcp_abort(pcb); return ERR_ABRT; } send_data(pcb, hs); } return ERR_OK; } /*-----------------------------------------------------------------------------------*/ static err_t http_sent(void *arg, struct tcp_pcb *pcb, u16_t len) { struct http_state *hs; DEBUG_PRINT("http_sent 0x%08x\n", pcb); LWIP_UNUSED_ARG(len); hs = arg; hs->retries = 0; /* Temporarily disable send notifications */ tcp_sent(pcb, NULL); send_data(pcb, hs); /* Reenable notifications. */ tcp_sent(pcb, http_sent); return ERR_OK; } /*-----------------------------------------------------------------------------------*/ static err_t http_recv(void *arg, struct tcp_pcb *pcb, struct pbuf *p, err_t err) { int i; int loop; char *data; char *uri; struct fs_file *file; struct http_state *hs; #ifdef INCLUDE_HTTPD_CGI int count; char *params; #endif DEBUG_PRINT("http_recv 0x%08x\n", pcb); hs = arg; if (err == ERR_OK && p != NULL) { /* Inform TCP that we have taken the data. */ tcp_recved(pcb, p->tot_len); if (hs->handle == NULL) { data = p->payload; uri = &data[4]; DEBUG_PRINT("Request:\n%s\n", data); if (strncmp(data, "GET ", 4) == 0) { /* * We have a GET request. Find the end of the URI by looking for the * HTTP marker. We can't just use strstr to find this since the request * came from an outside source and we can't be sure that it is * correctly formed. We need to make sure that our search is bounded * by the packet length so we do it manually. If we don't find " HTTP", * assume the request is invalid and close the connection. */ for(i = 4; i < (p->len - 5); i++) { if ((data[i] == ' ') && (data[i + 1] == 'H') && (data[i + 2] == 'T') && (data[i + 3] == 'T') && (data[i + 4] == 'P')) { data[i] = 0; break; } } if(i == (p->len - 5)) { /* We failed to find " HTTP" in the request so assume it is invalid */ DEBUG_PRINT("Invalid GET request. Closing.\n"); pbuf_free(p); close_conn(pcb, hs); } #ifdef INCLUDE_HTTPD_SSI /* * By default, assume we will not be processing server-side-includes * tags */ hs->tag_check = false; #endif /* * Have we been asked for the default root file? */ if((uri[0] == '/') && (uri[1] == 0)) { /* * Try each of the configured default filenames until we find one * that exists. */ for(loop = 0; loop < NUM_DEFAULT_FILENAMES; loop++) { DEBUG_PRINT("Looking for %s...\n", g_psDefaultFilenames[loop].name); file = fs_open((char *)g_psDefaultFilenames[loop].name); if(file != NULL) { DEBUG_PRINT("Opened.\n"); #ifdef INCLUDE_HTTPD_SSI hs->tag_check = g_psDefaultFilenames[loop].shtml; #endif break; } } if(file == NULL) { /* None of the default filenames exist so send back a 404 page */ file = fs_open("/404.html"); #ifdef INCLUDE_HTTPD_SSI hs->tag_check = false; #endif } } else { /* No - we've been asked for a specific file. */ #ifdef INCLUDE_HTTPD_CGI /* First, isolate the base URI (without any parameters) */ params = strchr(uri, '?'); if(params) { *params = '\0'; params++; } /* Does the base URI we have isolated correspond to a CGI handler? */ if(g_iNumCGIs && g_pCGIs) { for(i = 0; i < g_iNumCGIs; i++) { if(strcmp(uri, g_pCGIs[i].pcCGIName) == 0) { /* * We found a CGI that handles this URI so extract the * parameters and call the handler. */ count = extract_uri_parameters(hs, params); uri = g_pCGIs[i].pfnCGIHandler(i, count, hs->params, hs->param_vals); break; } } } #endif DEBUG_PRINT("Opening %s\n", uri); file = fs_open(uri); if(file == NULL) { file = fs_open("/404.html"); } #ifdef INCLUDE_HTTPD_SSI else { /* * See if we have been asked for an shtml file and, if so, * enable tag checking. */ hs->tag_check = false; for(loop = 0; loop < NUM_SHTML_EXTENSIONS; loop++) { if(ustrstr(uri, g_pcSSIExtensions[loop])) { hs->tag_check = true; break; } } } #endif /* INCLUDE_HTTP_SSI */ } #ifdef INCLUDE_HTTPD_SSI hs->tag_index = 0; hs->tag_state = TAG_NONE; hs->parsed = file->data; hs->parse_left = file->len; hs->tag_end = file->data; #endif hs->handle = file; hs->file = file->data; LWIP_ASSERT("File length must be positive!", (file->len >= 0)); hs->left = file->len; hs->retries = 0; /* printf("data %p len %ld\n", hs->file, hs->left);*/ pbuf_free(p); send_data(pcb, hs); /* Tell TCP that we wish be to informed of data that has been successfully sent by a call to the http_sent() function. */ tcp_sent(pcb, http_sent); } else { pbuf_free(p); close_conn(pcb, hs); } } else { pbuf_free(p); } } if (err == ERR_OK && p == NULL) { close_conn(pcb, hs); } return ERR_OK; } /*-----------------------------------------------------------------------------------*/ static err_t http_accept(void *arg, struct tcp_pcb *pcb, err_t err) { struct http_state *hs; LWIP_UNUSED_ARG(arg); LWIP_UNUSED_ARG(err); DEBUG_PRINT("http_accept 0x%08x\n", pcb); tcp_setprio(pcb, TCP_PRIO_MIN); /* Allocate memory for the structure that holds the state of the connection. */ hs = (struct http_state *)mem_malloc(sizeof(struct http_state)); if (hs == NULL) { /* printf("http_accept: Out of memory\n"); */ return ERR_MEM; } /* Initialize the structure. */ hs->handle = NULL; hs->file = NULL; hs->buf = NULL; hs->buf_len = 0; hs->left = 0; hs->retries = 0; /* Tell TCP that this is the structure we wish to be passed for our callbacks. */ tcp_arg(pcb, hs); /* Tell TCP that we wish to be informed of incoming data by a call to the http_recv() function. */ tcp_recv(pcb, http_recv); tcp_err(pcb, conn_err); tcp_poll(pcb, http_poll, 4); return ERR_OK; } /*-----------------------------------------------------------------------------------*/ void httpd_init(void) { struct tcp_pcb *pcb; DEBUG_PRINT("httpd_init\n"); pcb = tcp_new(); tcp_bind(pcb, IP_ADDR_ANY, 80); pcb = tcp_listen(pcb); tcp_accept(pcb, http_accept); } #ifdef INCLUDE_HTTPD_SSI /*-----------------------------------------------------------------------------------*/ void http_set_ssi_handler(tSSIHandler pfnSSIHandler, const char **ppcTags, int iNumTags) { DEBUG_PRINT("http_set_ssi_handler\n"); g_pfnSSIHandler = pfnSSIHandler; g_ppcTags = ppcTags; g_iNumTags = iNumTags; } #endif #ifdef INCLUDE_HTTPD_CGI /*-----------------------------------------------------------------------------------*/ void http_set_cgi_handlers(const tCGI *pCGIs, int iNumHandlers) { g_pCGIs = pCGIs; g_iNumCGIs = iNumHandlers; } #endif /*-----------------------------------------------------------------------------------*/