📄 httpd.c
字号:
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;
}
/* If this connection has a file open, try to send some more data. If
* it has not yet received a GET request, don't do this since it will
* cause the connection to close immediately. */
if(hs->handle) {
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 struct fs_file *
get_404_file(char **ppURI)
{
struct fs_file *file;
*ppURI = "/404.html";
file = fs_open(*ppURI);
if(file == NULL) {
/* 404.html doesn't exist. Try 404.htm instead. */
*ppURI = "/404.htm";
file = fs_open(*ppURI);
if(file == NULL) {
/* 404.htm doesn't exist either. Indicate to the caller that it should
* send back a default 404 page.
*/
*ppURI = NULL;
}
}
return(file);
}
/*-----------------------------------------------------------------------------------*/
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);
return(ERR_OK);
}
#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);
uri = (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 = get_404_file(&uri);
#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;
}
}
/* Did we handle this URL as a CGI? If not, reinstate the
* original URL and pass it to the file system directly. */
if(i == g_iNumCGIs)
{
/* Replace the ? marker at the beginning of the parameters */
if(params) {
params--;
*params = '?';
}
}
}
#endif
DEBUG_PRINT("Opening %s\n", uri);
file = fs_open(uri);
if(file == NULL) {
file = get_404_file(&uri);
}
#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 */
}
if(file) {
#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;
pbuf_free(p);
} else {
hs->handle = NULL;
hs->file = NULL;
hs->left = 0;
hs->retries = 0;
}
#ifdef DYNAMIC_HTTP_HEADERS
/* Determine the HTTP headers to send based on the file extension of
* the requested URI. */
get_http_headers(hs, uri);
#endif
/* 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);
/* Start sending the headers and file data. */
send_data(pcb, hs);
} 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);
/* 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) {
DEBUG_PRINT("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;
#ifdef DYNAMIC_HTTP_HEADERS
/* Indicate that the headers are not yet valid */
hs->hdr_index = NUM_FILE_HDR_STRINGS;
#endif
/* 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
/*-----------------------------------------------------------------------------------*/
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -