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

📄 http.c

📁 Dag Erling http library source code
💻 C
📖 第 1 页 / 共 4 页
字号:
	while (*str && *hdr && tolower(*str++) == tolower(*hdr++))		/* nothing */;	if (*str || *hdr != ':')		return (NULL);	while (*hdr && isspace(*++hdr))		/* nothing */;	return (hdr);}/* * Get the next header and return the appropriate symbolic code. */static hdr_t_http_next_header(conn_t *conn, const RMascii **p){	RMint32 i;	if (_fetch_getln(conn) == -1)		return (hdr_syserror);	while (conn->buflen && isspace(conn->buf[conn->buflen - 1]))		conn->buflen--;	conn->buf[conn->buflen] = '\0';	if (conn->buflen == 0)		return (hdr_end);	/*	 * We could check for malformed headers but we don't really care.	 * A valid header starts with a token immediately followed by a	 * colon; a token is any sequence of non-control, non-whitespace	 * characters except "()<>@,;:\\\"{}".	 */	for (i = 0; hdr_names[i].num != hdr_unknown; i++)		if ((*p = _http_match(hdr_names[i].name, (RMascii *)conn->buf)) != NULL)			return (hdr_names[i].num);	return (hdr_unknown);}/* * Parse a last-modified header */static RMint32_http_parse_mtime(const RMascii *p, time_t *mtime){	RMascii locale[64], *r;	struct tm tm;	strncpy(locale, setlocale(LC_TIME, NULL), sizeof(locale));	setlocale(LC_TIME, "C");	r = (RMascii *) strptime(p, "%a, %d %b %Y %H:%M:%S GMT", &tm);	/* XXX should add support for date-2 and date-3 */	setlocale(LC_TIME, locale);	if (r == NULL)		return (-1);	RMDBGLOG((HTTPDEBUG,"    last modified: [%04d-%02d-%02d "		  "%02d:%02d:%02d]\n",		  tm.tm_year + 1900, tm.tm_mon + 1, tm.tm_mday,		  tm.tm_hour, tm.tm_min, tm.tm_sec));	*mtime = my_timegm(&tm);	return (0);}/* * Parse a content-length header */static RMint32_http_parse_length(const RMascii *p, RMint64 *length){	RMint64 len;	for (len = 0; *p && isdigit(*p); ++p)		len = len * 10 + (*p - '0');	if (*p)		return (-1);	RMDBGLOG((HTTPDEBUG, "    content length: [%lld]\n",	    (RMint64)len));	*length = len;	return (0);}/* * Parse a content-range header */static RMint32_http_parse_range(const RMascii *p, RMint64 *offset, RMint64 *length, RMint64 *size){	RMint64 first, last, len;	if (strncasecmp(p, "bytes ", 6) != 0)		return (-1);	p += 6;	if (*p == '*') {		first = last = -1;		++p;	} else {		for (first = 0; *p && isdigit(*p); ++p)			first = first * 10 + *p - '0';		if (*p != '-')			return (-1);		for (last = 0, ++p; *p && isdigit(*p); ++p)			last = last * 10 + *p - '0';	}	if (first > last || *p != '/')		return (-1);	for (len = 0, ++p; *p && isdigit(*p); ++p)		len = len * 10 + *p - '0';	if (*p || len < last - first + 1)		return (-1);	if (first == -1) {		RMDBGLOG((HTTPDEBUG, "    content range: [*/%lld]\n",		    (RMint64)len));		*length = 0;	} else {		RMDBGLOG((HTTPDEBUG, "    content range: [%lld-%lld/%lld]\n",		    (RMint64)first, (RMint64)last, (RMint64)len));		*length = last - first + 1;	}	*offset = first;	*size = len;	return (0);}/***************************************************************************** * Helper functions for authorization *//* * Base64 encoding */static RMascii *_http_base64(const RMascii *src){	static const RMascii base64[] =	    "ABCDEFGHIJKLMNOPQRSTUVWXYZ"	    "abcdefghijklmnopqrstuvwxyz"	    "0123456789+/";	RMascii *str, *dst;	RMuint32 l;	RMint32 t, r;	l = strlen(src);	if ((str = RMMalloc(((l + 2) / 3) * 4 + 1)) == NULL)		return (NULL);	dst = str;	r = 0;	while (l >= 3) {		t = (src[0] << 16) | (src[1] << 8) | src[2];		dst[0] = base64[(t >> 18) & 0x3f];		dst[1] = base64[(t >> 12) & 0x3f];		dst[2] = base64[(t >> 6) & 0x3f];		dst[3] = base64[(t >> 0) & 0x3f];		src += 3; l -= 3;		dst += 4; r += 4;	}	switch (l) {	case 2:		t = (src[0] << 16) | (src[1] << 8);		dst[0] = base64[(t >> 18) & 0x3f];		dst[1] = base64[(t >> 12) & 0x3f];		dst[2] = base64[(t >> 6) & 0x3f];		dst[3] = '=';		dst += 4;		r += 4;		break;	case 1:		t = src[0] << 16;		dst[0] = base64[(t >> 18) & 0x3f];		dst[1] = base64[(t >> 12) & 0x3f];		dst[2] = dst[3] = '=';		dst += 4;		r += 4;		break;	case 0:		break;	}	*dst = 0;	return (str);}/* * Encode username and password */static RMint32_http_basic_auth(conn_t *conn, const RMascii *hdr, const RMascii *usr, const RMascii *pwd){	RMascii *upw, *auth;	RMint32 r;	RMDBGLOG((HTTPDEBUG, "usr: [%s]\n", usr));	RMDBGLOG((HTTPDEBUG, "pwd: [%s]\n", pwd));	upw = RMMalloc(strlen(usr)+strlen(pwd)+2);	if (sprintf(upw, "%s:%s", usr, pwd) == -1)		return (-1);	auth = _http_base64(upw);	RMFree(upw);	if (auth == NULL)		return (-1);	r = _http_cmd(conn, "%s: Basic %s", hdr, auth);	RMFree(auth);	return (r);}/* * Send an authorization header */static RMint32_http_authorize(conn_t *conn, const RMascii *hdr, const RMascii *p){	/* basic authorization */	if (strncasecmp(p, "basic:", 6) == 0) {		RMascii *user, *pwd, *str;		RMint32 r;		/* skip realm */		for (p += 6; *p && *p != ':'; ++p)			/* nothing */ ;		if (!*p || strchr(++p, ':') == NULL)			return (-1);		str = RMMallocAndDuplicateAscii(p);		if (str == NULL)			return (-1); /* XXX */		user = str;		pwd = strchr(str, ':');		*pwd++ = '\0';		r = _http_basic_auth(conn, hdr, user, pwd);		RMFree(str);		return (r);	}	return (-1);}/***************************************************************************** * Helper functions for connecting to a server or proxy *//* * Connect to the correct HTTP server or proxy. */static conn_t *_http_connect(struct url *URL, struct url *purl, RMHTTPFlags flags){	conn_t *conn;	RMint32 verbose;	RMint32 af;#ifdef INET6	af = AF_UNSPEC;#else	af = AF_INET;#endif	verbose = (flags & RM_HTTP_VERBOSE);	if (flags & RM_HTTP_IPV4)		af = AF_INET;#ifdef INET6	else if (flags & RM_HTTP_IPV6)		af = AF_INET6;#endif	if (purl && strcasecmp(URL->scheme, SCHEME_HTTPS) != 0) {		URL = purl;	} else if (strcasecmp(URL->scheme, SCHEME_FTP) == 0) {		/* can't talk http to an ftp server */		/* XXX should set an error code */		return (NULL);	}	if ((conn = _fetch_connect(URL->host, URL->port, af, verbose)) == NULL)		/* _fetch_connect() has already set an error code */		return (NULL);	if (strcasecmp(URL->scheme, SCHEME_HTTPS) == 0 &&	    _fetch_ssl(conn, verbose) == -1) {		_fetch_close(conn);		/* grrr */		errno = ECONNREFUSED;		_fetch_syserr();		return (NULL);	}	return (conn);}static struct url *_http_get_proxy(RMHTTPFlags flags){	struct url *purl;	RMascii *p;	if (flags & RM_HTTP_NO_PROXY)		return (NULL);	if (((p = getenv("HTTP_PROXY")) || (p = getenv("http_proxy"))) &&	    (purl = fetchParseURL(p))) {		if (!*purl->scheme)			strcpy(purl->scheme, SCHEME_HTTP);		if (!purl->port)			purl->port = _fetch_default_proxy_port(purl->scheme);		if (strcasecmp(purl->scheme, SCHEME_HTTP) == 0)			return (purl);		fetchFreeURL(purl);	}	return (NULL);}/***************************************************************************** * Core *//** * Connect to a specified server * @param request - the HTTP request * @return < 0 on error */static RMint32 __http_connect(struct http_request_s *request){	struct url *url, *purl;	if (request == NULL)		return(-1);	url = request->url;	purl = request->purl;	/* check port */	if (!url->port)		url->port = _fetch_default_port(url->scheme);	/* were we redirected to an FTP URL? */	if (purl == NULL && strcmp(url->scheme, SCHEME_FTP) == 0) {		RMDBGLOG((ENABLE,"Cannot redirect HTTP to FTP\n"));		return(-1);	}	/* connect to server or proxy */	if ((request->conn = _http_connect(url, purl, request->flags)) == NULL)		return(-1);		if (request->host)		RMFree(request->host);	request->host = (RMascii *) RMMalloc(strlen(url->host)+16);	strcpy(request->host, url->host);#ifdef INET6	if (strchr(url->host, ':')) {		snprintf(request->host, strlen(url->host)+15, "[%s]", url->host);	}#endif	if (url->port != _fetch_default_port(url->scheme)) {		snprintf(request->host + strlen(request->host), 15, ":%ld", url->port);	}	return(0);}/**  * Send a HTTP request * @param request - the HTTP request * @return <0 on error */static RMint32 __http_send_request(struct http_request_s *request){	struct url *url, *purl;	conn_t *conn;	const RMascii *p;	RMint32 status;	if (request == NULL)		return(-1);	url = request->url;	purl = request->purl;	conn = request->conn;	/* send request */	if (request->verbose)		_fetch_info("requesting %s://%s%s",		    url->scheme, request->host, url->doc);	if (purl) {		SAFE(_http_cmd(conn, "%s %s://%s%s HTTP/1.1",		    request->op, url->scheme, request->host, url->doc));	} else {		SAFE(_http_cmd(conn, "%s %s HTTP/1.1",		    request->op, url->doc));	}	/* virtual host */	SAFE(_http_cmd(conn, "Host: %s", request->host));	/* proxy authorization */	if (purl) {		if (*purl->user || *purl->pwd){			SAFE(_http_basic_auth(conn, "Proxy-Authorization",			    purl->user, purl->pwd));		} else if ((p = getenv("HTTP_PROXY_AUTH")) != NULL && *p != '\0') {			SAFE(_http_authorize(conn, "Proxy-Authorization", p));		}	}	/* server authorization */	if (request->need_auth || *url->user || *url->pwd) {		if (*url->user || *url->pwd){			SAFE(_http_basic_auth(conn, "Authorization", url->user, url->pwd));		} else if ((p = getenv("HTTP_AUTH")) != NULL && *p != '\0') {			SAFE(_http_authorize(conn, "Authorization", p));		} else {			_http_seterr(HTTP_NEED_AUTH);			return(-1);		}	}	/* other headers */	if ((p = getenv("HTTP_REFERER")) != NULL && *p != '\0') {		if (strcasecmp(p, "auto") == 0) {			SAFE(_http_cmd(conn, "Referer: %s://%s%s", url->scheme, request->host, url->doc));		} else {			SAFE(_http_cmd(conn, "Referer: %s", p));		}	}	/* Custom header */	if (request->custom_header){		SAFE(_http_cmd(conn,"%s", request->custom_header));	}		if ((p = getenv("HTTP_USER_AGENT")) != NULL && *p != '\0')		SAFE(_http_cmd(conn, "User-Agent: %s", p));	/*else		SAFE(_http_cmd(conn, "User-Agent: %s " _LIBFETCH_VER, getprogname()));*/	if (url->offset > 0 || request->open){		if (request->open){			SAFE(_http_cmd(conn, "Range: bytes=%lld-%lld", (RMint64)url->offset, (RMint64)url->offset_end));		} else {			SAFE(_http_cmd(conn, "Range: bytes=%lld-", (RMint64)url->offset));		}	}	if (!request->open){		SAFE(_http_cmd(conn, "Connection: close"));	}	SAFE(_http_cmd(conn, ""));	return(0);}/** * Get HTTP reply from the server * @param request - the HTTP request * @return < 0 on error */static RMint32 __http_get_reply(struct http_request_s *request){	conn_t *conn;	if (request == NULL){		/* RMDBGLOG((ENABLE,"Null request\n")); */		return(-1);	}	conn = request->conn;		/* get reply */	switch (_http_get_reply(conn)) {	case HTTP_OK:		if (request->url && request->url->offset > 0){			/* We should have received a HTTP_PARTIAL, see RFC			 * 2616, section 14.35 */			RMDBGLOG((HTTPDEBUG,"HTTP_OK received instead of HTTP_PARTIAL, range not satisfied\n"));			request->last_read_short = 1;			return(-1);		}		break;	case HTTP_CONTINUE:		break;				/* Retry after we read headers */	case HTTP_PARTIAL:		/* fine */		break;	case HTTP_MOVED_PERM:	case HTTP_MOVED_TEMP:

⌨️ 快捷键说明

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