?? webs.c
字號(hào):
a_assert(ptext);
a_assert(pnbytes);
*ptext = text = NULL;
*pnbytes = 0;
/*
* If this request is a POST with a content length, we know the number
* of bytes to read so we use socketRead().
*/
if (wp->state == WEBS_POST_CLEN) {
len = (wp->clen > WEBS_SOCKET_BUFSIZ) ? WEBS_SOCKET_BUFSIZ : wp->clen;
} else {
len = 0;
}
if (len > 0) {
#ifdef WEBS_SSL_SUPPORT
if (wp->flags & WEBS_SECURE) {
nbytes = websSSLRead(wp->wsp, buf, len);
} else {
nbytes = socketRead(wp->sid, buf, len);
}
#else
nbytes = socketRead(wp->sid, buf, len);
#endif
if (nbytes < 0) { /* Error */
websDone(wp, 0);
return -1;
} else if (nbytes == 0) { /* EOF or No data available */
return -1;
} else { /* Valid data */
/*
* Convert to UNICODE if necessary. First be sure the string
* is NULL terminated.
*/
buf[nbytes] = '\0';
if ((text = ballocAscToUni(buf, nbytes)) == NULL) {
websError(wp, 503, T("Insufficient memory"));
return -1;
}
}
} else {
#ifdef WEBS_SSL_SUPPORT
if (wp->flags & WEBS_SECURE) {
nbytes = websSSLGets(wp->wsp, &text);
} else {
nbytes = socketGets(wp->sid, &text);
}
#else
nbytes = socketGets(wp->sid, &text);
#endif
if (nbytes < 0) {
int eof;
/*
* Error, EOF or incomplete
*/
#ifdef WEBS_SSL_SUPPORT
if (wp->flags & WEBS_SECURE) {
/*
* If state is WEBS_BEGIN and the request is secure, a -1 will
* usually indicate SSL negotiation
*/
if (wp->state == WEBS_BEGIN) {
eof = 1;
} else {
eof = websSSLEof(wp->wsp);
}
} else {
eof = socketEof(wp->sid);
}
#else
eof = socketEof(wp->sid);
#endif
if (eof) {
/*
* If this is a post request without content length, process
* the request as we now have all the data. Otherwise just
* close the connection.
*/
if (wp->state == WEBS_POST) {
websUrlHandlerRequest(wp);
} else {
websDone(wp, 0);
}
} else {
/*
* If an error occurred and it wasn't an eof, close the connection
*/
#ifdef HP_FIX
websDone(wp, 0);
#endif /*HP_FIX*/
}
/*
* If state is WEBS_HEADER and the ringq is empty, then this is a
* simple request with no additional header fields to process and
* no empty line terminator.
*/
/*
* NOTE: this fix for earlier versions of browsers is troublesome
* because if we don't receive the entire header in the first pass
* this code assumes we were only expecting a one line header, which
* is not necessarily the case. So we weren't processing the whole
* header and weren't fufilling requests properly.
*/
#ifdef UNUSED
if (wp->state == WEBS_HEADER && ringqLen(&wp->header) <= 0) {
websParseRequest(wp);
websUrlHandlerRequest(wp);
}
#endif
return -1;
} else if (nbytes == 0) {
if (wp->state == WEBS_HEADER) {
/*
* Valid empty line, now finished with header
*/
websParseRequest(wp);
if (wp->flags & WEBS_POST_REQUEST) {
if (wp->flags & WEBS_CLEN) {
wp->state = WEBS_POST_CLEN;
clen = wp->clen;
} else {
wp->state = WEBS_POST;
clen = 1;
}
if (clen > 0) {
/*
* Return 0 to get more data.
*/
return 0;
}
return 1;
}
/*
* We've read the header so go and handle the request
*/
websUrlHandlerRequest(wp);
}
return -1;
}
}
a_assert(text);
a_assert(nbytes > 0);
*ptext = text;
*pnbytes = nbytes;
return 1;
}
/******************************************************************************/
/*
* Parse the first line of a HTTP request
*/
static int websParseFirst(webs_t wp, char_t *text)
{
char_t *op, *proto, *protoVer, *url, *host, *query, *path, *port, *ext;
char_t *buf;
int testPort;
a_assert(websValid(wp));
a_assert(text && *text);
/*
* Determine the request type: GET, HEAD or POST
*/
op = gstrtok(text, T(" \t"));
if (op == NULL || *op == '\0') {
websError(wp, 400, T("Bad HTTP request"));
return -1;
}
if (gstrcmp(op, T("GET")) != 0) {
if (gstrcmp(op, T("POST")) == 0) {
wp->flags |= WEBS_POST_REQUEST;
} else if (gstrcmp(op, T("HEAD")) == 0) {
wp->flags |= WEBS_HEAD_REQUEST;
} else {
websError(wp, 400, T("Bad request type"));
return -1;
}
}
/*
* Store result in the form (CGI) variable store
*/
websSetVar(wp, T("REQUEST_METHOD"), op);
url = gstrtok(NULL, T(" \t\n"));
if (url == NULL || *url == '\0') {
websError(wp, 400, T("Bad HTTP request"));
return -1;
}
protoVer = gstrtok(NULL, T(" \t\n"));
/*
* Parse the URL and store all the various URL components. websUrlParse
* returns an allocated buffer in buf which we must free. We support both
* proxied and non-proxied requests. Proxied requests will have http://host/
* at the start of the URL. Non-proxied will just be local path names.
*/
host = path = port = proto = query = ext = NULL;
if (websUrlParse(url, &buf, &host, &path, &port, &query, &proto,
NULL, &ext) < 0) {
websError(wp, 400, T("Bad URL format"));
return -1;
}
wp->url = bstrdup(B_L, url);
#ifndef __NO_CGI_BIN
if (gstrstr(url, CGI_BIN) != NULL) {
wp->flags |= WEBS_CGI_REQUEST;
if (wp->flags & WEBS_POST_REQUEST) {
wp->cgiStdin = websGetCgiCommName();
}
}
#endif
wp->query = bstrdup(B_L, query);
wp->host = bstrdup(B_L, host);
wp->path = bstrdup(B_L, path);
wp->protocol = bstrdup(B_L, proto);
wp->protoVersion = bstrdup(B_L, protoVer);
if ((testPort = socketGetPort(wp->listenSid)) >= 0) {
wp->port = testPort;
} else {
wp->port = gatoi(port);
}
if (gstrcmp(ext, T(".asp")) == 0) {
wp->flags |= WEBS_ASP;
}
bfree(B_L, buf);
websUrlType(url, wp->type, TSZ(wp->type));
#ifdef WEBS_PROXY_SUPPORT
/*
* Determine if this is a request for local webs data. If it is not a proxied
* request from the browser, we won't see the "http://" or the system name, so
* we assume it must be talking to us directly for local webs data.
* Note: not fully implemented yet.
*/
if (gstrstr(wp->url, T("http://")) == NULL ||
((gstrcmp(wp->host, T("localhost")) == 0 ||
gstrcmp(wp->host, websHost) == 0) && (wp->port == websPort))) {
wp->flags |= WEBS_LOCAL_PAGE;
if (gstrcmp(wp->path, T("/")) == 0) {
wp->flags |= WEBS_HOME_PAGE;
}
}
#endif
ringqFlush(&wp->header);
return 0;
}
/******************************************************************************/
/*
* Parse a full request
*/
#define isgoodchar(s) (gisalnum((s)) || ((s) == '/') || ((s) == '_') || \
((s) == '.') || ((s) == '-') )
static void websParseRequest(webs_t wp)
{
char_t *authType, *upperKey, *cp, *browser, *lp, *key, *value;
a_assert(websValid(wp));
/*
* Define default CGI values
*/
websSetVar(wp, T("HTTP_AUTHORIZATION"), T(""));
/*
* Parse the header and create the Http header keyword variables
* We rewrite the header as we go for non-local requests. NOTE: this
* modifies the header string directly and tokenizes each line with '\0'.
*/
browser = NULL;
for (lp = (char_t*) wp->header.servp; lp && *lp; ) {
cp = lp;
if ((lp = gstrchr(lp, '\n')) != NULL) {
lp++;
}
if ((key = gstrtok(cp, T(": \t\n"))) == NULL) {
continue;
}
if ((value = gstrtok(NULL, T("\n"))) == NULL) {
value = T("");
}
while (gisspace(*value)) {
value++;
}
strlower(key);
/*
* Create a variable (CGI) for each line in the header
*/
fmtAlloc(&upperKey, (gstrlen(key) + 6), T("HTTP_%s"), key);
for (cp = upperKey; *cp; cp++) {
if (*cp == '-')
*cp = '_';
}
strupper(upperKey);
websSetVar(wp, upperKey, value);
bfree(B_L, upperKey);
/*
* Track the requesting agent (browser) type
*/
if (gstrcmp(key, T("user-agent")) == 0) {
wp->userAgent = bstrdup(B_L, value);
/*
* Parse the user authorization. ie. password
*/
} else if (gstricmp(key, T("authorization")) == 0) {
/*
* Determine the type of Authorization Request
*/
authType = bstrdup (B_L, value);
a_assert (authType);
/*
* Truncate authType at the next non-alpha character
*/
cp = authType;
while (gisalpha(*cp)) {
cp++;
}
*cp = '\0';
wp->authType = bstrdup(B_L, authType);
bfree(B_L, authType);
if (gstricmp(wp->authType, T("basic")) == 0) {
char_t userAuth[FNAMESIZE];
/*
* The incoming value is username:password (Basic authentication)
*/
if ((cp = gstrchr(value, ' ')) != NULL) {
*cp = '\0';
/*
* bugfix 5/24/02 -- we were leaking the memory pointed to by
* wp->authType that was allocated just before the if()
* statement that we are currently in. Thanks to Simon Byholm.
*/
bfree(B_L, wp->authType);
wp->authType = bstrdup(B_L, value);
websDecode64(userAuth, ++cp, sizeof(userAuth));
} else {
websDecode64(userAuth, value, sizeof(userAuth));
}
/*
* Split userAuth into userid and password
*/
if ((cp = gstrchr(userAuth, ':')) != NULL) {
*cp++ = '\0';
}
if (cp) {
wp->userName = bstrdup(B_L, userAuth);
wp->password = bstrdup(B_L, cp);
} else {
wp->userName = bstrdup(B_L, T(""));
wp->password = bstrdup(B_L, T(""));
}
/*
* Set the flags to indicate digest authentication
*/
wp->flags |= WEBS_AUTH_BASIC;
} else {
#ifdef DIGEST_ACCESS_SUPPORT
/*
* The incoming value is slightly more complicated (Digest)
*/
char_t *np; /* pointer to end of tag name */
char_t tp; /* temporary character holding space */
char_t *vp; /* pointer to value */
char_t *npv; /* pointer to end of value, "next" pointer */
char_t tpv; /* temporary character holding space */
/*
* Set the flags to indicate digest authentication
*/
wp->flags |= WEBS_AUTH_DIGEST;
/*
* Move cp to Next word beyond "Digest",
* vp to first char after '='.
*/
cp = value;
while (isgoodchar(*cp)) {
cp++;
}
while (!isgoodchar(*cp)) {
cp++;
}
/*
* Find beginning of value
*/
vp = gstrchr(cp, '=');
while (vp) {
/*
* Zero-terminate tag name
*/
np = cp;
while (isgoodchar(*np)) {
np++;
}
tp = *np;
*np = 0;
/*
* Advance value pointer to first legit character
*/
vp++;
while (!isgoodchar(*vp)) {
vp++;
}
/*
* Zero-terminate value
*/
npv = vp;
while (isgoodchar(*npv)) {
npv++;
}
tpv = *npv;
*npv = 0;
/*
* Extract the fields
*/
if (gstricmp(cp, T("username")) == 0) {
wp->userName = bstrdup(B_L, vp);
} else if (gstricmp(cp, T("response")) == 0) {
wp->digest = bstrdup(B_L, vp);
} else if (gstricmp(cp, T("opaque")) == 0) {
wp->opaque = bstrdup(B_L, vp);
} else if (gstricmp(cp, T("uri")) == 0) {
wp->uri = bstrdup(B_L, vp);
} else if (gstricmp(cp, T("realm")) == 0) {
wp->realm = bstrdup(B_L, vp);
} else if (gstricmp(cp, T("nonce")) == 0) {
wp->nonce = bstrdup(B_L, vp);
} else if (gstricmp(cp, T("nc")) == 0) {
wp->nc = bstrdup(B_L, vp);
} else if (gstricmp(cp, T("cnonce")) == 0) {
wp->cnonce = bstrdup(B_L, vp);
} else if (gstricmp(cp, T("qop")) == 0) {
wp->qop = bstrdup(B_L, vp);
}
/*
* Restore tag name and value zero-terminations
*/
*np = tp;
*npv = tpv;
/*
* Advance tag name and value pointers
*/
cp = npv;
while (*cp && isgoodchar(*cp)) {
cp++;
}
while (*cp && !isgoodchar(*cp)) {
cp++;
}
if (*cp) {
vp = gstrchr(cp, '=');
} else {
vp = NULL;
}
}
#endif /* DIGEST_ACCESS_SUPPORT */
} /* if (gstrcmp(wp->authType)) */
/*
* Parse the content length
*/
} else if (gstrcmp(key, T("content-length")) == 0) {
/*
* 11 Oct 02 BgP -- The server would crash if an attacker sent a POST
* message with a content-length value <= 0. We assume that anyone
* sending this is malicious, and the POST is read from the socket,
* but it is ignored, and the socket is closed.
*/
wp->clen = gatoi(value);
if (wp->clen > 0)
{
wp->flags |= WEBS_CLEN;
websSetVar(wp, T("CONTENT_LENGTH"), value);
}
else
{
wp->clen = 0;
}
/*
* Parse the content type
*/
} else if (gstrcmp(key, T("content-type")) == 0) {
websSetVar(wp, T("CONTENT_TYPE"), value);
#ifdef WEBS_KEEP_ALIVE_SUPPORT
} else if (gstrcmp(key, T("connection")) == 0) {
strlower(value);
if (gstrcmp(value, T("keep-alive")) == 0) {
wp->flags |= WEBS_KEEP_ALIVE;
}
#endif
#ifdef WEBS_PROXY_SUPPORT
/*
* This may be useful if you wish to keep a local cache of web pages
* for proxied requests.
*/
} else if (gstrcmp(key, T("pragma")) == 0) {
char_t tmp[256];
gstrncpy(tmp, value, TSZ(tmp));
strlower(tmp);
if (gstrstr(tmp, T("no-cache"))) {
wp->flags |= WEBS_DONT_USE_CACHE;
}
#endif /* WEBS_PROXY_SUPPORT */
/*
* Store the cookie
*/
} else if (gstrcmp(key, T("cookie")) == 0) {
wp->flags |= WEBS_COOKIE;
wp->cookie = bstrdup(B_L, value);
#ifdef WEBS_IF_MODIFIED_SUPPORT
/*
* See if the local page has been modified since the browser last
* requested this document. If not, just return a 302
*/
} else if (gstrcmp(key, T("if-modified-since")) == 0) {
char_t *cmd;
time_t tip = 0;
if ((cp = gstrchr(value, ';')) != NULL) {
*cp = '\0';
?? 快捷鍵說(shuō)明
復(fù)制代碼
Ctrl + C
搜索代碼
Ctrl + F
全屏模式
F11
切換主題
Ctrl + Shift + D
顯示快捷鍵
?
增大字號(hào)
Ctrl + =
減小字號(hào)
Ctrl + -