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

📄 http.c

📁 Dag Erling http library source code
💻 C
📖 第 1 页 / 共 4 页
字号:
	case HTTP_SEE_OTHER:		/*		 * Not so fine, but we still have to read the		 * headers to get the new location.		 */		break;	case HTTP_NEED_AUTH:		if (request->need_auth) {			/*			 * We already sent out authorization code,			 * so there's nothing more we can do.			 */			_http_seterr(conn->err);			return(-1);		}		/* try again, but send the password this time */		if (request->verbose)			_fetch_info("server requires authorization");		break;	case HTTP_NEED_PROXY_AUTH:		/*		 * If we're talking to a proxy, we already sent		 * our proxy authorization code, so there's		 * nothing more we can do.		 */		_http_seterr(conn->err);		return(-1);	case HTTP_BAD_RANGE:		/*		 * This can happen if we ask for 0 bytes because		 * we already have the whole file.  Consider this		 * a success for now, and check sizes later.		 */		request->last_read_short = 1;		break;	case HTTP_PROTOCOL_ERROR:		/* fall through */	case -1:		/* RMDBGLOG((ENABLE,"Error getting reply : errno = %d\n", errno)); */		_fetch_syserr();		return(-1);	default:		_http_seterr(conn->err);		if (!request->verbose)			return (-1);		/* fall through so we can get the full error message */	}	return(0);}/** * Get headers from a HTTP reply * @param request - the HTTP request * @return < 0 on error */static RMint32 __http_get_headers(struct http_request_s *request){	struct url *url, *purl;	conn_t *conn;	const RMascii *p;	hdr_t h;	if (request == NULL)		return(-1);	url = request->url;	purl = request->purl;	conn = request->conn;	/* get headers */	do {		switch ((h = _http_next_header(conn, &p))) {		case hdr_syserror:			_fetch_syserr();			return (-1);		case hdr_error:			_http_seterr(HTTP_PROTOCOL_ERROR);			return (-1);		case hdr_content_length:			_http_parse_length(p, &request->clength);			break;		case hdr_content_range:			_http_parse_range(p, &request->offset, &request->length, &request->size);			break;		case hdr_last_modified:			_http_parse_mtime(p, &request->mtime);			break;		case hdr_location:			if (!HTTP_REDIRECT(conn->err))				break;			if (request->new)				RMFree(request->new);			if (request->verbose)				_fetch_info("%d redirect to %s", conn->err, p);			if (*p == '/')				/* absolute path */				request->new = fetchMakeURL(url->scheme, url->host, url->port, p,				    url->user, url->pwd);			else				request->new = fetchParseURL(p);			if (request->new == NULL) {				/* XXX should set an error code */				RMDBGLOG((ENABLE, "failed to parse new URL\n"));				return(-1);			}			if (!*request->new->user && !*request->new->pwd) {				strcpy(request->new->user, url->user);				strcpy(request->new->pwd, url->pwd);			}			request->new->offset = url->offset;			request->new->length = url->length;			break;		case hdr_transfer_encoding:			/* XXX weak test*/			request->chunked = (strcasecmp(p, "chunked") == 0);			/* RMDBGLOG((HTTPDEBUG,"Chunked !!! %d\n", request->chunked)); */			break;		case hdr_www_authenticate:			if (conn->err != HTTP_NEED_AUTH)				break;			/* if we were smarter, we'd check the method and realm */			break;		case hdr_connection:			/* Assume the connection will close, need to reopen in			 * case of open connection */			if (request->open)				request->need_reopen = 1;		case hdr_end:			/* fall through */		case hdr_unknown:			/* ignore */			break;		}	} while (h > hdr_end);	return(0);}	/** * Send a single HTTP request * @param request - the HTTP request * @return -1 on error, 0 if redirect, 1 if HIT. In case of a redirect, the * "new" field is set to the redirected URL. */ static RMint32 _http_single_request(struct http_request_s *request){	RMint32 status; 	if (request == NULL)		return(-1);	request->new = NULL;	request->chunked = 0;	request->offset = 0;	request->clength = -1;	request->length = -1;	request->mtime = 0;		status = __http_connect(request);	if (status < 0)		return(-1);		status = __http_send_request(request);	if (status < 0)		return(status);get_reply:	status = __http_get_reply(request);	if (status < 0)		return(status);	status = __http_get_headers(request);	if (status < 0) 		return(status);	if( request->conn->err == HTTP_CONTINUE) {		goto get_reply;	}	/* we need to provide authentication */	if (request->conn->err == HTTP_NEED_AUTH) {		request->e = request->conn->err;		request->need_auth = 1;		_fetch_close(request->conn);		request->conn = NULL;		return(0);	}	/* requested range not satisfiable */	if (request->conn->err == HTTP_BAD_RANGE) {		if (request->url->offset == request->size && request->url->length == 0) {			/* asked for 0 bytes; fake it */			request->offset = request->url->offset;			request->conn->err = HTTP_OK;			return(1);		} else {			_http_seterr(request->conn->err);			return(-1);		}	}	/* we have a hit or an error */	if (request->conn->err == HTTP_OK || 	    request->conn->err == HTTP_PARTIAL || 	    HTTP_ERROR(request->conn->err))		return(1);	/* all other cases: we got a redirect */	request->e = request->conn->err;	request->need_auth = 0;	_fetch_close(request->conn);	request->conn = NULL;	if (!request->new) {		RMDBGLOG((ENABLE, "redirect with no new location\n"));		return(1);	}	return(0);}/* * Send a request and process the reply * * @param URL - url to fetch * @param op - operation requested (GET, POST, ...) * @param us - url stat * @param purl - proxy url * @param flasg * @return HTTPFile * * */static HTTPFile *_http_request(struct url *URL, const RMascii *op, struct url_stat *us,    struct url *purl, RMHTTPFlags flags){	struct http_request_s *request;	RMint32 i, n, status;	HTTPFile *f;	request = (struct http_request_s *) RMMalloc(sizeof(struct http_request_s));	if (request == NULL){		RMDBGLOG((ENABLE,"Cannot malloc\n"));		return NULL;	}	RMMemset(request, 0, sizeof(struct http_request_s));	/* Handle the flags */	request->direct = (flags & RM_HTTP_NO_PROXY);	request->noredirect = (flags & RM_HTTP_NO_REDIRECT);	request->verbose = (flags & RM_HTTP_VERBOSE);	request->open = (flags & RM_HTTP_OPEN_CACHED);	if (request->open){		request->cache = init_cache(CACHENBUFFER, CACHEBUFFERSIZE);		if (request->cache == NULL)			goto ouch;	}	if ((flags & RM_HTTP_CUSTOM_HEADER) && (fetchCustomHeader != NULL)){		request->custom_header = RMMallocAndDuplicateAscii(fetchCustomHeader);	}	if ((flags & RM_HTTP_CUSTOM_HOOKS) && (fetchCustomCookie != NULL) && (fetchCustomHooks != NULL)){		request->custom_cookie = fetchCustomCookie;		request->custom_hooks = fetchCustomHooks;		fetchCustomCookie = NULL;		fetchCustomHooks = NULL;		/* Perform a custom open hook if present */		if (request->custom_hooks->open != NULL)			request->custom_hooks->open(request->custom_cookie);	}		/* try the provided URL first */	request->url = URL;	/* First request, open mode, only HEAD */	if (request->open)		request->op = "HEAD";	else		request->op = op;	request->us = us;	request->purl = purl;	request->flags = flags;	request->e = HTTP_PROTOCOL_ERROR;	request->need_auth = 0;	request->size = -1;	if (request->direct && request->purl) {		fetchFreeURL(request->purl);		request->purl = NULL;	}	/* if the A flag is set, we only get one try */	n = request->noredirect ? 1 : MAX_REDIRECT;	i = 0;	do {		status = _http_single_request(request);		if (status < 0)			goto ouch;		else if (status > 0)			break;		if (request->url != URL)			fetchFreeURL(request->url);		request->url = request->new;		request->new = NULL;	} while (++i < n);	/* we failed, or ran out of retries */	if (request->conn == NULL) {		_http_seterr(request->e);		goto ouch;	}	if (request->open)		request->op = op;	RMDBGLOG((HTTPDEBUG, "offset %lld, length %lld,"		  " size %lld, clength %lld\n",		  (RMint64)request->offset, (RMint64)request->length,		  (RMint64)request->size, (RMint64)request->clength));	/* check for inconsistencies, computed length and clength should be the same if set */	if (request->clength != -1 && request->length != -1 && request->clength != request->length) {		_http_seterr(HTTP_PROTOCOL_ERROR);		goto ouch;	}	/* Content-Length: not provided, use computed length if we had a Range: */	if (request->clength == -1 && request->length != -1)		request->clength = request->length;	/* We allow request->length != request->size, length is length of this	 * request, whereas size is the total length of the target */	/* if (request->length != -1 && request->size != -1 && request->length != request->size) {		_http_seterr(HTTP_PROTOCOL_ERROR);		goto ouch;	}*/	/* For a closed connection, use the content length as the size */	if (request->size == -1 && !request->open)		request->size = request->clength;	/* fill in stats */	if (request->us) {		request->us->size = request->size;		request->us->atime = request->us->mtime = request->mtime;	}	/* too far? */	if (URL->offset > 0 && request->offset > URL->offset) {		_http_seterr(HTTP_PROTOCOL_ERROR);		goto ouch;	}	/* report back real offset and size */	URL->offset = request->offset;	URL->length = request->clength;	/* wrap it up in a HTTPFile*/	if ((f = _http_funopen(request)) == NULL) {		_fetch_syserr();		goto ouch;	}	/*if (request->url != URL)		fetchFreeURL(request->url);	if (request->purl)		fetchFreeURL(request->purl);*/	if (HTTP_ERROR(request->conn->err)) {		fetchClose(f);		f = NULL;	}	return (f);ouch:	if (request->cache)		destroy_cache(request->cache);	if (request->url)		fetchFreeURL(request->url);	if (request->purl)		fetchFreeURL(request->purl);	if (request->conn != NULL)		_fetch_close(request->conn);	if (request->host != NULL)		RMFree(request->host);	if (request->custom_header != NULL)		RMFree(request->custom_header);	RMFree(request);	return (NULL);}/***************************************************************************** * Entry points *//** * Set custom hooks. The custom hooks will be used if the * RM_HTTP_CUSTOM_HOOKS flag is set during the fetchOpen. * * @param cookie - cookie used by the hooks. * @param hooks - set of custom callbacks that use the cookie. * @return void */void fetchSetCustomHooks(void *cookie, HttpHookOps *hooks){	fetchCustomCookie = cookie;	fetchCustomHooks = hooks;}/** * Set custom headers. The custom headers will be used if the * RM_HTTP_CUSTOM_HEADER flag is set during the fetchOpen. * * @param header - custom header, should use "\r\n" as end of line, NULL *                 terminated. The final "\r\n" will be added upon sending over *                 the wire.  This string will be duplicated by each fetchOpen, *                 so it should ne be freed before the fetchOpen. * @return void */void fetchSetCustomHeader(RMascii *header){	fetchCustomHeader = header;}/* * Retrieve and stat a file by HTTP */HTTPFile *fetchXGetHTTP(struct url *URL, struct url_stat *us, RMHTTPFlags flags){	return (_http_request(URL, "GET", us, _http_get_proxy(flags), flags));}/* * Retrieve a file by HTTP */HTTPFile *fetchGetHTTP(struct url *URL, RMHTTPFlags flags){	return (fetchXGetHTTP(URL, NULL, flags));}HTTPFile *fetchOpen(const RMascii *URL, RMHTTPFlags flags){	struct url *url;	RMDBGLOG((ENABLE,"Open %s\n", URL));	url = fetchParseURL(URL);	if (url == NULL)		return(NULL);		return(fetchXGetHTTP(url, NULL, flags));}/* * Get an HTTP document's metadata */RMint32fetchStatHTTP(struct url *URL, struct url_stat *us, RMHTTPFlags flags){	HTTPFile *f;	f = _http_request(URL, "HEAD", us, _http_get_proxy(flags), flags);	if (f == NULL)		return (-1);	fetchClose(f);	return (0);}

⌨️ 快捷键说明

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