📄 webs.c
字号:
va_start(vargs, fmt);
buf = NULL;
rc = 0;
if (fmtValloc(&buf, WEBS_BUFSIZE, fmt, vargs) >= WEBS_BUFSIZE) {
trace(0, T("webs: websWrite lost data, buffer overflow\n"));
}
va_end(vargs);
a_assert(buf);
if (buf) {
rc = websWriteBlock(wp, buf, gstrlen(buf));
bfree(B_L, buf);
}
return rc;
}
/******************************************************************************/
/*
* Write a block of data of length "nChars" to the user's browser. Public
* write block procedure. If unicode is turned on this function expects
* buf to be a unicode string and it converts it to ASCII before writing.
* See websWriteDataNonBlock to always write binary or ASCII data with no
* unicode conversion. This returns the number of char_t's processed.
* It spins until nChars are flushed to the socket. For non-blocking
* behavior, use websWriteDataNonBlock.
*/
int websWriteBlock(webs_t wp, char_t *buf, int nChars)
{
int len, done;
char *asciiBuf, *pBuf;
a_assert(wp);
a_assert(websValid(wp));
a_assert(buf);
a_assert(nChars >= 0);
done = len = 0;
/*
* ballocUniToAsc will convert Unicode to strings to Ascii. If Unicode is
* not turned on then ballocUniToAsc will not do the conversion.
*/
pBuf = asciiBuf = ballocUniToAsc(buf, nChars);
while (nChars > 0) {
#ifdef WEBS_SSL_SUPPORT
if (wp->flags & WEBS_SECURE) {
if ((len = websSSLWrite(wp->wsp, pBuf, nChars)) < 0) {
bfree(B_L, asciiBuf);
return -1;
}
websSSLFlush(wp->wsp);
} else {
if ((len = socketWrite(wp->sid, pBuf, nChars)) < 0) {
bfree(B_L, asciiBuf);
return -1;
}
socketFlush(wp->sid);
}
#else /* ! WEBS_SSL_SUPPORT */
if ((len = socketWrite(wp->sid, pBuf, nChars)) < 0) {
bfree(B_L, asciiBuf);
return -1;
}
socketFlush(wp->sid);
#endif /* WEBS_SSL_SUPPORT */
nChars -= len;
pBuf += len;
done += len;
}
bfree(B_L, asciiBuf);
return done;
}
/******************************************************************************/
/*
* Write a block of data of length "nChars" to the user's browser. Same as
* websWriteBlock except that it expects straight ASCII or binary and does no
* unicode conversion before writing the data. If the socket cannot hold all
* the data, it will return the number of bytes flushed to the socket before
* it would have blocked. This returns the number of chars processed or -1
* if socketWrite fails.
*/
int websWriteDataNonBlock(webs_t wp, char *buf, int nChars)
{
int r;
a_assert(wp);
a_assert(websValid(wp));
a_assert(buf);
a_assert(nChars >= 0);
#ifdef WEBS_SSL_SUPPORT
if (wp->flags & WEBS_SECURE) {
r = websSSLWrite(wp->wsp, buf, nChars);
websSSLFlush(wp->wsp);
} else {
r = socketWrite(wp->sid, buf, nChars);
socketFlush(wp->sid);
}
#else
r = socketWrite(wp->sid, buf, nChars);
socketFlush(wp->sid);
#endif
return r;
}
/******************************************************************************/
/*
* Decode a URL (or part thereof). Allows insitu decoding.
*/
void websDecodeUrl(char_t *decoded, char_t *token, int len)
{
char_t *ip, *op;
int num, i, c;
a_assert(decoded);
a_assert(token);
op = decoded;
for (ip = token; *ip && len > 0; ip++, op++) {
if (*ip == '+') {
*op = ' ';
} else if (*ip == '%' && gisxdigit(ip[1]) && gisxdigit(ip[2])) {
/*
* Convert %nn to a single character
*/
ip++;
for (i = 0, num = 0; i < 2; i++, ip++) {
c = tolower(*ip);
if (c >= 'a' && c <= 'f') {
num = (num * 16) + 10 + c - 'a';
} else {
num = (num * 16) + c - '0';
}
}
*op = (char_t) num;
ip--;
} else {
*op = *ip;
}
len--;
}
*op = '\0';
}
/******************************************************************************/
#ifdef WEBS_LOG_SUPPORT
/*
* Output a log message
*/
static void websLog(webs_t wp, int code)
{
char_t *buf;
char *abuf;
int len;
#define qAnlLog 1
#if (defined(qAnlLog) && !defined(CE))
time_t timer;
char_t* newLine = NULL;
char_t* timeStr = NULL;
#endif
a_assert(websValid(wp));
buf = NULL;
#if (defined(qAnlLog) && !defined(CE))
time(&timer);
timeStr = ctime(&timer);
newLine = gstrchr(timeStr, '\n');
if (newLine)
{
*newLine = '\0';
}
fmtAlloc(&buf, WEBS_MAX_URL + 80, T("%s\t%s\t%s\tcode = %d\n"),
timeStr, wp->ipaddr, wp->url, code);
#else
fmtAlloc(&buf, WEBS_MAX_URL + 80, T("%d %s %d %d\n"), time(0),
wp->url, code, wp->written);
#endif
len = gstrlen(buf);
abuf = ballocUniToAsc(buf, len+1);
write(websLogFd, abuf, len);
bfreeSafe(B_L, buf);
bfreeSafe(B_L, abuf);
}
#endif /* WEBS_LOG_SUPPORT */
/******************************************************************************/
/*
* Request timeout. The timeout triggers if we have not read any data from
* the users browser in the last WEBS_TIMEOUT period. If we have heard from
* the browser, simply re-issue the timeout.
*/
void websTimeout(void *arg, int id)
{
webs_t wp;
int delay, tm;
wp = (webs_t) arg;
a_assert(websValid(wp));
tm = websGetTimeSinceMark(wp) * 1000;
if (tm >= WEBS_TIMEOUT) {
websStats.timeouts++;
emfUnschedCallback(id);
/*
* Clear the timeout id
*/
wp->timeout = -1;
websDone(wp, 404);
} else {
delay = WEBS_TIMEOUT - tm;
a_assert(delay > 0);
emfReschedCallback(id, delay);
}
}
/******************************************************************************/
/*
* Called when the request is done.
*/
void websDone(webs_t wp, int code)
{
a_assert(websValid(wp));
/*
* Disable socket handler in case keep alive set.
*/
socketDeleteHandler(wp->sid);
if (code != 200) {
wp->flags &= ~WEBS_KEEP_ALIVE;
}
#ifdef WEBS_PROXY_SUPPORT
if (! (wp->flags & WEBS_LOCAL_PAGE)) {
websStats.activeNetRequests--;
}
#endif
#ifdef WEBS_LOG_SUPPORT
if (! (wp->flags & WEBS_REQUEST_DONE)) {
websLog(wp, code);
}
#endif
/*
* Close any opened document by a handler
*/
websPageClose(wp);
/*
* Exit if secure.
*/
#ifdef WEBS_SSL_SUPPORT
if (wp->flags & WEBS_SECURE) {
websTimeoutCancel(wp);
websSSLFlush(wp->wsp);
socketCloseConnection(wp->sid);
websFree(wp);
return;
}
#endif
/*
* If using Keep Alive (HTTP/1.1) we keep the socket open for a period
* while waiting for another request on the socket.
*/
if (wp->flags & WEBS_KEEP_ALIVE) {
if (socketFlush(wp->sid) == 0) {
wp->state = WEBS_BEGIN;
wp->flags |= WEBS_REQUEST_DONE;
if (wp->header.buf) {
ringqFlush(&wp->header);
}
socketCreateHandler(wp->sid, SOCKET_READABLE, websSocketEvent,
(int) wp);
websTimeoutCancel(wp);
wp->timeout = emfSchedCallback(WEBS_TIMEOUT, websTimeout,
(void *) wp);
return;
}
} else {
websTimeoutCancel(wp);
socketSetBlock(wp->sid, 1);
socketFlush(wp->sid);
socketCloseConnection(wp->sid);
}
websFree(wp);
}
/******************************************************************************/
/*
* Allocate a new webs structure
*/
int websAlloc(int sid)
{
webs_t wp;
int wid;
/*
* Allocate a new handle for this connection
*/
if ((wid = hAllocEntry((void***) &webs, &websMax,
sizeof(struct websRec))) < 0) {
return -1;
}
wp = webs[wid];
wp->wid = wid;
wp->sid = sid;
wp->state = WEBS_BEGIN;
wp->docfd = -1;
wp->timeout = -1;
wp->dir = NULL;
wp->authType = NULL;
wp->protocol = NULL;
wp->protoVersion = NULL;
wp->password = NULL;
wp->userName = NULL;
#ifdef DIGEST_ACCESS_SUPPORT
wp->realm = NULL;
wp->nonce = NULL;
wp->digest = NULL;
wp->uri = NULL;
wp->opaque = NULL;
wp->nc = NULL;
wp->cnonce = NULL;
wp->qop = NULL;
#endif
#ifdef WEBS_SSL_SUPPORT
wp->wsp = NULL;
#endif
ringqOpen(&wp->header, WEBS_HEADER_BUFINC, WEBS_MAX_HEADER);
/*
* Create storage for the CGI variables. We supply the symbol tables for
* both the CGI variables and for the global functions. The function table
* is common to all webs instances (ie. all browsers)
*/
wp->cgiVars = symOpen(WEBS_SYM_INIT);
return wid;
}
/******************************************************************************/
/*
* Free a webs structure
*/
void websFree(webs_t wp)
{
a_assert(websValid(wp));
if (wp->path)
bfree(B_L, wp->path);
if (wp->url)
bfree(B_L, wp->url);
if (wp->host)
bfree(B_L, wp->host);
if (wp->lpath)
bfree(B_L, wp->lpath);
if (wp->query)
bfree(B_L, wp->query);
if (wp->decodedQuery)
bfree(B_L, wp->decodedQuery);
if (wp->authType)
bfree(B_L, wp->authType);
if (wp->password)
bfree(B_L, wp->password);
if (wp->userName)
bfree(B_L, wp->userName);
if (wp->cookie)
bfree(B_L, wp->cookie);
if (wp->userAgent)
bfree(B_L, wp->userAgent);
if (wp->dir)
bfree(B_L, wp->dir);
if (wp->protocol)
bfree(B_L, wp->protocol);
if (wp->protoVersion)
bfree(B_L, wp->protoVersion);
if (wp->cgiStdin)
bfree(B_L, wp->cgiStdin);
#ifdef DIGEST_ACCESS_SUPPORT
if (wp->realm)
bfree(B_L, wp->realm);
if (wp->uri)
bfree(B_L, wp->uri);
if (wp->digest)
bfree(B_L, wp->digest);
if (wp->opaque)
bfree(B_L, wp->opaque);
if (wp->nonce)
bfree(B_L, wp->nonce);
if (wp->nc)
bfree(B_L, wp->nc);
if (wp->cnonce)
bfree(B_L, wp->cnonce);
if (wp->qop)
bfree(B_L, wp->qop);
#endif
#ifdef WEBS_SSL_SUPPORT
websSSLFree(wp->wsp);
#endif
symClose(wp->cgiVars);
if (wp->header.buf) {
ringqClose(&wp->header);
}
websMax = hFree((void***) &webs, wp->wid);
bfree(B_L, wp);
a_assert(websMax >= 0);
}
/******************************************************************************/
/*
* Return the server address
*/
char_t *websGetHost()
{
return websHost;
}
/******************************************************************************/
/*
* Return the the url to access the server. (ip address)
*/
char_t *websGetIpaddrUrl()
{
return websIpaddrUrl;
}
/******************************************************************************/
/*
* Return the server address
*/
char_t *websGetHostUrl()
{
return websHostUrl;
}
/******************************************************************************/
/*
* Return the listen port
*/
int websGetPort()
{
return websPort;
}
/******************************************************************************/
/*
* Get the number of bytes to write
*/
int websGetRequestBytes(webs_t wp)
{
a_assert(websValid(wp));
return wp->numbytes;
}
/******************************************************************************/
/*
* Get the directory for this request
*/
char_t *websGetRequestDir(webs_t wp)
{
a_assert(websValid(wp));
if (wp->dir == NULL) {
return T("");
}
return wp->dir;
}
/******************************************************************************/
/*
* Get the flags for this request
*/
int websGetRequestFlags(webs_t wp)
{
a_assert(websValid(wp));
return wp->flags;
}
/******************************************************************************/
/*
* Return the IP address
*/
char_t *websGetRequestIpaddr(webs_t wp)
{
a_assert(websValid(wp));
return wp->ipaddr;
}
/******************************************************************************/
/*
* Set the local path for the request
*/
char_t *websGetRequestLpath(webs_t wp)
{
a_assert(websValid(wp));
#ifdef WEBS_PAGE_ROM
return wp->path;
#else
return wp->lpath;
#endif
}
/******************************************************************************/
/*
* Get the path for this request
*/
char_t *websGetRequestPath(webs_t wp)
{
a_assert(websValid(wp));
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -