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

📄 htmime.c

📁 www工具包. 这是W3C官方支持的www支撑库. 其中提供通用目的的客户端的WebAPI: complete HTTP/1.1 (with caching, pipelining, PUT, POS
💻 C
📖 第 1 页 / 共 2 页
字号:
/*								       HTMIME.c**	MIME MESSAGE PARSE****	(c) COPYRIGHT MIT 1995.**	Please first read the full copyright statement in the file COPYRIGH.**	@(#) $Id: HTMIME.c,v 2.101 2000/12/18 17:00:56 kahan Exp $****	This is RFC 1341-specific code.**	The input stream pushed into this parser is assumed to be**	stripped on CRs, ie lines end with LF, not CR LF.**	(It is easy to change this except for the body part where**	conversion can be slow.)**** History:**	   Feb 92	Written Tim Berners-Lee, CERN**	 8 Jul 94  FM	Insulate free() from _free structure element.**	14 Mar 95  HFN	Now using response for storing data. No more `\n',**			static buffers etc.*//* Library include files */#include "wwwsys.h"#include "WWWUtil.h"#include "WWWCore.h"#include "HTReqMan.h"#include "HTNetMan.h"#include "HTHeader.h"#include "HTWWWStr.h"#ifndef NO_CACHE#include "HTTee.h"#include "HTConLen.h"#include "HTMerge.h"#include "WWWCache.h"#endif#include "HTMIME.h"					 /* Implemented here */typedef enum _HTMIMEMode {    HT_MIME_HEADER	= 0x1,    HT_MIME_FOOTER	= 0x2,    HT_MIME_PARTIAL	= 0x4,    HT_MIME_CONT	= 0x8,    HT_MIME_UPGRADE	= 0x10} HTMIMEMode;struct _HTStream {    const HTStreamClass *	isa;    HTRequest *			request;    HTResponse *		response;    HTNet *			net;    HTStream *			target;    HTConverter *		save_stream;    HTFormat			target_format;    HTChunk *			token;    HTChunk *			value;    int				hash;    HTEOLState			EOLstate;    HTMIMEMode			mode;    BOOL			transparent;    BOOL			haveToken;    BOOL			hasBody;};PRIVATE HTConverter * LocalSaveStream = NULL; /* Where to save unknown stuff *//* ------------------------------------------------------------------------- */PRIVATE int pumpData (HTStream * me){    HTRequest * request = me->request;    HTResponse * response = me->response;    HTFormat format = HTResponse_format(response);    HTList * te = HTResponse_transfer(response);    HTList * ce = HTResponse_encoding(response);    long length = HTResponse_length(response);    HTStream * BlackHole = HTBlackHole();    BOOL savestream = NO;    me->transparent = YES;		  /* Pump rest of data right through */    /*    **  Cache the metainformation in the anchor object by copying    **  it from the response object. This we do regardless if    **  we have a persistent cache or not as the memory cache will    **  use it as well. If we are updating a cache entry using    **  byte ranges then we already have the metainformation and    **  hence we can ignore the new one as it'd better be the same.    */    if (!(me->mode & HT_MIME_PARTIAL) &&	HTResponse_isCachable(me->response) != HT_NO_CACHE)	HTAnchor_update(HTRequest_anchor(request), me->response);    /*    **  If we asked only to read the header or footer or we used a HEAD    **  method then we stop here as we don't expect any body part.    */    if (me->mode & (HT_MIME_HEADER | HT_MIME_FOOTER) ||	HTRequest_method(request) == METHOD_HEAD) {        HTAlertCallback * cbf = HTAlert_find(HT_PROG_DONE);        if (cbf) (*cbf)(request, HT_PROG_DONE, HT_MSG_NULL, NULL, NULL, NULL);        return HT_LOADED;    }    /*    **  If we are paring a 1xx response then return HT_CONTINUE    */    if (me->mode & HT_MIME_CONT)	return HT_CONTINUE;    /*    **  If we get a 101 Protocol Switch then we are done here    **  but not done with the response (which we don't know    **  how to go about parsing    */    if (me->mode & HT_MIME_UPGRADE) {	me->hasBody = YES;	return HT_OK;    }    /*    **  If there is no content-length, no transfer encoding and no    **  content type then we assume that there is no body part in    **  the message and we can return HT_LOADED    */    {	HTHost * host = HTNet_host(me->net);	if (length<0 && te==NULL &&	    HTHost_isPersistent(host) && !HTHost_closeNotification(host)) {	    if (format != WWW_UNKNOWN) {		HTTRACE(STREAM_TRACE, "MIME Parser. BAD - there seems to be a body but no length. This must be an HTTP/1.0 server pretending that it is HTTP/1.1\n");		HTHost_setCloseNotification(host, YES);	    } else {                HTAlertCallback * cbf = HTAlert_find(HT_PROG_DONE);                if (cbf) (*cbf)(request, HT_PROG_DONE, HT_MSG_NULL, NULL, NULL, NULL);		HTTRACE(STREAM_TRACE, "MIME Parser. No body in this message\n");		return HT_LOADED;	    }	}    }    /*    **  Deal with the body    */    me->hasBody = YES;    /*    **  Handle any Content Type    */    if (!(me->mode & HT_MIME_PARTIAL) &&	(format != WWW_UNKNOWN || length > 0 || te)) {	HTStream * target;	HTTRACE(STREAM_TRACE, "Building.... C-T stack from %s to %s\n" _ 				  HTAtom_name(format) _ 				  HTAtom_name(me->target_format));	if ((target = HTStreamStack(format, me->target_format,				    me->target, request, YES))==BlackHole) {	    if (!savestream) {                if (me->target) (*me->target->isa->abort)(me->target, NULL);                me->target = me->save_stream(request, NULL,					     format, me->target_format, me->target);		savestream = YES;	    }	} else	    me->target = target;    }    /*    **  Handle any Content Encodings    */    HTTRACE(STREAM_TRACE, "Building.... Content-Decoding stack\n");    if (ce) {	HTStream * target = HTContentDecodingStack(ce, me->target, request, NULL);	if (target == BlackHole) {	    if (!savestream) {		if (me->target) (*me->target->isa->abort)(me->target, NULL);                me->target = me->save_stream(request, NULL,					     format, me->target_format, me->target);		savestream = YES;	    }	} else	    me->target = target;    }    /*    **  Can we cache the data object? If so then create a T stream and hook it     **  into the stream pipe. We do it before the transfer decoding so that we    **  don't have to deal with that when we retrieve the object from cache.    **  If we are appending to a cache entry then use a different stream than    **  if creating a new entry.    */#ifndef NO_CACHE    if (HTCacheMode_enabled()) {	if (me->mode & HT_MIME_PARTIAL) {	    HTStream * append = HTStreamStack(WWW_CACHE_APPEND,					      me->target_format,					      me->target, request, NO);	    if (append) me->target = HTTee(me->target, append, NULL);#if 0	    /* @@ JK: change */	    if (append) me->target = append;#endif	} else if (HTResponse_isCachable(me->response) == HT_CACHE_ALL) {	    HTStream * cache = HTStreamStack(WWW_CACHE, me->target_format,					     me->target, request, NO);	    if (cache) me->target = HTTee(me->target, cache, NULL);	}    }#endif        /*    **  Handle any Transfer Encodings    */    HTTRACE(STREAM_TRACE, "Building.... Transfer-Decoding stack\n");    if (te) {	HTStream * target = HTTransferDecodingStack(te, me->target, request, NULL);	if (target == BlackHole) {	    if (!savestream) {		if (me->target) (*me->target->isa->abort)(me->target, NULL);                me->target = me->save_stream(request, NULL,					     format, me->target_format, me->target);		savestream = YES;	    }	} else	    me->target = target;    }    /*    ** If we for some reason couldn't find a target stream    */    if (!me->target) me->target = HTBlackHole();    return HT_OK;}/* _dispatchParsers * call request's MIME header parser. Use global parser if no  * appropriate one is found for request.*/PRIVATE int _dispatchParsers (HTRequest * req, char * token, char * value){    int status;    BOOL found = NO;    BOOL local = NO;    HTMIMEParseSet * parseSet;    /* In case we get an empty header consisting of a CRLF, we fall thru */    HTTRACE(STREAM_TRACE, "MIME header. %s: %s\n" _ 			      token ? token : "<null>" _ 			      value ? value : "<null>");    if (!token) return HT_OK;			    /* Ignore noop token */    /*    ** Search the local set of MIME parsers    */    if ((parseSet = HTRequest_MIMEParseSet(req, &local)) != NULL) {        status = HTMIMEParseSet_dispatch(parseSet, req, 					 token, value, &found);	if (found) return status;    }    /*    ** Search the global set of MIME parsers    */    if (local==NO && (parseSet = HTHeader_MIMEParseSet()) != NULL) {	status = HTMIMEParseSet_dispatch(parseSet, req, 					 token, value, &found);	if (found) return status;    }    return HT_OK;}/* _stream2dispatchParsers - extracts the arguments from a * MIME stream before calling the generic _dispatchParser * function. */PRIVATE int _stream2dispatchParsers (HTStream * me){    char * token = HTChunk_data(me->token);    char * value = HTChunk_data(me->value);    /* In case we get an empty header consisting of a CRLF, we fall thru */    HTTRACE(STREAM_TRACE, "MIME header. %s: %s\n" _ 			      token ? token : "<null>" _ 			      value ? value : "<null>");    if (!token) return HT_OK;			    /* Ignore noop token */    /*    ** Remember the original header    */    HTResponse_addHeader(me->response, token, value);    /* call the parsers to set the headers */    return (_dispatchParsers (me->request, token, value));}/***	Header is terminated by CRCR, LFLF, CRLFLF, CRLFCRLF**	Folding is either of CF LWS, LF LWS, CRLF LWS*/PRIVATE int HTMIME_put_block (HTStream * me, const char * b, int l){    const char * start = b;    const char * end = start;    const char * value = HTChunk_size(me->value) > 0 ? b : NULL;    int length = l;    int status;    while (!me->transparent) {	if (me->EOLstate == EOL_FCR) {	    if (*b == CR)				    /* End of header */	        me->EOLstate = EOL_END;	    else if (*b == LF)			   	     /* CRLF */		me->EOLstate = EOL_FLF;	    else if (isspace((int) *b))			   /* Folding: CR SP */	        me->EOLstate = EOL_FOLD;	    else						 /* New line */	        me->EOLstate = EOL_LINE;	} else if (me->EOLstate == EOL_FLF) {	    if (*b == CR)				/* LF CR or CR LF CR */		me->EOLstate = EOL_SCR;	    else if (*b == LF)				    /* End of header */	        me->EOLstate = EOL_END;	    else if (isspace((int) *b))	       /* Folding: LF SP or CR LF SP */		me->EOLstate = EOL_FOLD;	    else						/* New line */		me->EOLstate = EOL_LINE;	} else if (me->EOLstate == EOL_SCR) {	    if (*b==CR || *b==LF)			    /* End of header */	        me->EOLstate = EOL_END;	    else if (isspace((int) *b))	 /* Folding: LF CR SP or CR LF CR SP */		me->EOLstate = EOL_FOLD;	    else						/* New line */		me->EOLstate = EOL_LINE;	} else if (*b == CR)	    me->EOLstate = EOL_FCR;	else if (*b == LF)	    me->EOLstate = EOL_FLF;			       /* Line found */	else {	    if (!me->haveToken) {	        if (*b == ':' || isspace((int) *b)) {		    HTChunk_putb(me->token, start, end-start);		    HTChunk_putc(me->token, '\0');		    me->haveToken = YES;		} else {		    unsigned char ch = *(unsigned char *) b;		    ch = TOLOWER(ch);		    me->hash = (me->hash * 3 + ch) % MIME_HASH_SIZE;		}	    } else if (value == NULL && *b != ':' && !isspace((int) *b))	        value = b;	    end++;	}	switch (me->EOLstate) {	    case EOL_LINE:	    case EOL_END:	    {		int ret = HT_ERROR;		HTChunk_putb(me->value, value, end-value);		HTChunk_putc(me->value, '\0');		ret =  _stream2dispatchParsers(me);		HTNet_addBytesRead(me->net, b-start);		start=b, end=b;		if (me->EOLstate == EOL_END) {		/* EOL_END */		    if (ret == HT_OK) {			b++, l--;			ret = pumpData(me);			HTNet_addBytesRead(me->net, 1);			if (me->mode & (HT_MIME_FOOTER | HT_MIME_CONT)) {			    HTHost_setConsumed(HTNet_host(me->net), length - l);			    return ret;                        } else {                            HTNet_setHeaderBytesRead(me->net, HTNet_bytesRead(me->net));                        }		    }	        } else {				/* EOL_LINE */		    HTChunk_truncate(me->token,0);		    HTChunk_truncate(me->value,0);		    me->haveToken = NO;		    me->hash = 0;		    value = NULL;		}		me->EOLstate = EOL_BEGIN;		if (ret != HT_OK && ret != HT_LOADED) return ret;		break;	    }	    case EOL_FOLD:		me->EOLstate = EOL_BEGIN;	        if (!me->haveToken) {		    HTChunk_putb(me->token, start, end-start);		    HTChunk_putc(me->token, '\0');		    me->haveToken = YES;	        } else if (value) {		    HTChunk_putb(me->value, value, end-value);		    HTChunk_putc(me->value, ' ');		}		start=b, end=b;		break;	    default: 	        b++, l--;	        if (!l) {		    BOOL stop = NO;		    if (!me->haveToken) {			/* If empty header then prepare to stop */			if (end-start)			    HTChunk_putb(me->token, start, end-start);			else			    stop = YES;		    } else if (value)		        HTChunk_putb(me->value, value, end-value);		    HTHost_setConsumed(HTNet_host(me->net), length - l);		    return stop ? pumpData(me) : HT_OK;		}	}    }    if (length != l) HTHost_setConsumed(HTNet_host(me->net), length - l);    /* 

⌨️ 快捷键说明

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