httpread.c

来自「最新的Host AP 新添加了许多pcmcia 的驱动」· C语言 代码 · 共 859 行 · 第 1/2 页

C
859
字号
				   "httpread premature eof(%p) %d/%d",				   h, h->body_nbytes,				   h->content_length);			goto bad;		}		/* No explicit length, hopefully we have all the data		 * although dropped connections can cause false		 * end		 */		if (httpread_debug >= 10)			wpa_printf(MSG_DEBUG, "httpread ok eof(%p)", h);			h->got_body = 1;			goto got_file;	}	rbp = readbuf;	/* Header consists of text lines (terminated by both CR and LF)	 * and an empty line (CR LF only).	 */	if (!h->got_hdr) {		hbp = h->hdr + h->hdr_nbytes;		/* add to headers until:		 *      -- we run out of data in read buffer		 *      -- or, we run out of header buffer room		 *      -- or, we get double CRLF in headers		 */		for (;;) {			if (nread == 0)				goto get_more;			if (h->hdr_nbytes == HTTPREAD_HEADER_MAX_SIZE) {				goto bad;			}			*hbp++ = *rbp++;			nread--;			h->hdr_nbytes++;			if (h->hdr_nbytes >= 4 &&			    hbp[-1] == '\n' &&			    hbp[-2] == '\r' &&			    hbp[-3] == '\n' &&			    hbp[-4] == '\r' ) {				h->got_hdr = 1;				*hbp = 0;       /* null terminate */				break;			}		}		/* here we've just finished reading the header */		if (httpread_hdr_analyze(h)) {			wpa_printf(MSG_DEBUG, "httpread bad hdr(%p)", h);			goto bad;		}		if (h->max_bytes == 0) {			if (httpread_debug >= 10)				wpa_printf(MSG_DEBUG,					   "httpread no body hdr end(%p)", h);			goto got_file;		}		if (h->got_content_length && h->content_length == 0) {			if (httpread_debug >= 10)				wpa_printf(MSG_DEBUG,					   "httpread zero content length(%p)",					   h);			goto got_file;		}	}	/* Certain types of requests never have data and so	 * must be specially recognized.	 */	if (!os_strncasecmp(h->hdr, "SUBSCRIBE", 9) ||	    !os_strncasecmp(h->hdr, "UNSUBSCRIBE", 11) ||	    !os_strncasecmp(h->hdr, "HEAD", 4) ||	    !os_strncasecmp(h->hdr, "GET", 3)) {		if (!h->got_body) {			if (httpread_debug >= 10)				wpa_printf(MSG_DEBUG,					   "httpread NO BODY for sp. type");		}		h->got_body = 1;		goto got_file;	}	/* Data can be just plain binary data, or if "chunked"	 * consists of chunks each with a header, ending with	 * an ending header.	 */	if (!h->got_body) {		/* Here to get (more of) body */		/* ensure we have enough room for worst case for body		 * plus a null termination character		 */		if (h->body_alloc_nbytes < (h->body_nbytes + nread + 1)) {			char *new_body;			int new_alloc_nbytes;			if (h->body_nbytes >= h->max_bytes)				goto bad;			new_alloc_nbytes = h->body_alloc_nbytes +				HTTPREAD_BODYBUF_DELTA;			/* For content-length case, the first time			 * through we allocate the whole amount			 * we need.			 */			if (h->got_content_length &&			    new_alloc_nbytes < (h->content_length + 1))				new_alloc_nbytes = h->content_length + 1;			if ((new_body = os_realloc(h->body, new_alloc_nbytes))			    == NULL)				goto bad;			h->body = new_body;			h->body_alloc_nbytes = new_alloc_nbytes;		}		/* add bytes */		bbp = h->body + h->body_nbytes;		for (;;) {			int ncopy;			/* See if we need to stop */			if (h->chunked && h->in_chunk_data == 0) {				/* in chunk header */				char *cbp = h->body + h->chunk_start;				if (bbp-cbp >= 2 && bbp[-2] == '\r' &&				    bbp[-1] == '\n') {					/* end of chunk hdr line */					/* hdr line consists solely					 * of a hex numeral and CFLF					 */					if (!isxdigit(*cbp))						goto bad;					h->chunk_size = strtoul(cbp, NULL, 16);					/* throw away chunk header					 * so we have only real data					 */					h->body_nbytes = h->chunk_start;					bbp = cbp;					if (h->chunk_size == 0) {						/* end of chunking */						/* trailer follows */						h->in_trailer = 1;						if (httpread_debug >= 20)							wpa_printf(								MSG_DEBUG,								"httpread end chunks(%p)", h);						break;					}					h->in_chunk_data = 1;					/* leave chunk_start alone */				}			} else if (h->chunked) {				/* in chunk data */				if ((h->body_nbytes - h->chunk_start) ==				    (h->chunk_size + 2)) {					/* end of chunk reached,					 * new chunk starts					 */					/* check chunk ended w/ CRLF					 * which we'll throw away					 */					if (bbp[-1] == '\n' &&					    bbp[-2] == '\r') {					} else						goto bad;					h->body_nbytes -= 2;					bbp -= 2;					h->chunk_start = h->body_nbytes;					h->in_chunk_data = 0;					h->chunk_size = 0; /* just in case */				}			} else if (h->got_content_length &&				   h->body_nbytes >= h->content_length) {				h->got_body = 1;				if (httpread_debug >= 10)					wpa_printf(						MSG_DEBUG,						"httpread got content(%p)", h);				goto got_file;			}			if (nread <= 0)				break;			/* Now transfer. Optimize using memcpy where we can. */			if (h->chunked && h->in_chunk_data) {				/* copy up to remainder of chunk data				 * plus the required CR+LF at end				 */				ncopy = (h->chunk_start + h->chunk_size + 2) -					h->body_nbytes;			} else if (h->chunked) {				/*in chunk header -- don't optimize */				*bbp++ = *rbp++;				nread--;				h->body_nbytes++;				continue;			} else if (h->got_content_length) {				ncopy = h->content_length - h->body_nbytes;			} else {				ncopy = nread;			}			/* Note: should never be 0 */			if (ncopy > nread)				ncopy = nread;			os_memcpy(bbp, rbp, ncopy);			bbp += ncopy;			h->body_nbytes += ncopy;			rbp += ncopy;			nread -= ncopy;		}       /* body copy loop */	}       /* !got_body */	if (h->chunked && h->in_trailer) {		/* If "chunked" then there is always a trailer,		 * consisting of zero or more non-empty lines		 * ending with CR LF and then an empty line w/ CR LF.		 * We do NOT support trailers except to skip them --		 * this is supported (generally) by the http spec.		 */		bbp = h->body + h->body_nbytes;		for (;;) {			int c;			if (nread <= 0)				break;			c = *rbp++;			nread--;			switch (h->trailer_state) {			case trailer_line_begin:				if (c == '\r')					h->trailer_state = trailer_empty_cr;				else					h->trailer_state = trailer_nonempty;				break;			case trailer_empty_cr:				/* end empty line */				if (c == '\n') {					h->trailer_state = trailer_line_begin;					h->in_trailer = 0;					if (httpread_debug >= 10)						wpa_printf(							MSG_DEBUG,							"httpread got content(%p)", h);					h->got_body = 1;					goto got_file;				}				h->trailer_state = trailer_nonempty;				break;			case trailer_nonempty:				if (c == '\r')					h->trailer_state = trailer_nonempty_cr;				break;			case trailer_nonempty_cr:				if (c == '\n')					h->trailer_state = trailer_line_begin;				else					h->trailer_state = trailer_nonempty;				break;			}		}	}	goto get_more;bad:	/* Error */	wpa_printf(MSG_DEBUG, "httpread read/parse failure (%p)", h);	(*h->cb)(h, h->cookie, HTTPREAD_EVENT_ERROR);	return;get_more:	return;got_file:	if (httpread_debug >= 10)		wpa_printf(MSG_DEBUG,			   "httpread got file %d bytes type %d",			   h->body_nbytes, h->hdr_type);	/* Null terminate for convenience of some applications */	if (h->body)		h->body[h->body_nbytes] = 0; /* null terminate */	h->got_file = 1;	/* Assume that we do NOT support keeping connection alive,	 * and just in case somehow we don't get destroyed right away,	 * unregister now.	 */	if (h->sd_registered)		eloop_unregister_sock(h->sd, EVENT_TYPE_READ);	h->sd_registered = 0;	/* The application can destroy us whenever they feel like...	 * cancel timeout.	 */	if (h->to_registered)		eloop_cancel_timeout(httpread_timeout_handler, NULL, h);	h->to_registered = 0;	(*h->cb)(h, h->cookie, HTTPREAD_EVENT_FILE_READY);}/* httpread_create -- start a new reading session making use of eloop. * The new instance will use the socket descriptor for reading (until * it gets a file and not after) but will not close the socket, even * when the instance is destroyed (the application must do that). * Return NULL on error. * * Provided that httpread_create successfully returns a handle, * the callback fnc is called to handle httpread_event events. * The caller should do destroy on any errors or unknown events. * * Pass max_bytes == 0 to not read body at all (required for e.g. * reply to HEAD request). */struct httpread * httpread_create(	int sd,	 /* descriptor of TCP socket to read from */	void (*cb)(struct httpread *handle, void *cookie,		   enum httpread_event e),  /* call on event */	void *cookie,    /* pass to callback */	int max_bytes,	  /* maximum body size else abort it */	int timeout_seconds     /* 0; or total duration timeout period */	){	struct httpread *h = NULL;	h = os_zalloc(sizeof(*h));	if (h == NULL)		goto fail;	h->sd = sd;	h->cb = cb;	h->cookie = cookie;	h->max_bytes = max_bytes;	h->timeout_seconds = timeout_seconds;	if (timeout_seconds > 0) {		if (eloop_register_timeout(timeout_seconds, 0,					   httpread_timeout_handler,					   NULL, h)) {			/* No way to recover (from malloc failure) */			goto fail;		}		h->to_registered = 1;	}	if (eloop_register_sock(sd, EVENT_TYPE_READ, httpread_read_handler,				NULL, h)) {		/* No way to recover (from malloc failure) */		goto fail;	}	h->sd_registered = 1;	return h;fail:	/* Error */	httpread_destroy(h);	return NULL;}/* httpread_hdr_type_get -- When file is ready, returns header type. */enum httpread_hdr_type httpread_hdr_type_get(struct httpread *h){	return h->hdr_type;}/* httpread_uri_get -- When file is ready, uri_get returns (translated) URI * or possibly NULL (which would be an error). */char * httpread_uri_get(struct httpread *h){	return h->uri;}/* httpread_reply_code_get -- When reply is ready, returns reply code */int httpread_reply_code_get(struct httpread *h){	return h->reply_code;}/* httpread_length_get -- When file is ready, returns file length. */int httpread_length_get(struct httpread *h){	return h->body_nbytes;}/* httpread_data_get -- When file is ready, returns file content * with null byte appened. * Might return NULL in some error condition. */void * httpread_data_get(struct httpread *h){	return h->body ? h->body : "";}/* httpread_hdr_get -- When file is ready, returns header content * with null byte appended. * Might return NULL in some error condition. */char * httpread_hdr_get(struct httpread *h){	return h->hdr;}/* httpread_hdr_line_get -- When file is ready, returns pointer * to line within header content matching the given tag * (after the tag itself and any spaces/tabs). * * The tag should end with a colon for reliable matching. * * If not found, returns NULL; */char * httpread_hdr_line_get(struct httpread *h, const char *tag){	int tag_len = os_strlen(tag);	char *hdr = h->hdr;	hdr = os_strchr(hdr, '\n');	if (hdr == NULL)		return NULL;	hdr++;	for (;;) {		if (!os_strncasecmp(hdr, tag, tag_len)) {			hdr += tag_len;			while (*hdr == ' ' || *hdr == '\t')				hdr++;			return hdr;		}		hdr = os_strchr(hdr, '\n');		if (hdr == NULL)			return NULL;		hdr++;	}}

⌨️ 快捷键说明

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