⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 webs.c

📁 嵌入式Linux系统用的web server,开源代码,非常好用
💻 C
📖 第 1 页 / 共 5 页
字号:
	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';

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -