Beispiel #1
0
PRIVATE int HTANSIReader_read (HTInputStream * me)
{
    FILE * fp = HTChannel_file(me->ch);
    HTNet * net = HTHost_getReadNet(me->host);
    int status;

    /* Read the file desriptor */
    while (fp) {
	if ((me->b_read = fread(me->data, 1, FILE_BUFFER_SIZE, fp)) == 0){
	    if (ferror(fp)) {
		HTTRACE(PROT_TRACE, "ANSI read... READ ERROR\n");
	    } else {
		HTAlertCallback *cbf = HTAlert_find(HT_PROG_DONE);
		HTTRACE(PROT_TRACE, "ANSI read... Finished loading file %p\n" _ fp);
		if (cbf) (*cbf)(net->request, HT_PROG_DONE, HT_MSG_NULL,NULL,NULL,NULL);
		return HT_CLOSED;
	    }
	}

	/* Remember how much we have read from the input socket */
	HTTRACEDATA(me->data, me->b_read, "HTANSIReader_read me->data:");
	me->write = me->data;
	me->read = me->data + me->b_read;

	{
	    HTAlertCallback * cbf = HTAlert_find(HT_PROG_READ);
	    HTNet_addBytesRead(net, me->b_read);
	    if (cbf) {
		int tr = HTNet_bytesRead(net);
		(*cbf)(net->request, HT_PROG_READ, HT_MSG_NULL, NULL, &tr, NULL);
	    }
	}

	/* Now push the data down the stream */
	if ((status = (*net->readStream->isa->put_block)
	     (net->readStream, me->data, me->b_read)) != HT_OK) {
	    if (status == HT_WOULD_BLOCK) {
		HTTRACE(PROT_TRACE, "ANSI read... Target WOULD BLOCK\n");
		return HT_WOULD_BLOCK;
	    } else if (status == HT_PAUSE) {
		HTTRACE(PROT_TRACE, "ANSI read... Target PAUSED\n");
		return HT_PAUSE;
	    } else if (status > 0) {	      /* Stream specific return code */
		HTTRACE(PROT_TRACE, "ANSI read... Target returns %d\n" _ status);
		me->write = me->data + me->b_read;
		return status;
	    } else {				     /* We have a real error */
		HTTRACE(PROT_TRACE, "ANSI read... Target ERROR\n");
		return status;
	    }
	}
	me->write = me->data + me->b_read;
    }
    HTTRACE(PROT_TRACE, "ANSI read... File descriptor is NULL...\n");
    return HT_ERROR;
}
Beispiel #2
0
/*
**	Error and Information AFTER filter
**	----------------------------------
**	It checks the status code from a request and generates an 
**	error/information message if required.
*/
PUBLIC int HTInfoFilter (HTRequest * request, HTResponse * response,
			 void * param, int status)
{
    HTParentAnchor * anchor = HTRequest_anchor(request);
    char * uri = HTAnchor_address((HTAnchor*) anchor);
    switch (status) {
    case HT_RETRY: {
        HTAlertCallback *cbf = HTAlert_find(HT_A_MESSAGE);
	if (cbf) (*cbf)(request, HT_A_MESSAGE, HT_MSG_NULL, NULL,
			HTRequest_error(request), NULL);
	HTTRACE(PROT_TRACE, "Load End.... NOT AVAILABLE, RETRY AT %ld\n" _ 
		    HTResponse_retryTime(response));
        }
        break;

    case HT_NO_DATA:
    {
	/*
	** The document was empty
	*/
	HTAlertCallback *cbf = HTAlert_find(HT_A_MESSAGE);
	if (cbf) (*cbf)(request, HT_A_MESSAGE, HT_MSG_NULL, NULL,
			HTRequest_error(request), NULL);
	HTTRACE(PROT_TRACE, "Load End.... EMPTY: No content `%s\'\n" _ 
		    uri ? uri : "<UNKNOWN>");
	break;
    }    

    case HT_LOADED:
	HTTRACE(PROT_TRACE, "Load End.... OK: `%s\'\n" _ uri);
	break;

    default:
    {
	/*
	** See if we have a function registered for outputting errors.
	** If so then call it and present the message to the user
	*/
	HTAlertCallback *cbf = HTAlert_find(HT_A_MESSAGE);
	if (cbf) (*cbf)(request, HT_A_MESSAGE, HT_MSG_NULL, NULL,
			HTRequest_error(request), NULL);
	HTTRACE(PROT_TRACE, "Load End.... Request ended with code %d\n" _ status);
	break;
    }
    }
    HT_FREE(uri);
    return HT_OK;
}
Beispiel #3
0
PUBLIC HTStream * HTRules (HTRequest *	request,
			   void *	param,
			   HTFormat	input_format,
			   HTFormat	output_format,
			   HTStream *	output_stream)
{
    HTAlertCallback *cbf = HTAlert_find(HT_A_CONFIRM);
    
    /*
    **  If the library has been compiled so that we automatically accept
    **  rule files then it's OK not to ask the user.
    */
#ifdef HT_AUTOMATIC_RULES
    if (!cbf || (cbf && (*cbf)(request,HT_A_CONFIRM, HT_MSG_RULES, NULL,NULL,NULL))) {
#else
    if ((cbf && (*cbf)(request,HT_A_CONFIRM, HT_MSG_RULES, NULL,NULL,NULL))) {
#endif
	HTStream * me;
	HTTRACE(APP_TRACE, "Rule file... Parser object created\n");
	if ((me = (HTStream *) HT_CALLOC(1, sizeof(HTStream))) == NULL)
	    HT_OUTOFMEM("HTRules");
	me->isa = &HTRuleClass;
	me->request = request;
	me->buffer = HTChunk_new(512);
	me->EOLstate = EOL_BEGIN;
	if (!rules) rules = HTList_new();
	return me;
    } else {
	HTRequest_addError(request, ERR_FATAL, NO, HTERR_NO_AUTO_RULES,
			   NULL, 0, "HTRules");
	return HTErrorStream();
    }
}

/*
**  Parse a rule file - don't ask don't tell - be carefull with this one!
*/
PUBLIC HTStream * HTRules_parseAutomatically (HTRequest *	request,
					      void *		param,
					      HTFormat		input_format,
					      HTFormat		output_format,
					      HTStream *	output_stream)
{
    if (request) {
	HTStream * me;
	HTTRACE(APP_TRACE, "Rule file... Automatic parser object created\n");
	if ((me = (HTStream *) HT_CALLOC(1, sizeof(HTStream))) == NULL)
	    HT_OUTOFMEM("HTRules");
	me->isa = &HTRuleClass;
	me->request = request;
	me->buffer = HTChunk_new(512);
	me->EOLstate = EOL_BEGIN;
	if (!rules) rules = HTList_new();
	return me;
    } else {
	HTRequest_addError(request, ERR_FATAL, NO, HTERR_NO_AUTO_RULES,
			   NULL, 0, "HTRules");
	return HTErrorStream();
    }
}
Beispiel #4
0
PRIVATE int HTSC_putBlock (HTStream * me, const char * b, int l)
{
    me->cur_size += l;

    /*
    ** If we get a buffer overflow and we are going to PUT or POST the document
    ** then ask the user whether it is OK to proceed buffering. Otherwise we
    ** must give up the request. In all other cases we stop if the buffer fills
    ** up.
    */
    if (!me->ignore && me->max_size > 0 && me->cur_size > me->max_size) {
	HTMethod method = HTRequest_method(me->request);
	if (HTMethod_hasEntity(method)) {
	    HTAlertCallback *cbf = HTAlert_find(HT_A_CONFIRM);
	    if ((cbf && (*cbf)(me->request, HT_A_CONFIRM, HT_MSG_BIG_PUT,
			       NULL, NULL, NULL)))
		me->ignore = YES;
	    else
		me->give_up = YES;
	} else {
	    me->give_up = YES;
	}
    } else if (!me->ensure) {
	HTParentAnchor * anchor = HTRequest_anchor(me->request);
	int cl = HTAnchor_length(anchor);
	if (cl > 0) HTChunk_ensure(me->chunk, cl);
	me->ensure = YES;
    }
    if (!me->give_up) {
	HTChunk_putb(me->chunk, b, l);
	return HT_OK;
    }    
    return HT_ERROR;
}
Beispiel #5
0
/*
**  Check the response to see if we got a cookie or more.
**  If so then figure out what to do with it (prompt user, store, etc.)
*/
PRIVATE int HTCookie_afterFilter (HTRequest * request, HTResponse * response,
                                  void * param, int status)
{
    if ((CookieMode & HT_COOKIE_ACCEPT) && SetCookie) {
        HTCookieHolder * holder = HTCookieHolder_find(request);
        if (holder) {
            HTList * cookies = holder->cookies;
            HTCookie * pres;
            while ((pres = (HTCookie *) HTAssocList_nextObject(cookies))) {

                /* Should we check to see if hosts match? */
                if (CookieMode & (HT_COOKIE_SAME_HOST|HT_COOKIE_SAME_DOMAIN)) {
                    char * cookie_host = HTCookie_domain(pres);
                    if (cookie_host) {
                        int res;
                        char * addr = HTAnchor_address((HTAnchor *) HTRequest_anchor(request));
                        char * host = HTParse(addr, "", PARSE_HOST);

                        if (CookieMode & HT_COOKIE_SAME_DOMAIN)
                            res = tailcasecomp(cookie_host, host);
                        else
                            res = strcasecomp(cookie_host, host);

                        if (res != 0) {
                            HTTRACE(APP_TRACE, "Cookie...... Host `%s\' doesn't match what is sent in cookie `%s\'\n" _ host _ cookie_host);
                            HT_FREE(addr);
                            continue;
                        }
                        HT_FREE(addr);
                    }
                }

                /* Should we prompt the user? */
                if (CookieMode & HT_COOKIE_PROMPT) {
                    HTAlertCallback * prompt = HTAlert_find(HT_A_CONFIRM);
                    if (prompt) {
                        if ((*prompt)(request, HT_A_CONFIRM, HT_MSG_ACCEPT_COOKIE,
                                      NULL, NULL, NULL) != YES)
                            continue;
                    } else
                        continue;
                }

                /* Call the application with our new cookie */
                (*SetCookie)(request, pres, SetCookieContext);
            }

            /* Delete cookie holder */
            HTCookieHolder_delete(holder);
        }
    }
    return HT_OK;
}
Beispiel #6
0
PRIVATE int RawCleanup (HTRequest * request, int status)
{
    HTNet * net = HTRequest_net(request);
    raw_info * raw = (raw_info *) HTNet_context(net);

    HTTRACE(PROT_TRACE, "Raw clean... Called with status %d, net %p\n" _ status _ net);

    if (status == HT_INTERRUPTED) {
    	HTAlertCallback * cbf = HTAlert_find(HT_PROG_INTERRUPT);
    	if (cbf) (*cbf)(request, HT_PROG_INTERRUPT,
	    HT_MSG_NULL, NULL, NULL, NULL);
    } else if (status == HT_TIMEOUT) {
    	HTAlertCallback * cbf = HTAlert_find(HT_PROG_TIMEOUT);
    	if (cbf) (*cbf)(request, HT_PROG_TIMEOUT,
	    HT_MSG_NULL, NULL, NULL, NULL);
    }	

    /* Delete the Net object */
    HTNet_delete(net, HT_ERROR);

    HT_FREE(raw);
    return YES;
}
Beispiel #7
0
/*
**	Retry through Proxy AFTER Filter
**	--------------------------------
**	This filter handles a 305 Use Proxy response and retries the request
**	through the proxy
*/
PUBLIC int HTUseProxyFilter (HTRequest * request, HTResponse * response,
			     void * param, int status)
{
    HTAlertCallback * cbf = HTAlert_find(HT_A_CONFIRM);
    HTAnchor * proxy_anchor = HTResponse_redirection(response); 
    if (!proxy_anchor) {
	HTTRACE(PROT_TRACE, "Use Proxy... No proxy location\n");
	return HT_OK;
    }

    /*
    **  Add the proxy to the list. Assume HTTP access method only!
    **  Because evil servers may rediret the client to an untrusted
    **  proxy, we can only accept redirects for this particular
    **  server. Also, we do not know whether this is for HTTP or all
    **  other requests as well
    */
    if ((cbf && (*cbf)(request, HT_A_CONFIRM, HT_MSG_PROXY, NULL,NULL,NULL))) {
	char * addr = HTAnchor_address(proxy_anchor);
	HTProxy_add("http", addr);
	HT_FREE(addr);
 
	/*
	**  Start new request through the proxy if we haven't reached the max
	**  number of redirections for this request
	*/ 
	if (HTRequest_doRetry(request)) { 
	    HTLoadAnchor(proxy_anchor, request);
	} else {
	    HTRequest_addError(request, ERR_FATAL, NO, HTERR_MAX_REDIRECT,
			       NULL, 0, "HTRedirectFilter");
	}

	/*
	**  By returning HT_ERROR we make sure that this is the last handler to be
	**  called. We do this as we don't want any other filter to delete the 
	**  request object now when we have just started a new one ourselves
	*/
	return HT_ERROR;

    } else {
	HTRequest_addError(request, ERR_FATAL, NO, HTERR_NO_AUTO_PROXY,
			   NULL, 0, "HTUseProxyFilter");
	return HT_OK;
    }
} 
Beispiel #8
0
/*	terminate_handler
**	-----------------
**	This function is registered to handle the result of the request
*/
PRIVATE int terminate_handler (HTRequest * request, HTResponse * response,
			       void * param, int status) 
{
    ComLine * cl = (ComLine *) HTRequest_context(request);
    if (status == HT_LOADED) {
	if (cl) {
	    if (cl->flags & CL_COUNT) {
		HTPrint("Content Length found to be %ld\n",
			 HTAnchor_length(cl->anchor));
	    }
	}
    } else {
	HTAlertCallback *cbf = HTAlert_find(HT_A_MESSAGE);
	if (cbf) (*cbf)(request, HT_A_MESSAGE, HT_MSG_NULL, NULL,
			HTRequest_error(request), NULL);
    }
    Cleanup(cl, (status/100 == 2) ? 0 : -1);
    return HT_OK;
}
Beispiel #9
0
/* return whether to give up the ghost
 */
#if 0 /* obsolete */
PUBLIC BOOL warn(CSParse_t * pCSParse, Message_t message, ...)
{
    va_list list;
    char space[257];
    char ** messages = CSParse_getMessages();
    HTAlertCallback *cbf = HTAlert_find(HT_A_CONFIRM);

    va_start(list, message);
    if (message >= message_COUNT) {
        HTTrace("Yous got a error\n");
        return YES;
    }
    vsprintf(space, messages[message], list);
    va_end(list);
    HTTrace(space);
    HTTrace("\n");
    if (cbf && (*cbf)(0, HT_A_CONFIRM, HT_MSG_RULES, NULL, NULL, NULL))
        return NO;
    return YES;
}
Beispiel #10
0
/*
**	This is our handle to the server reply stream when data is coming
**	back from our "client" request. It is responsible for setting up the
**	remaining streams in order to produce a complete HTTP output.
**	If we have a HTTP 1.x response then forward untouched.
*/
PRIVATE int MakeReplyPipe (HTStream * me, HTRequest * client)
{
    char * response_line = NULL;

    /* Generate the Response line */
    {
        HTAlertCallback *cbf = HTAlert_find(HT_A_MESSAGE);
        if (cbf) {
            HTAlertPar * reply = HTAlert_newReply();
            if ((*cbf)(client, HT_A_MESSAGE, HT_MSG_NULL, NULL,
                       HTRequest_error(client), reply))
                response_line = HTAlert_replyMessage(reply);
            HTAlert_deleteReply(reply);
        }

        if (response_line) {
            PUTS(response_line);
            HT_FREE(response_line);
        } else {
            PUTS(HTTP_VERSION);
            PUTS(" 500 Internal");
            PUTC(CR);
            PUTC(LF);
        }
    }

    /*
    ** We now have to create the rest of the response stream. We see whether
    ** there is a data object or not by looking at the Content Type of the
    ** client anchor.
    */
    {
        HTParentAnchor * anchor = HTRequest_anchor(client);
        HTFormat format = HTAnchor_format(anchor);
        me->target = (format == WWW_UNKNOWN) ?
                     HTTPResponse_new(client, me->target, YES, HTTP_11) :
                     HTMIMERequest_new(client,
                                       HTTPResponse_new(client,me->target, NO, HTTP_11), YES);
    }
    return HT_OK;
}
Beispiel #11
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;
}
Beispiel #12
0
/*
**	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;
}
Beispiel #13
0
/*
**	Redirection AFTER filter
**	------------------------
**	The redirection handler only handles redirections
**	on the GET or HEAD method (or any other safe method)
*/
PUBLIC int HTRedirectFilter (HTRequest * request, HTResponse * response,
			     void * param, int status)
{
    HTMethod method = HTRequest_method(request); 
    HTAnchor * new_anchor = HTResponse_redirection(response); 

    /* Check for destination */
    if (!new_anchor) {
	HTTRACE(PROT_TRACE, "Redirection. No destination\n");
	return HT_OK;
    }

    /*
    ** Only do automatic redirect on GET and HEAD. Ask for all
    ** other methods.
    */
    if (!HTMethod_isSafe(method)) {

	/*
	** If we got a 303 See Other then change the method to GET.
	** Otherwise ask the user whether we should continue.
	*/
	if (status == HT_SEE_OTHER) {
	    HTTRACE(PROT_TRACE, "Redirection. Changing method from %s to GET\n" _ 
			HTMethod_name(method));
	    HTRequest_setMethod(request, METHOD_GET);
	} else {
	    HTAlertCallback * prompt = HTAlert_find(HT_A_CONFIRM);
	    if (prompt) {
		if ((*prompt)(request, HT_A_CONFIRM, HT_MSG_REDIRECTION,
			      NULL, NULL, NULL) != YES)
		    return HT_OK;
	    }
	}
    } 

    /* Register the redirection as a link relationship */
    {
	HTLinkType ltype = status==HT_PERM_REDIRECT ? HT_LR_PERM_REDIRECT :
	    (status==HT_TEMP_REDIRECT || status==HT_FOUND) ? HT_LR_TEMP_REDIRECT :
	    status==HT_SEE_OTHER ? HT_LR_SEE_OTHER : NULL;
	if (ltype) {
	    HTLink_add((HTAnchor *) HTRequest_anchor(request), new_anchor, 
		       ltype, method);
	}
    }

    /* Delete any auth credendials as they get regenerated */
    HTRequest_deleteCredentialsAll(request);

    /*
    **  Start new request with the redirect anchor found in the headers.
    **	Note that we reuse the same request object which means that we must
    **  keep this around until the redirected request has terminated. It also
    **  allows us in an easy way to keep track of the number of redirections
    **	so that we can detect endless loops.
    */ 
    if (HTRequest_doRetry(request)) { 
	HTLoadAnchor(new_anchor, request);
    } else {
	HTRequest_addError(request, ERR_FATAL, NO, HTERR_MAX_REDIRECT,
			   NULL, 0, "HTRedirectFilter");
	return HT_OK;		/* Wanna fall through */
    }

    /*
    **  By returning HT_ERROR we make sure that this is the last handler to be
    **  called. We do this as we don't want any other filter to delete the 
    **  request object now when we have just started a new one ourselves
    */
    return HT_ERROR;
} 
Beispiel #14
0
/*	Save Locally
**	------------
**	Saves a file to local disk. This can for example be used to dump
**	data objects of unknown media types to local disk. The stream prompts
**	for a file name for the temporary file.
*/
PUBLIC HTStream* HTSaveLocally (HTRequest *	request,
				void *		param,
				HTFormat	input_format,
				HTFormat	output_format,
				HTStream *	output_stream)
{
    FILE * fp = NULL;
    char * filename = NULL;
    HTUserProfile * up = HTRequest_userProfile(request);
    char * tmproot = HTUserProfile_tmp(up);
    if (HTLib_secure()) {
	HTRequest_addError(request, ERR_NON_FATAL, NO, HTERR_UNAUTHORIZED,
			   NULL, 0, "HTSaveLocally");
	return HTErrorStream();
    }
    if (!tmproot) {
	HTTRACE(STREAM_TRACE, "Save File... turned off\n");
	return HTErrorStream();
    }
	
    /* Let's prompt the user for a file name for this file */
    {
	HTAlertCallback *cbf = HTAlert_find(HT_A_PROMPT);
	HTParentAnchor *anchor = (HTParentAnchor *) HTRequest_anchor(request);

	/*
	**  If we found an alert handler for prompting the user then call it.
	**  If not then either we are in non-interactive mode or no handler
	**  has been registered. For now we then return a blackhole which may
	**  not be the best thing to do.
	*/
	if (cbf) {
	    HTAlertPar * reply = HTAlert_newReply();
	    char * suffix = HTBind_getSuffix(anchor);
	    char * deflt = get_filename(tmproot, HTAnchor_physical(anchor), suffix, YES);
	    if ((*cbf)(request, HT_A_PROMPT, HT_MSG_FILENAME,deflt,NULL,reply))
		filename = HTAlert_replyMessage(reply);
	    HTAlert_deleteReply(reply);
	    HT_FREE(suffix);
	    HT_FREE(deflt);
	}
	if (filename) {
	    if ((fp = fopen(filename, "wb")) == NULL) {
		HTRequest_addError(request, ERR_NON_FATAL, NO, HTERR_NO_FILE,
				   filename, strlen(filename),"HTSaveLocally");
		HT_FREE(filename);
		return HTErrorStream();
	    }
	} else if (cbf) {
	    HTTRACE(STREAM_TRACE, "Save File... No file name - error stream\n");
	    return HTErrorStream();
	} else {
	    HTTRACE(STREAM_TRACE, "Save File... No file name - black hole\n");
	    return HTBlackHole();
	}
    }
    
    /* Now we are ready for creating the file writer stream */
    if (fp) {
	HTStream * me = HTFileSave_new(request, fp, NO);
	me->filename = filename;
	return me;
    }
    HT_FREE(filename);
    return HTErrorStream();
}
Beispiel #15
0
PRIVATE int HTSSLReader_read (HTInputStream * me)
{
    HTHost * host = me->host;
    SOCKET soc = HTChannel_socket(me->ch);
    HTNet * net = HTHost_getReadNet(host);
    HTRequest * request = HTNet_request(net);
    int status;
    if (!net->readStream) {
	HTTRACE(STREAM_TRACE, "HTSSLReader. No read stream for net object %p\n" _ net);
        return HT_ERROR;
    }
        
    /* Setting SSL */
    if (!me->htssl) {
	if ((me->htssl = HTSSL_new(soc)) == NULL) {
	    HTRequest_addSystemError(net->request, ERR_FATAL, socerrno, NO, "SSLREAD");
	    return HT_ERROR;
	}
    }

    /* Read from socket if we got rid of all the data previously read */
    do {

	/* Don't read if we have to push unwritten data from last call */
        if (me->write >= me->read) {
            me->b_read = 0;
            me->data[0] ='\0';
 	    me->b_read = HTSSL_read(me->htssl, soc, me->data, INPUT_BUFFER_SIZE);     
	    status = HTSSL_getError(me->htssl, me->b_read);
	    HTTRACE(STREAM_TRACE, "HTSSLReader. SSL returned %d\n" _ status);

	    /* Check what we got done */
	    switch (status) {

	    case SSL_ERROR_NONE:

		HTTRACEDATA(me->data, me->b_read, "Reading from socket %d" _ soc);
		me->write = me->data;
		me->read = me->data + me->b_read;
		HTTRACE(STREAM_TRACE, "HTSSLReader. %d bytes read from socket %d\n" _ 
			me->b_read _ soc);

		/* Make progress notification */
		if (request) {
		    HTAlertCallback * cbf = HTAlert_find(HT_PROG_READ);
		    if (HTNet_rawBytesCount(net))
			HTNet_addBytesRead(net, me->b_read);
		    if (cbf) {
			int tr = HTNet_bytesRead(net);
			(*cbf)(request, HT_PROG_READ, HT_MSG_NULL, NULL, &tr, NULL);
		    }
		}
		break;

	    case SSL_ERROR_WANT_READ:
		HTTRACE(STREAM_TRACE, "HTSSLReader. WOULD BLOCK fd %d\n" _ soc);
		HTHost_register(host, net, HTEvent_READ);

		/*
		**  There seems to be a bug as even though it says "read finished"
		**  it doesn't say that it wants to write. We therefore have to make
		**  an explicit flush to make sure that we don't block forever.
		*/
		HTHost_forceFlush(host);

		return HT_WOULD_BLOCK;

	    case SSL_ERROR_WANT_WRITE:
		return HTHost_forceFlush(host);

	    case SSL_ERROR_WANT_X509_LOOKUP:
		/* @@@ what to do here? @@@ */
		return HT_OK;

	    case SSL_ERROR_ZERO_RETURN:
	    case SSL_ERROR_SSL:
	    case SSL_ERROR_SYSCALL:
		HTTRACE(PROT_TRACE, "HTSSLReader. FIN received on socket %d\n" _ soc);
                HTHost_unregister(host, net, HTEvent_READ);
                HTHost_register(host, net, HTEvent_CLOSE);

                HTSSL_close(me->htssl);    
                HTSSL_free(me->htssl);
                me->htssl = NULL;

                return HT_CLOSED;
	    }
	}

#ifdef FIND_SIGNATURES
	{
	    char * ptr = me->data;
	    int len = me->b_read;
	    while ((ptr = strnstr(ptr, &len, "HTTP/1.1 200 OK")) != NULL) {
		HTTRACE(STREAM_TRACE, "HTSSLReader. Signature found at 0x%x of 0x%x.\n" _ ptr - me->data _ me->b_read);
		ptr++;
		len--;
	    }
	}
#endif /* FIND_SIGNATURES */
 #ifdef NOT_ASCII
	{
	    char *p = me->data;
	    while (p < me->read) {
		*p = FROMASCII(*p);
		p++;
	    }
	}
#endif /* NOT_ASCII */
	
	/* Now push the data down the stream */
	if ((status = (*net->readStream->isa->put_block)
	     (net->readStream, me->write, me->b_read)) != HT_OK) {
	    if (status == HT_WOULD_BLOCK) {
		HTTRACE(STREAM_TRACE, "HTSSLReader. Target WOULD BLOCK\n");
		HTHost_unregister(host, net, HTEvent_READ);
		return HT_WOULD_BLOCK;
	    } else if (status == HT_PAUSE) {
		HTTRACE(STREAM_TRACE, "HTSSLReader. Target PAUSED\n");
		HTHost_unregister(host, net, HTEvent_READ);
		return HT_PAUSE;
	    /* CONTINUE code or stream code means data was consumed */
	    } else if (status == HT_CONTINUE || status > 0) {
		if (status == HT_CONTINUE) {
		    HTTRACE(STREAM_TRACE, "HTSSLReader. CONTINUE\n");
		} else
		    HTTRACE(STREAM_TRACE, "HTSSLReader. Target returns %d\n" _ status);
/*		me->write = me->read; */
		return status;
	    } else {				     /* We have a real error */
		HTTRACE(STREAM_TRACE, "HTSSLReader. Target ERROR %d\n" _ status);
		return status;
	    }
	}
	me->write = me->read;
	{
	    int remaining = HTHost_remainingRead(host);
	    if (remaining > 0) {
		HTTRACE(STREAM_TRACE, "HTSSLReader. DIDN'T CONSUME %d BYTES: `%s\'\n" _ 
			    remaining _ me->read);
		HTHost_setConsumed(host, remaining);
	    }
	}
    } while (net->preemptive);
    HTHost_register(host, net, HTEvent_READ);
    return HT_WOULD_BLOCK;
}
Beispiel #16
0
/*	HTGetHostByName
**	---------------
**	Resolve the host name using internal DNS cache. As we want to refer   
**	a specific host when timing the connection the weight function must
**	use the 'current' value as returned.
**      Returns:
**	       	>0	Number of homes
**		-1	Error
*/
PUBLIC int HTGetHostByName (HTHost * host, char *hostname, HTRequest* request)
{
    SockA *sin = HTHost_getSockAddr(host);
    int homes = -1;
    HTList *list;				    /* Current list in cache */
    HTdns *pres = NULL;
    if (!host || !hostname) {
	HTTRACE(PROT_TRACE, "HostByName.. Bad argument\n");
	return -1;
    }
    HTHost_setHome(host, 0);
    
    /* Find a hash for this host */
    {
	int hash = 0;
	char *ptr;
	for(ptr=hostname; *ptr; ptr++)
	    hash = (int) ((hash * 3 + (*(unsigned char *) ptr)) % HT_M_HASH_SIZE);
	if (!CacheTable) {
	    if ((CacheTable = (HTList* *) HT_CALLOC(HT_M_HASH_SIZE, sizeof(HTList *))) == NULL)
	        HT_OUTOFMEM("HTDNS_init");
	}
	if (!CacheTable[hash]) CacheTable[hash] = HTList_new();
	list = CacheTable[hash];
    }

    /* Search the cache */
    {
	HTList *cur = list;
	while ((pres = (HTdns *) HTList_nextObject(cur))) {
	    if (!strcmp(pres->hostname, hostname)) {
		if (time(NULL) > pres->ntime + DNSTimeout) {
		    HTTRACE(PROT_TRACE, "HostByName.. Refreshing cache\n");
		    delete_object(list, pres);
		    pres = NULL;
		}
		break;
	    }
	}
    }
    if (pres) {
	/*
	** Find the best home. We still want to do this as we use it as a
	** fall back for persistent connections
	*/
	homes = pres->homes;
	if (pres->homes > 1) {
	    int cnt = 0;
	    double best_weight = 1e30;			      /* Pretty bad */
	    while (cnt < pres->homes) {
		if (*(pres->weight+cnt) < best_weight) {
		    best_weight = *(pres->weight+cnt);
		    HTHost_setHome(host, cnt);
		}
		cnt++;
	    }
	}
	host->dns = pres;
	memcpy((void *) &sin->sin_addr, *(pres->addrlist+HTHost_home(host)),
	       pres->addrlength);
    } else {
	struct hostent *hostelement;			      /* see netdb.h */
	HTAlertCallback *cbf = HTAlert_find(HT_PROG_DNS);
#ifdef HT_REENTRANT
	int thd_errno;
	char buffer[HOSTENT_MAX];
	struct hostent result;			      /* For gethostbyname_r */
#endif
#ifdef HAVE_GETHOSTBYNAME_R_3
        struct hostent_data hdata;
#endif

	if (cbf) (*cbf)(request, HT_PROG_DNS, HT_MSG_NULL,NULL,hostname,NULL);
#ifdef HAVE_GETHOSTBYNAME_R_5
	hostelement = gethostbyname_r(hostname, &result, buffer,
				      HOSTENT_MAX, &thd_errno);
#elif defined(HAVE_GETHOSTBYNAME_R_6)
	gethostbyname_r(hostname, &result, buffer,
		        HOSTENT_MAX, &hostelement, &thd_errno);

#elif defined(HAVE_GETHOSTBYNAME_R_3)
        if (gethostbyname_r(hostname, &result, &hdata) == 0) {
	    hostelement = &result;
	}
	else {
	    hostelement = NULL;
	}
#else
	if (cbf) (*cbf)(request, HT_PROG_DNS, HT_MSG_NULL,NULL,hostname,NULL);
	hostelement = gethostbyname(hostname);
#endif
	if (!hostelement) {
            HTRequest_addSystemError(request, ERR_FATAL, socerrno, NO,
   			             "gethostbyname");
	    return -1;
	}	
	host->dns = HTDNS_add(list, hostelement, hostname, &homes);
	memcpy((void *) &sin->sin_addr, *hostelement->h_addr_list,
	       hostelement->h_length);
    }
    return homes;
}
Beispiel #17
0
/*	Write to the socket
**
** According to Solaris 2.3 man on write:
**
**    o	If O_NONBLOCK and O_NDELAY are clear, write() blocks
**	until the data can be accepted.
**
**    o	If O_NONBLOCK or O_NDELAY is set, write()  does  not
**	block  the  process.   If  some  data  can be written
**	without blocking the process, write() writes what  it
**	can  and returns the number of bytes written.  Other-
**	wise, if O_NONBLOCK is set, it returns - 1  and  sets
**	errno to EAGAIN or if O_NDELAY is set, it returns 0.
**
** According to SunOS 4.1.1 man on write:
**
**   +	If the descriptor is  marked  for  non-blocking  I/O
**	using  fcntl()  to  set  the FNONBLOCK or O_NONBLOCK
**	flag (defined in  <sys/fcntl.h>),  write()  requests
**	for  {PIPE_BUF}  (see  pathconf(2V))  or fewer bytes
**	either  succeed  completely  and  return  nbyte,  or
**	return -1 and set errno to EAGAIN. A write() request
**	for greater than {PIPE_BUF} bytes  either  transfers
**	what it can and returns the number of bytes written,
**	or transfers no data and returns -1 and  sets  errno
**	to  EAGAIN.  If  a  write()  request is greater than
**	{PIPE_BUF} bytes and all data previously written  to
**	the  pipe  has been read, write() transfers at least
**	{PIPE_BUF} bytes.
*/
PRIVATE int HTWriter_write (HTOutputStream * me, const char * buf, int len)
{
    HTHost * host = me->host;
    SOCKET soc = HTChannel_socket(HTHost_channel(host));
    HTNet * net = HTHost_getWriteNet(host);
    int b_write;
    char * wrtp;
    const char *limit = buf+len;

    /* If we don't have a Net object then return right away */
    if (!net) {
        HTTRACE(STREAM_TRACE, "Write Socket No Net object %d (offset %d)\n" _ soc _ me->offset);
        return HT_ERROR;
    }

#ifdef NOT_ASCII
    if (len && !me->ascbuf) {			      /* Generate new buffer */
        const char *orig = buf;
        char *dest;
        int cnt;
        if ((me->ascbuf = (char  *) HT_MALLOC(len)) == NULL)
            HT_OUTOFMEM("HTWriter_write");
        dest = me->ascbuf;
        for (cnt=0; cnt<len; cnt++) {
            *dest = TOASCII(*orig);
            dest++, orig++;
        }
        wrtp = me->ascbuf;
        limit = me->ascbuf+len;
    }
#else
    if (!me->offset)
        wrtp = (char *) buf;
    else {
        wrtp = (char *) buf + me->offset;
        len -= me->offset;
        me->offset = 0;
    }
#endif

    /* Write data to the network */
    while (wrtp < limit) {
        if ((b_write = NETWRITE(soc, wrtp, len)) < 0) {
#ifdef EAGAIN
            if (socerrno == EAGAIN || socerrno == EWOULDBLOCK)/* POSIX, SVR4 */
#else
            if (socerrno == EWOULDBLOCK)			      /* BSD */
#endif
            {
                HTHost_register(host, net, HTEvent_WRITE);
                me->offset = wrtp - buf;
                HTTRACE(STREAM_TRACE, "Write Socket WOULD BLOCK %d (offset %d)\n" _ soc _ me->offset);
                return HT_WOULD_BLOCK;
#ifdef EINTR
            } else if (socerrno == EINTR) {
                /*
                **	EINTR	A signal was caught during the  write  opera-
                **		tion and no data was transferred.
                */
                HTTRACE(STREAM_TRACE, "Write Socket call interrupted - try again\n");
                continue;
#endif
            } else {
                host->broken_pipe = YES;
#ifdef EPIPE
                if (socerrno == EPIPE) {
                    /* JK: an experimental bug solution proposed by
                               Olga and Mikhael */
                    HTTRACE(STREAM_TRACE, "Write Socket got EPIPE\n");
                    HTHost_unregister(host, net, HTEvent_WRITE);
                    HTHost_register(host, net, HTEvent_CLOSE);
                    /* @@ JK: seems that some functions check the errors
                       as part of the flow control */
                    HTRequest_addSystemError(net->request, ERR_FATAL, socerrno, NO,
                                             "NETWRITE");
                    return HT_CLOSED;
                }
#endif /* EPIPE */
                /* all errors that aren't EPIPE */
                HTRequest_addSystemError(net->request, ERR_FATAL, socerrno, NO,
                                         "NETWRITE");
                return HT_ERROR;
            }
        }

        /* We do this unconditionally, should we check to see if we ever blocked? */
        HTTRACEDATA(wrtp, b_write, "Writing to socket %d" _ soc);
        HTNet_addBytesWritten(net, b_write);
        wrtp += b_write;
        len -= b_write;
        HTTRACE(STREAM_TRACE, "Write Socket %d bytes written to %d\n" _ b_write _ soc);
        {
            HTAlertCallback *cbf = HTAlert_find(HT_PROG_WRITE);
            if (cbf) {
                int tw = HTNet_bytesWritten(net);
                (*cbf)(net->request, HT_PROG_WRITE,
                       HT_MSG_NULL, NULL, &tw, NULL);
            }
        }
    }
#ifdef NOT_ASCII
    HT_FREE(me->ascbuf);
#endif
    return HT_OK;
}