/* ** Take the relevant infomration from the response object and cache it ** in the anchor object. We inherit the information that is already ** parsed in the response along with the unparsed headers. */ PUBLIC BOOL HTAnchor_update (HTParentAnchor * me, HTResponse * response) { if (me && response) { HTCachable cachable = HTResponse_isCachable(response); if (cachable == HT_CACHE_ETAG) { char * etag = HTResponse_etag(response); HTTRACE(ANCH_TRACE, "HTAnchor.... Updating etag for %p\n" _ me); if (etag) { HTAnchor_setEtag(me, etag); return YES; } } else if (cachable == HT_CACHE_NOT_MODIFIED) { HTTRACE(ANCH_TRACE, "HTAnchor.... Information is up to date for %p\n" _ me); return YES; } else if (cachable == HT_CACHE_ALL) { char * etag = HTResponse_etag(response); HTTRACE(ANCH_TRACE, "HTAnchor.... Updating metainformation for %p\n" _ me); /* ** The content length and type is already parsed at this point ** in time. We also check for format parameters like charset etc. ** and copy the contents in the anchor object */ me->content_length = HTResponse_length(response); me->content_type = HTResponse_format(response); me->type_parameters = HTResponse_formatParam(response); me->content_encoding = HTResponse_encoding(response); /* Don't forget the etag as well */ if (etag) HTAnchor_setEtag(me, etag); /* ** Inherit all the unparsed headers - we may need them later! */ if (me->headers) HTAssocList_delete(me->headers); me->headers = HTResponse_handOverHeader(response); /* ** Notifify the response object not to delete the lists that we ** have inherited in the anchor object */ HTResponse_isCached(response, YES); /* ** Set the datestamp of when the anchor was updated if we didn't ** get any in the response */ if (!HTAssocList_findObject(me->headers, "date")) HTAnchor_setDate(me, time(NULL)); return YES; } } return NO; }
BinURLInputStream::BinURLInputStream(const XMLURL& urlSource) : fBuffer(0) , fBufferSize(0) , fBufferIndex(0) , fRemoteFileSize(0) , fAnchor(0) , fBytesProcessed(0) , fMemoryManager(urlSource.getMemoryManager()) { fBuffer = (XMLByte*) fMemoryManager->allocate ( URLISBUFMAXSIZE * sizeof(XMLByte) );//new XMLByte[URLISBUFMAXSIZE]; const XMLCh* uri = urlSource.getURLText(); char* uriAsCharStar = localTranscode(uri, fMemoryManager); // // First find the size of the remote resource being asked for. // We use the ContentCounter stream provided by libWWW. // fAnchor = HTAnchor_findAddress(uriAsCharStar); HTRequest* request = HTRequest_new(); HTRequest_setOutputFormat(request, WWW_SOURCE); HTStream* counterStrm = HTContentCounter(HTBlackHole(), request, 0xFFFF); BOOL status = HTLoadToStream(uriAsCharStar, counterStrm, request); if (status == YES) { HTParentAnchor * anchor = HTRequest_anchor(request); fRemoteFileSize=HTAnchor_length(anchor); if(fRemoteFileSize < 0) { // Patch by Artur Klauser // When a redirection is processed in libWWW, it seems that // HTAnchor_length(anchor) == -1 on the original anchor, whereas // HTResponse_length(response) gives the correct content length of // the redirection target. This has confused fRemoteFileSize and it was // not checked for a -1 response at all. HTResponse * response = HTRequest_response (request); fRemoteFileSize = HTResponse_length(response); if (fRemoteFileSize < 0) { ThrowXMLwithMemMgr(NetAccessorException, XMLExcepts::NetAcc_LengthError, fMemoryManager); } } } // Cleanup, before you throw any errors. fMemoryManager->deallocate(uriAsCharStar); HTRequest_delete(request); // Don't know whether I am supposed to delete counterStrm. if (status == NO) { ThrowXMLwithMemMgr(NetAccessorException, XMLExcepts::NetAcc_LengthError, fMemoryManager); } }
/* ** request_terminater : global filter to delete the requests ** Funtion's type : HTNetAfter */ PRIVATE int terminate_handler (HTRequest * request, HTResponse * response, void * param, int status) { my_headers(request); if (response) { HTPrint ("\tStatus:%d\n\tContent-length:%d\n\tIs Cachable:%c\n\tis Cached:%c\n\tReason: %s\n",\ status, HTResponse_length(response),\ (HTResponse_isCachable(response))?'Y':'N',\ (HTResponse_isCached(response,YES))?'Y':'N', \ (HTResponse_reason(response))?HTResponse_reason(response):"NULL"); HTPrint ("\tFormat : %s \n",(char *)HTAtom_name(HTResponse_format(response))); } else HTPrint ("\tResponse NULL\n"); /* Terminate libwww */ HTProfile_delete(); exit(0); }
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; }
/* ** 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); /* ** Put the rest down the stream without touching the data but make sure ** that we get the correct content length of data. If we have a CL in ** the headers then this stream is responsible for the accountance. */ if (me->hasBody) { HTNet * net = me->net; /* Check if CL at all - thanks to [email protected] (John Wei) */ long cl = HTResponse_length(me->response); if (cl >= 0) { long bodyRead = HTNet_bytesRead(net) - HTNet_headerBytesRead(net); /* ** If we have more than we need then just take what belongs to us. */ if (bodyRead + l >= cl) { int consume = cl - bodyRead; if ((status = (*me->target->isa->put_block)(me->target, b, consume)) < 0) return status; else { HTAlertCallback * cbf = HTAlert_find(HT_PROG_DONE); HTNet_addBytesRead(net, consume); HTHost_setConsumed(HTNet_host(net), consume); if (cbf) (*cbf)(me->request, HT_PROG_DONE, HT_MSG_NULL, NULL, NULL, NULL); return HT_LOADED; } } else { if ((status = (*me->target->isa->put_block)(me->target, b, l)) < 0) return status; HTNet_addBytesRead(net, l); HTHost_setConsumed(HTNet_host(net), l); return status; } } return (*me->target->isa->put_block)(me->target, b, l); } else { HTAlertCallback * cbf = HTAlert_find(HT_PROG_DONE); if (cbf) (*cbf)(me->request, HT_PROG_DONE, HT_MSG_NULL, NULL, NULL, NULL); } return HT_LOADED; }