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

📄 http.c

📁 Dag Erling http library source code
💻 C
📖 第 1 页 / 共 4 页
字号:
		request->url->offset_end = request->size - 1;		len = request->url->offset_end - request->url->offset + 1;	}	/*fprintf(stderr,"Read %lu -> %lu (%ld)\n", 	        (RMuint32) request->url->offset, 		(RMuint32) request->url->offset_end,		(RMuint32) request->url->offset_end - (RMuint32) request->url->offset + 1);*/		/* Keep them for later */	start_save = request->url->offset;	end_save = request->url->offset_end;	plen = end_save - start_save + 1;	start = ( start_save & (~((1<<CACHELOG2)-1)));	offset = start_save & ((1<<CACHELOG2)-1);	do {		RMint64 read = mmin(plen, CACHEBUFFERSIZE - offset);		cached = get_buffer_cache(request->cache, start, &buf_cache);		RMDBGLOG((HTTPDEBUG,"request = %p, cache = %p, buf_cache = %p\n", request, request->cache, buf_cache));		if (cached < 0){			/* Not cached */			request->url->offset = start;			request->url->offset_end = mmin(start+CACHEBUFFERSIZE-1, (request->size-1));			status = __http_read(v, buf_cache);			if (status < 0){				RMDBGLOG((ENABLE,"Error reading %lu->%lu : %ld %ld %ld\n", 						(RMuint32) request->url->offset, 						(RMuint32) request->url->offset_end,						status, request->conn->err, fetchLastErrCode));				request->url->offset = start_save;				request->url->offset_end = end_save;				return status;			}		}		bcopy(buf_cache+offset, buf, read);		buf+=read;		plen-=read;		offset = 0;		start += CACHEBUFFERSIZE;	} while (plen > 0);	request->url->offset = end_save + 1;	return(end_save-start_save+1);}static RMint32__http_read_uncached(void *v, RMuint8 *buf, RMuint32 len){	struct httpio *io = (struct httpio *)v;	struct http_request_s *request = io->request;	RMint32 total_read = 0;	RMint32 nread = 0;	while (1){		if (request->need_reopen){			RMint32 status;						RMDBGLOG((HTTPDEBUG,"Need to open a new connection\n"));			status = _fetch_close(request->conn);			if (status < 0)				perror("Error closing previous connection, keep going");			/* New connection */			status = _http_single_request(request);			/* No redirect at this point allowed */			if (status <= 0){				if (request->last_read_short){					/* EOF */					io->eof = 1;					request->last_read_short = 0;					return total_read;				} else {					/* Error */					return(-1);				}			}			request->need_reopen = 0;			/* Reset the chunk size */			io->chunksize = 0;		}			while (len > 0){			nread = _http_fillbuf(io, len, buf);			if (nread <= 0){				RMDBGLOG((HTTPDEBUG,"nread <= 0 : %ld\n", total_read));				/* For some servers (Intel DTCPIP for example),				 * a bad range is not a problem, so the request				 * above will not fail at EOF, but the read				 * should at least ... */				if (request->last_read_short)					return total_read;				break;			}			total_read += nread;			len -= nread;			buf += nread;		}				if (!total_read && io->error){			RMDBGLOG((ENABLE,"IO error %ld\n", io->error));			return (-1);		}		request->url->offset += total_read;		if (nread == 0){			/* Might be end of file or peer closed connection (time			 * out, ...), so try to reopen, if it was end of file,			 * it will fail */			request->need_reopen = 1;			request->last_read_short = 1;			continue;		}		request->last_read_short = 0;		return (total_read);	}	return(-1);}	/* * Read function */static RMint32_http_readfn(void *v, RMuint8 *buf, RMuint32 len){	struct httpio *io = (struct httpio *)v;	struct http_request_s *request = io->request;	if (io->error){		RMDBGLOG((ENABLE,"IO error %ld\n", io->error));		return (-1);	}	if (io->eof){		RMDBGLOG((ENABLE,"IO EOF %ld\n", io->eof));		return (0);	}	if (request->open)		return (__http_read_cached(v, buf, len));	/* If custom decryption hooks are being used, ... */	if ((request->custom_cookie != NULL) &&	    (request->custom_hooks  != NULL) &&	    (request->custom_hooks->preread  != NULL) &&	    (request->custom_hooks->postread != NULL)) {		RMint32 result;		RMint32 new_read_size;		RMint32 nread;		RMint32 actual_read;		RMint32 more_data = 0;		RMint32 bytes_left = len;		RMint32 total_read = 0;		RMuint8 *buf_ptr = buf;		do {			/* If reopening the connection and resynchronizing the decryption block boundary are necessary, ... */			if ((request->need_reopen) && (request->custom_hooks->reopen != NULL)) {				if ((result = request->custom_hooks->reopen(request->custom_cookie)) < 0)					return result;			}			/* Truncate read size if necessary to prevent reading beyond a decryption block boundary */			if ((new_read_size = request->custom_hooks->preread(request->custom_cookie, buf_ptr, bytes_left)) <= 0)				return new_read_size;			/* Fill up the buffer without going beyond the end of a decryption block boundary */			if ((nread = __http_read_uncached(v, buf_ptr, new_read_size)) <= 0)				return nread;			/* Decrypt the data */			if ((actual_read = request->custom_hooks->postread(request->custom_cookie, buf_ptr, nread, &more_data)) <= 0)				return actual_read;			/* Update the position */			bytes_left -= actual_read;			total_read += actual_read;			buf_ptr    += actual_read;		} while ((more_data != 0) && (bytes_left > 0));		return(total_read);	}	return (__http_read_uncached(v, buf, len));}RMint32 fetchRead(RMuint8 *buf, RMint32 size, HTTPFile * file){	return(_http_readfn((void *)file, buf, (RMuint32) size));}/* * Close function */static RMint32_http_closefn(void *v){	struct httpio *io = (struct httpio *)v;	RMint32 r;	struct http_request_s *request = io->request;	/* Perform a custom close hook if present */	if ((request->custom_cookie != NULL) &&	    (request->custom_hooks  != NULL) &&	    (request->custom_hooks->close != NULL))		request->custom_hooks->close(request->custom_cookie);	r = _fetch_close(CONN(io));	if (io->request->purl)		fetchFreeURL(io->request->purl);	if (io->request->url)		fetchFreeURL(io->request->url);	if (io->request->host)		RMFree(io->request->host);	if (io->request->cache)		destroy_cache(io->request->cache);	if (io->request->custom_header != NULL)		RMFree(io->request->custom_header);	if (io->request)		RMFree(io->request);	RMFree(io);	return (r);}RMint32 fetchClose(HTTPFile * file){	return (_http_closefn((void *) file));}/* * Seek function */static RMint32 _http_seekn(void *cookie, RMint64 *position, RMint32 whence){	struct httpio *io = (struct httpio *)cookie;	struct http_request_s *request = io->request;	RMint64 newpos = -1;	/* Perform a custom seek hook if present */	if ((request->custom_cookie != NULL) &&	    (request->custom_hooks  != NULL) &&	    (request->custom_hooks->seek != NULL))		request->custom_hooks->seek(request->custom_cookie, *position, whence);	if (whence == SEEK_SET){		newpos = *position;	}else if (whence == SEEK_CUR){		newpos = request->url->offset + *position;	}else if (whence == SEEK_END){		newpos = (RMint64) request->size + *position;	}	RMDBGLOG((HTTPDEBUG,"Seeking : newpos = %lld pos = %lld\n", newpos, *position));	if (newpos < 0){		RMDBGLOG((ENABLE,"Seeking out of bounds : %lld\n", newpos));		return(-1);	}		/* See man lseek, seeking beyond end of file should not return an error	 * (allow creation of sparse file for example) */#if 0	if ( (request->size != -1) && (newpos > request->size) ){		RMDBGLOG((ENABLE,"Seeking out of bounds : size = %lld, newpos = %lld\n", request->size, newpos));		return(-1);	}#endif	if ((request->url->offset != newpos) && 	    (request->open == 0)){		/* Closed connection request, we need to reopen a connection */		if (request->open == 0)			request->need_reopen = 1;	}	request->url->offset = newpos;	*position = newpos;	io->eof = 0;	return(0);}RMint32 fetchSeek(HTTPFile * file, RMint64 offset, RMint32 whence){	RMint64 pos=offset;	return(_http_seekn((void *) file, &pos, whence));}RMint64 fetchTell(HTTPFile * file){	RMint64 pos=0;	RMint32 status;		SAFE(_http_seekn((void *) file, &pos, SEEK_CUR));	return pos;}			/* * Wrap it up */static HTTPFile *_http_funopen(struct http_request_s *request){	struct httpio *io;	if (request == NULL)		return(NULL);	if ((io = RMCalloc(1, sizeof(*io))) == NULL) {		_fetch_syserr();		return (NULL);	}	io->request = request;	return (HTTPFile *)io;}/***************************************************************************** * Helper functions for talking to the server and parsing its replies *//* Header types */typedef enum {	hdr_syserror = -2,	hdr_error = -1,	hdr_end = 0,	hdr_unknown = 1,	hdr_content_length,	hdr_content_range,	hdr_last_modified,	hdr_location,	hdr_transfer_encoding,	hdr_www_authenticate,	hdr_connection} hdr_t;/* Names of interesting headers */static struct {	hdr_t		 num;	const RMascii	*name;} hdr_names[] = {	{ hdr_content_length,		"Content-Length" },	{ hdr_content_range,		"Content-Range" },	{ hdr_last_modified,		"Last-Modified" },	{ hdr_location,			"Location" },	{ hdr_transfer_encoding,	"Transfer-Encoding" },	{ hdr_www_authenticate,		"WWW-Authenticate" },	{ hdr_connection,		"Connection"},	{ hdr_unknown,			NULL },};/* * Send a formatted line; optionally echo to terminal */static RMint32_http_cmd(conn_t *conn, const RMascii *fmt, ...){#define MAXLINE 1024	va_list ap;	RMuint32 len;	RMascii msg[MAXLINE];	RMascii *long_msg = NULL;	RMint32 r;	RMuint32 long_size = MAXLINE;	va_start(ap, fmt);	len = vsnprintf(msg, MAXLINE, fmt, ap);	va_end(ap);	if (len >= MAXLINE){		do {			if (long_msg)				RMFree(long_msg);			long_size = long_size * 2;			long_msg = RMMalloc(long_size);			if (long_msg == NULL){				errno = ENOMEM;				goto error;			}			va_start(ap, fmt);			len = vsnprintf(long_msg, long_size, fmt, ap);			va_end(ap);		} while (len >= long_size);	}	if (long_msg)		r = _fetch_putln(conn, long_msg, len);	else		r = _fetch_putln(conn, msg, len);	if (r < 0) 		goto error;		return (0);error:	_fetch_syserr();	if (long_msg)		RMFree(long_msg);	return(-1);	}/* * Get and parse status line */static RMint32_http_get_reply(conn_t *conn){	RMascii *p;	if (_fetch_getln(conn) == -1){		return (-1);	}	/*	 * A valid status line looks like "HTTP/m.n xyz reason" where m	 * and n are the major and minor protocol version numbers and xyz	 * is the reply code.	 * Unfortunately, there are servers out there (NCSA 1.5.1, to name	 * just one) that do not send a version number, so we can't rely	 * on finding one, but if we do, insist on it being 1.0 or 1.1.	 * We don't care about the reason phrase.	 */	if (conn->buflen >= 4) {		if (strncmp((RMascii *)conn->buf, "HTTP", 4) != 0)			return (HTTP_PROTOCOL_ERROR);		}	else {		/*		 * Check if a chunked-body ending was received from the server for previous transactions.		 * Some servers which encode using chunked streams,		 * finish their transactions with a chunk body terminator like "0\r\n\r\n". 		 */		 		if (strncmp((RMascii *)conn->buf, "0\r\n", 3) != 0){			return (HTTP_PROTOCOL_ERROR);		}		if (_fetch_getln(conn) == -1){			return (-1);		}		if (strncmp((RMascii *)conn->buf, "\r\n", 2) != 0){			return (HTTP_PROTOCOL_ERROR);		}		/*		 * If found "0\r\n\r\n" left inside connection buffers, discard it and start to read the HTTP header.		 */		if (_fetch_getln(conn) == -1){			return (-1);		}		if (strncmp((RMascii *)conn->buf, "HTTP", 4) != 0)			return (HTTP_PROTOCOL_ERROR);	}	p = (RMascii *)conn->buf + 4;	if (*p == '/') {		if (p[1] != '1' || p[2] != '.' || (p[3] != '0' && p[3] != '1'))			return (HTTP_PROTOCOL_ERROR);		p += 4;	}	if (*p != ' ' || !isdigit(p[1]) || !isdigit(p[2]) || !isdigit(p[3]))		return (HTTP_PROTOCOL_ERROR);	conn->err = (p[1] - '0') * 100 + (p[2] - '0') * 10 + (p[3] - '0');	return (conn->err);}/* * Check a header; if the type matches the given string, return a pointer * to the beginning of the value. */static const RMascii *_http_match(const RMascii *str, const RMascii *hdr){

⌨️ 快捷键说明

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