httpd.c
来自「在luminary平台下移植lwip到freertos,集成开发环境KEIL」· C语言 代码 · 共 1,445 行 · 第 1/3 页
C
1,445 行
// Get a pointer to the file extension. We find this by looking for the
// last occurrence of "." in the filename passed.
//
pszExt = NULL;
pszWork = strchr(pszURI, '.');
while(pszWork)
{
pszExt = pszWork + 1;
pszWork = strchr(pszExt, '.');
}
//
// Now determine the content type and add the relevant header for that.
//
for(iLoop = 0; (iLoop < NUM_HTTP_HEADERS) && pszExt; iLoop++)
{
//
// Have we found a matching extension?
//
if(!strcmp(g_psHTTPHeaders[iLoop].pszExtension, pszExt))
{
pState->hdrs[2] =
g_psHTTPHeaderStrings[g_psHTTPHeaders[iLoop].ulHeaderIndex];
break;
}
}
//
// Reinstate the parameter marker if there was one in the original
// URI.
//
if(pszVars)
{
*pszVars = '?';
}
}
//
// Does the URL passed have any file extension? If not, we assume it
// is a special-case URL used for control state notification and we do
// not send any HTTP headers with the response.
//
if(!pszExt)
{
//
// Force the header index to a value indicating that all headers
// have already been sent.
//
pState->hdr_index = NUM_FILE_HDR_STRINGS;
}
else
{
//
// Did we find a matching extension?
//
if(iLoop == NUM_HTTP_HEADERS)
{
//
// No - use the default, plain text file type.
//
pState->hdrs[2] = g_psHTTPHeaderStrings[HTTP_HDR_DEFAULT_TYPE];
}
//
// Set up to send the first header string.
//
pState->hdr_index = 0;
pState->hdr_pos = 0;
}
}
#endif
/*-----------------------------------------------------------------------------------*/
static void
send_data(struct tcp_pcb *pcb, struct http_state *hs)
{
err_t err;
u16_t len;
u8_t data_to_send = false;
#ifdef DYNAMIC_HTTP_HEADERS
u16_t hdrlen, sendlen;
/* Assume no error until we find otherwise */
err = ERR_OK;
/* Do we have any more header data to send for this file? */
if(hs->hdr_index < NUM_FILE_HDR_STRINGS)
{
/* How much data can we send? */
len = tcp_sndbuf(pcb);
sendlen = len;
while(len && (hs->hdr_index < NUM_FILE_HDR_STRINGS) && sendlen)
{
/* How much do we have to send from the current header? */
hdrlen = strlen(hs->hdrs[hs->hdr_index]);
/* How much of this can we send? */
sendlen = (len < (hdrlen - hs->hdr_pos)) ? len : (hdrlen - hs->hdr_pos);
/* Send this amount of data or as much as we can given memory
* constraints. */
do {
err = tcp_write(pcb, (const void *)(hs->hdrs[hs->hdr_index] +
hs->hdr_pos), sendlen, 0);
if (err == ERR_MEM) {
sendlen /= 2;
}
} while ((err == ERR_MEM) && (sendlen > 1));
/* Fix up the header position for the next time round. */
hs->hdr_pos += sendlen;
len -= sendlen;
/* Have we finished sending this string? */
if(hs->hdr_pos == hdrlen) {
/* Yes - move on to the next one */
hs->hdr_index++;
hs->hdr_pos = 0;
}
}
if (err == ERR_OK) {
data_to_send = true;
}
/* If we get here and there are still header bytes to send, we send
* the header information we just wrote immediately. If there are no
* more headers to send, but we do have file data to send, drop through
* to try to send some file data too.
*/
if((hs->hdr_index < NUM_FILE_HDR_STRINGS) || !hs->file) {
DEBUG_PRINT("tcp_output\n");
tcp_output(pcb);
return;
}
}
#else
/* Assume no error until we find otherwise */
err = ERR_OK;
#endif
/* 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 2mss 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);
/* If the data is being read from a buffer in RAM, we need to copy it
* into the PCB. If it's in flash, however, we can avoid the copy since
* the data is obviously not going to be overwritten during the life
* of the connection.
*/
err = tcp_write(pcb, hs->file, len,
(hs->file < (char *)0x20000000) ? 0 : 1);
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) && (err == ERR_OK)) {
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.
*/
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?