📄 httpd.c
字号:
(sysStrnicmp(dec->extension, f, l) == 0))
{
conn->contenttype = dec->contenttype;
break;
}
dec++;
}
}
/*-------------------------------------------------------------------------*/
/* fill the input buffer with upstream data
*/
static sint_t ht_fillInputBuffer(HTTPCONN_t *conn)
{
int bytes, space;
if (conn->rxbufptr == conn->rxbuflen)
{
conn->rxbufptr = 0;
conn->rxbuflen = 0;
}
if (conn->rxbuflen < HTTP_RXBUFSIZE)
{
if (conn->dataavail == 0)
return -1; /* can not read from socket */
conn->lasttransfer = COUNTERVAR;
conn->dataavail = 0;
space = HTTP_RXBUFSIZE - (int) conn->rxbuflen;
bytes = recv(conn->socket, (char*)(conn->rxbuffer + conn->rxbuflen),
space, 0);
if (bytes <= 0)
{
ht_destroyConnection(conn);
return -1; /* connection closed */
}
if (bytes > space)
return ht_sendStatus(conn, status_500); /* internal server error */
conn->rxbuflen += (uint_t) bytes;
}
return 0;
}
/* read byte from socket. returns with 0 on success.
*/
static sint_t ht_readByte(HTTPCONN_t *conn, u8_t *data)
{
if (conn->rxbufptr == conn->rxbuflen)
{
if (ht_fillInputBuffer(conn) < 0)
return -1;
}
*data = conn->rxbuffer[conn->rxbufptr++];
return 0;
}
/* Read a full text line from the socket.
* Returns NULL when line is not yet available.
*/
static char* ht_readLine(HTTPCONN_t *conn)
{
struct timeval timeout;
u8_t b;
sint_t read = 0;
fd_set fds;
int status;
for(;;)
{
if ((read != 0) && (conn->rxbufptr == conn->rxbuflen))
{
FD_ZERO(&fds);
FD_SET(conn->socket, &fds);
timeout.tv_sec = 0;
timeout.tv_usec = 0;
status = select(FD_SETSIZE, &fds, NULL, NULL, &timeout);
if (status <= 0)
{
if (conn->rxlinelen > 1)
{
if ((conn->rxlinebuf[conn->rxlinelen - 2] == 0x0D) &&
(conn->rxlinebuf[conn->rxlinelen - 1] == 0x0A))
{
if ((conn->rxlinelen == 2) && (conn->emptyline == 0))
{
conn->rxlinebuf[0] = 0x20;
conn->rxlinelen++;
}
conn->rxlinebuf[conn->rxlinelen - 2] = 0;
conn->rxlinelen = 0;
conn->emptyline = 1;
return conn->rxlinebuf; /* return full line */
}
}
return NULL; /* no full string yet, and no more data to receive */
}
conn->dataavail = 1;
}
if (conn->havebackchar != 0)
{
conn->havebackchar = 0;
b = conn->backchar;
}
else
{
if (ht_readByte(conn, &b) < 0)
return NULL; /* no byte available or connection closed */
read = 1;
}
if (b == 0x09)
b = 0x20; /* convert tab to space */
if (b == 0x20) /* space? */
{
if (conn->rxlinelen > 1)
{
if ((conn->rxlinebuf[conn->rxlinelen - 2] == 0x0D) &&
(conn->rxlinebuf[conn->rxlinelen - 1] == 0x0A))
{
conn->rxlinelen -= 2;
}
}
else
if (conn->rxlinelen == 0)
{
conn->emptyline = 0;
continue;
}
}
if (conn->rxlinelen > 1)
{
if ((conn->rxlinebuf[conn->rxlinelen - 2] == 0x0D) &&
(conn->rxlinebuf[conn->rxlinelen - 1] == 0x0A))
{
conn->backchar = b;
conn->havebackchar = 1;
conn->rxlinebuf[conn->rxlinelen - 2] = 0;
conn->rxlinelen = 0;
conn->emptyline = 1;
return conn->rxlinebuf; /* return full line */
}
}
conn->rxlinebuf[conn->rxlinelen++] = (char) b;
if (conn->rxlinelen >= (HTTP_MAXSTRLEN-1))
{
/* prevent buffer overflow */
conn->rxlinebuf[conn->rxlinelen] = 0;
conn->rxlinelen = 0;
return conn->rxlinebuf;
}
}
}
/*-------------------------------------------------------------------------*/
/* This function sends a correctly formatted
* HTTP status message. In some cases, a small
* html page is generated to make the status
* visible for the user.
*/
static sint_t ht_sendStatus(HTTPCONN_t *conn, sint_t status)
{
char *buf = (char*)tempbuf1_g;
char *html = (char*)tempbuf2_g;
sint_t closeconn = 0;
sint_t addhtml = 1;
u32_t length = conn->filesize;
if ((conn->keepalive == 0) ||
(statustab_g[status].closeconn != 0))
closeconn = 1;
if ((conn->method == method_head) ||
(statustab_g[status].sendhtml == 0))
addhtml = 0;
sprintf(buf, "HTTP/1.%i %s\r\n", conn->http11, statustab_g[status].text);
if (addhtml != 0)
{
sysStrcpy(html, "<html><head>\r\n<title>");
sysStrcat(html, statustab_g[status].text);
sysStrcat(html, "</title>\r\n</head><body>\r\n<h1>");
#if HTTP_SERVLETS
if (status == status_busy)
{
sysStrcat(html, "The server is busy.");
}
else
if (status == status_idtimeout)
{
sysStrcat(html, "The requested session timed out.");
}
else
#endif
sysStrcat(html, statustab_g[status].text);
sysStrcat(html, "</h1>\r\n");
if ((status = status_404) && (*conn->filename != 0))
{
sysStrcat(html, "<hr><br>\r\n<code><b>File: ");
sysStrcat(html, conn->filename);
sysStrcat(html, "</b></code>\r\n");
}
#if HTTP_SERVLETS
else
if (status == status_busy)
{
sysStrcat(html, "<hr><br>\r\n<code><b>Please try later again."
"</b></code>\r\n");
}
#endif
sysStrcat(html, "</body></html>\r\n");
length = sysStrlen(html);
}
#if HTTP_SERVLETS
if (conn->servlet != NULL)
{
sysStrcat(buf, "Cache-Control: no-cache\r\n");
}
#endif
if ((status != status_100) && (status != status_101))
{
if (closeconn != 0)
{
if (conn->http11 != 0)
{
sysStrcat(buf, "Connection: close\r\n");
}
}
else
{
if (conn->keepalive == KEEPALIVE_UPONREQUEST)
{
sysStrcat(buf, "Connection: Keep-Alive\r\n");
}
}
}
if ((conn->method == method_get) || (conn->method == method_head) ||
(addhtml != 0))
{
if (length != 0)
{
sprintf(buf + sysStrlen(buf), "Content-Length: %u\r\n", length);
}
if ((status == status_200) &&
(conn->contenttype != content_unknown))
{
sprintf(buf + sysStrlen(buf), "Content-Type: %s\r\n",
contentTypeStrings_g[conn->contenttype]);
}
else
if (addhtml != 0)
{
sysStrcat(buf, "Content-Type: text/html\r\n");
}
}
if (status == status_405)
{
sysStrcat(buf, "Allow: GET, HEAD\r\n");
}
sysStrcat(buf, "\r\n");
if (addhtml != 0)
{
sysStrcat(buf, html);
}
log(conn->socket, "------ reply status ------\r\n");
log(conn->socket, buf);
if (send(conn->socket, buf, sysStrlen(buf), 0) <= 0)
{
ht_destroyConnection(conn);
return -1;
}
if (statustab_g[status].closeconn != 0)
{
ht_destroyConnection(conn);
return -1;
}
conn->lasttransfer = COUNTERVAR;
return 0;
}
/*-------------------------------------------------------------------------*/
/* small helper: skip the next word in the string
*/
static char* ht_skipWord(char *m)
{
while ((*m != 0) && (*m != ' ')) m++;
while (*m == ' ') m++;
return m;
}
/* small helper: move pointer behind the next colon
*/
static char *ht_movePtrToParam(char *s)
{
while (*s == ' ') s++;
if (*s == ':')
{
s++;
while (*s == ' ') s++;
}
return s;
}
/* This function reads and decodes the URI
* that is sent with the HEAD / GET / POST method.
*/
static sint_t ht_readURI(HTTPCONN_t *conn, char *str)
{
char *s = str;
char *dbuf;
uint_t b;
sint_t i, qm;
i = 0;
while ((str[i] != 0) && (str[i] != ':')) i++;
if (str[i] != 0)
{
if ((str[i+1] != '/') || (str[i+2] != '/'))
return ht_sendStatus(conn, status_400); /* bad request */
s = str + 2;
while ((*s != 0) && (*s != '/')) s++;
if (*s == 0)
return ht_sendStatus(conn, status_400); /* bad request */
}
i = 0;
qm = 0;
dbuf = conn->filename;
#if HTTP_SERVLETS
conn->optstring[0] = 0;
conn->optstring[1] = 0;
#endif
while ((*s != 0) && (*s != ' '))
{
if (*s == '?')
{
#if HTTP_SERVLETS
qm = 1;
dbuf[i] = 0;
dbuf = conn->optstring;
s++;
i = 0;
continue;
#else
break;
#endif
}
if (*s == '%')
{
s++;
if ((s[0] == 0) || (s[0] == ' ') ||
(s[1] == 0) || (s[1] == ' ') ||
(sscanf(s, "%02x", &b) != 1))
return ht_sendStatus(conn, status_400); /* bad request */
s++;
dbuf[i] = (char) b;
}
else
{
if (qm == 0)
{
dbuf[i] = *s;
}
#if HTTP_SERVLETS
else
{
if (*s == '+')
{
dbuf[i] = ' ';
}
else
if (*s == '&')
{
dbuf[i] = 0;
}
else
{
dbuf[i] = *s;
}
}
#endif
}
if (((qm == 0) && (i >= (HTTP_FNAMESIZE - 1))) ||
((qm != 0) && (i >= (HTTP_OPTSTRSIZE - 1))))
{
return ht_sendStatus(conn, status_414); /* request URI too large */
}
i++;
s++;
}
dbuf[i] = 0;
#if HTTP_SERVLETS
if (qm != 0)
dbuf[++i] = 0;
#endif
if (*conn->filename == 0)
return ht_sendStatus(conn, status_400); /* bad request */
return 0;
}
/* This function parses the HTTP commands that
* were sent with a HTTP request from a client.
*/
static sint_t ht_parseCommandLine(HTTPCONN_t *conn, char *cmd)
{
char *m;
sint_t i;
uint_t t1, t2;
/* first try to get the method */
if (conn->method == method_none)
{
for(i = 0; *(m = methodList_g[i]) != 0; i++)
{
if (sysStrncmp(cmd, m, sysStrlen(m)) == 0)
break;
}
conn->method = i;
if ((conn->method != method_get) && (conn->method != method_head))
return ht_sendStatus(conn, status_501); /* method not implemented */
m = ht_skipWord(cmd);
/* parse the URI */
if (ht_readURI(conn, m) != 0)
return -1;
m = ht_skipWord(m);
/* get HTTP version */
if (sysStrnicmp(m, "HTTP/", 5) == 0)
{
if (sscanf(m + 5, "%u.%u", &t1, &t2) == 2)
{
if ((t1 >= 1) && (t2 >= 1))
conn->http11 = 1; /* is at least HTTP/1.1 */
}
}
if (conn->http11 == 0)
conn->keepalive = 0;
}
else
if (sysStrnicmp(cmd, "Connection", 10) == 0)
{
m = ht_movePtrToParam(cmd + 10);
if (sysStrnicmp(m, "close", 5) == 0)
{
conn->keepalive = 0;
}
else
if (sysStrnicmp(m, "Keep-Alive", 10) == 0)
{
conn->keepalive = KEEPALIVE_UPONREQUEST;
}
}
else
if (sysStrnicmp(cmd, "Content-Length", 14) == 0)
{
m = ht_movePtrToParam(cmd + 14);
if (sscanf(m, "%u", &conn->upStreamLen) != 1)
return ht_sendStatus(conn, status_400); /* bad request */
if (((conn->method == method_get) || (conn->method == method_head)) &&
(conn->upStreamLen > 0))
conn->keepalive = 0; /* GET and HEAD do not allow upstream data. */
}
else
if (sysStrnicmp(cmd, "Expect", 6) == 0)
{
m = ht_movePtrToParam(cmd + 6);
if (sysStrnicmp(m, "100-continue", 12) == 0)
{
if (conn->http11 != 0)
conn->cont100 = 1;
}
else
{
return ht_sendStatus(conn, status_417); /* Expectation Failed */
}
}
return 0;
}
/* initialize next transfer
*/
static void ht_nextTransfer(HTTPCONN_t *conn)
{
if (conn->socket >= 0)
{
ht_closeFile(conn);
if ((conn->keepalive == 0) ||
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -