Exemplo n.º 1
0
/*	Partial Response MIME parser stream
**	-----------------------------------
**	In case we sent a Range conditional GET we may get back a partial
**	response. This response must be appended to the already existing
**	cache entry before presented to the user.
**	We do this by continuing to load the new object into a temporary 
**	buffer and at the same time start the cache load of the already
**	existing object. When we have loaded the cache we merge the two
**	buffers.
*/
PUBLIC HTStream * HTMIMEPartial (HTRequest *	request,
				 void *		param,
				 HTFormat	input_format,
				 HTFormat	output_format,
				 HTStream *	output_stream)
{
#ifndef NO_CACHE
    HTParentAnchor * anchor = HTRequest_anchor(request);
    HTFormat format = HTAnchor_format(anchor);
    HTStream * pipe = NULL;

    /*
    **  The merge stream is a place holder for where we can put data when it
    **  arrives. We have two feeds: one from the cache and one from the net.
    **  We call the stream stack already now to get the right output stream.
    **  We can do this as we already know the content type from when we got the
    **  first part of the object.
    */
    HTStream * merge = HTMerge(HTStreamStack(format,
					     output_format, output_stream,
					     request, YES), 2);

    /*
    **  Now we create the MIME parser stream in partial data mode. We also
    **  set the target to our merge stream.
    */
    HTStream * me = HTMIMEConvert(request, param, input_format,
				  output_format, output_stream);
    me->mode |= HT_MIME_PARTIAL;
    me->target = merge;

#if 0
    /* JK: this doesn't work because this work is repeated before */
    /*
    **  Create the cache append stream, and a Tee stream
    */
    {
	HTStream * append = HTStreamStack(WWW_CACHE_APPEND, output_format,
					  output_stream, request, NO);
	if (append) me->target = HTTee(me->target, append, NULL);
    }
#endif

    /*
    **  Create the pipe buffer stream to buffer the data that we read
    **  from the network
    */
    if ((pipe = HTPipeBuffer(me->target, 0))) me->target = pipe;

    /*
    **  Now start the second load from the cache. First we read this data from
    **  the cache and then we flush the data that we have read from the net.
    */
    {
	HTRequest * cache_request = HTRequest_new();

	/*
	**  Set the output format to source and the output stream to the
	**  merge stream. As we have already set up the stream pipe, we just 
	**  load it as source.
	*/
	HTRequest_setOutputFormat(cache_request, WWW_SOURCE);
	HTRequest_setOutputStream(cache_request, merge);

	/*
	**  Bind the anchor to the new request and also register a local
	**  AFTER filter to flush the pipe buffer so that we can get
	**  rest of the data through. 
	*/
	HTRequest_setAnchor(cache_request, (HTAnchor *) anchor);
	HTRequest_addBefore(cache_request, HTCacheLoadFilter, NULL, NULL,
			    HT_FILTER_FIRST, YES);
	HTRequest_addAfter(cache_request, HTCacheFlushFilter, NULL, pipe,
			   HT_ALL, HT_FILTER_FIRST, YES);

	HTTRACE(STREAM_TRACE, "Partial..... Starting cache load\n");
	HTLoad(cache_request, NO);
    }
    return me;
#else
    return NULL;
#endif
}
Exemplo n.º 2
0
/*
**  Tries really hard to get rid of the data.
**  Returns:
**	-1 Error
**	 0 Buffered the data
**       1 Got rid of the data
*/
PUBLIC int HTMuxSession_disposeData (HTMuxSession * me, const char * buf, int len)
{
    HTTRACE(MUX_TRACE, "Mux Channel. Writing %d bytes to session %p\n" _ len _ me);

    /*
    **  There are two situations that can occur: Either we have an accepted session
    **  with a Net object or we have an unaccepted session with no Net object. In
    **  the former case we try to get rid of the data by pushing it directly to the
    **  read stream of the Net object. In the latter case we buffer as much as we
    **  can.
    */
    if (me) {	
	HTNet * net;
	HTStream * sink = NULL;
	int status;
	if ((net = me->net) && (sink = HTNet_readStream(net))) {

	    /*
	    **  Look first to see if we have old data that we can dispose down
	    **  the sink. We keep the buffer stream so that we can reuse it later.
	    */
	    if (me->buffer && me->buffering) {
		if ((*me->buffer->isa->flush)(me->buffer) == HT_OK) {
		    HTTRACE(MUX_TRACE, "Mux Channel. Flushed buffered data\n");
		    me->buffering = NO;
		} else if ((*me->buffer->isa->put_block)(me->buffer, buf, len) >= 0) {
		    HTTRACE(MUX_TRACE, "Mux Channel. Buffer accepted data\n");
		    return 0;
		}
		HTTRACE(MUX_TRACE, "Mux Channel. Can't buffer data\n");
		return (-1);		    
	    }

	    /*
	    **  See if we can get rid of the new data. If not then try to buffer it.
	    **  If this also fails then we reset the channel. A positive return code
	    **  from the stream means that we got rid of the data successfully.
	    */
	    if ((status = (*sink->isa->put_block)(sink, buf, len)) >= 0) {
		HTTRACE(MUX_TRACE, "Mux Channel. Stream returned %d\n" _ status);
		
		/*
		**  If we get back a HT_LOADED then we have all the data we need
		**  and we can terminate the request
		*/
		if (status == HT_LOADED) {
		    HTNet_execute (net, HTEvent_END);
		    return 0;
		}

		/*
		**  Decide whether we should send a credit message
		**  MORE TO COME
		*/
		me->read += len;
		if (me->read >= DEFAULT_CREDIT / 2) {
		    me->read = 0;
		    return 1;
		}
		return 0;
	    }
	}

	/*
	**  The stream is not ready and we try to buffer the data in
	**  the meantime.
	*/
	if (!me->buffer) {
	    me->buffer = HTPipeBuffer(sink, DEFAULT_CREDIT);
	    me->buffering = YES;
	}
	status = (*me->buffer->isa->put_block)(me->buffer, buf, len);
	if (status >= 0) {
	    HTTRACE(MUX_TRACE, "Mux Channel. Buffer accepted data\n");
	    return 0;
	}
	HTTRACE(MUX_TRACE, "Mux Channel. Buffer returned %d\n" _ status);
    }
    return (-1);
}