コード例 #1
0
ファイル: HTFilter.c プロジェクト: svagionitis/libwww
/*
**	Proxy and Gateway BEFORE filter
**	-------------------------------
**	Checks for registerd proxy servers or gateways and sees whether this
**	request should be redirected to a proxy or a gateway. Proxies have
**	higher priority than gateways so we look for them first!
**	For HTTP/1.0 and HTTP/1.1 we may only send a full URL (including the
**	host portion) to proxy servers. Therefore, we tell the Library whether
**	to use the full URL or the traditional HTTP one without the host part.
*/
PUBLIC int HTProxyFilter (HTRequest * request, void * param, int mode)
{
    HTParentAnchor * anchor = HTRequest_anchor(request);
    char * addr = HTAnchor_physical(anchor);
    char * physical = NULL;
    if ((physical = HTProxy_find(addr))) {
	HTRequest_setFullURI(request, YES);			  /* For now */
	HTRequest_setProxy(request, physical);
	HT_FREE(physical);
#if 0
	/* Don't paste the URLs together anymore */
	StrAllocCat(physical, addr);
	HTAnchor_setPhysical(anchor, physical);	
#endif
    } else if ((physical = HTGateway_find(addr))) {
	/* 
	** A gateway URL is crated by chopping off any leading "/" to make the
	** host into part of path
	*/
	char * path =
	    HTParse(addr, "", PARSE_HOST + PARSE_PATH + PARSE_PUNCTUATION);
	char * gatewayed = HTParse((*path=='/') ? path+1 : path, physical, PARSE_ALL);
	HTAnchor_setPhysical(anchor, gatewayed);
	HT_FREE(path);
	HT_FREE(gatewayed);
	HTRequest_setFullURI(request, NO);
	HTRequest_deleteProxy(request);
    } else {
	HTRequest_setFullURI(request, NO);			  /* For now */
	HTRequest_deleteProxy(request);
    }
    return HT_OK;
}
コード例 #2
0
ファイル: HTFSave.c プロジェクト: svagionitis/libwww
/*	Take action using a system command
**	----------------------------------
**	Creates temporary file, writes to it and then executes system
**	command (maybe an external viewer) when EOF has been reached. The
**	stream finds a suitable name of the temporary file which preserves the
**	suffix. This way, the system command can find out the file type from
**	the name of the temporary file name.
*/
PUBLIC HTStream* HTSaveAndExecute (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");
	return HTErrorStream();
    }
	
    /* Let's find a hash name for this file without asking user */
    {
	HTParentAnchor *anchor = (HTParentAnchor *) HTRequest_anchor(request);
	char *suffix = HTBind_getSuffix(anchor);
	filename = get_filename(tmproot, HTAnchor_physical(anchor), suffix, NO);
	HT_FREE(suffix);
	if (filename) {
	    if ((fp = fopen(filename, "wb")) == NULL) {
		HTRequest_addError(request, ERR_NON_FATAL, NO, HTERR_NO_FILE,
				   filename, strlen(filename),"HTSaveAndExecute");
		HT_FREE(filename);
		return HTErrorStream();
	    }
	} else {
	    HTTRACE(STREAM_TRACE, "Save File... No file name\n");
	    return HTErrorStream();
	}
    }
    
    /* Now we are ready for creating the file writer stream */
    if (fp) {
	HTStream * me = HTFileSave_new(request, fp, NO);
	me->filename = filename;
	if (param) {
	    if ((me->end_command = (char  *) HT_MALLOC((strlen((char *) param) + 10 + 3*strlen(filename)))) == NULL)
		HT_OUTOFMEM("SaveAndExecute");
	    sprintf (me->end_command,
		     (char *)param, filename, filename, filename);
	}
	return me;
    }
    HT_FREE(filename);
    return HTErrorStream();
}
コード例 #3
0
ファイル: HTNDir.c プロジェクト: BackupTheBerlios/texlive
/*	HTNewsDir_new
**	----------
**    	Creates a structured stream object and sets up the initial HTML stuff
**	Returns the newsdir object if OK, else NULL
*/
PUBLIC HTNewsDir * HTNewsDir_new (HTRequest * request, const char * title,
				  HTNewsDirKey key, BOOL cache)
{
    HTNewsDir *dir;
    if (!request) return NULL;

    /* Create object */
    if ((dir = (HTNewsDir *) HT_CALLOC(1, sizeof (HTNewsDir))) == NULL)
        HT_OUTOFMEM("HTNewsDir_new");
    dir->target = HTMLGenerator(request, NULL, WWW_HTML,
				HTRequest_outputFormat(request),
				HTRequest_outputStream(request));
    HTAnchor_setFormat(HTRequest_anchor(request), WWW_HTML);
    dir->request = request;
    dir->key = key;
    dir->lastLevel = -1;  /* Added by MP. */

    /*  Get the newsgroup(s) name; added by MP. */
    {
        char* url = HTAnchor_physical(HTRequest_anchor(request));
        char* p = url+strlen(url);
        while (p > url && p[-1] != ':' && p[-1] != '/' && p[-1] != '\\')
            p--;
        StrAllocCopy (dir->name, p);
    }

    if (key != HT_NDK_NONE) {			       /* Thread is unsorted */
	int total = HTNews_maxArticles();
	dir->array = HTArray_new(total > 0 ? total : 128);
    }

    /* If we are asked to prepare a cache entry then create the cache array */
    if (cache) {
	int total = HTNews_maxArticles();
	dir->cache = HTArray_new(total > 0 ? total : 128);
    }

    /* Start the HTML stuff */
    {
	HTStructured *target = dir->target;
	const char *msg = title ? title : "News Listing";
	START(HTML_HTML);
	START(HTML_HEAD);
	START(HTML_TITLE);
	PUTS(msg);
	END(HTML_TITLE);
	END(HTML_HEAD);
	START(HTML_BODY);
	START(HTML_H1);
	PUTS(msg);
	END(HTML_H1);
    }
    return dir;
}
コード例 #4
0
ファイル: HTNewsLs.c プロジェクト: Hiroyuki-Nagata/libwww
/* Helper function added by MP. */
PRIVATE char* GetNewsGroupTitle (HTRequest* request)
{
    char * url = HTAnchor_physical(HTRequest_anchor(request));
    char * title = NULL;
    if (strrchr(url, '*'))
        StrAllocCopy(title, "Newsgroups: ");
    else
        StrAllocCopy(title, "Newsgroup: ");
    if (!strncasecomp(url, "news:", 5))
	StrAllocCat(title, url+5);
    else
	StrAllocCat(title, HTParse(url, "", PARSE_PATH));
    return title;
}
コード例 #5
0
ファイル: HTFilter.c プロジェクト: svagionitis/libwww
/*
**	Rule Translation BEFORE Filter
**	------------------------------
**	If we have a set of rules loaded (see the Rule manager) then check
**	before each request whether how that should be translated. The trick
**	is that a parent anchor has a "address" which is the part from the URL
**	we used when we created the anchor. However, it also have a "physical
**	address" which is the place we are actually going to look for the
**	resource. Hence this filter translates the physical address
**	(if any translations are found)
*/
PUBLIC int HTRuleFilter (HTRequest * request, void * param, int mode)
{
    HTList * list = HTRule_global();
    HTParentAnchor * anchor = HTRequest_anchor(request);
    char * addr = HTAnchor_physical(anchor);
    char * physical = HTRule_translate(list, addr, NO);
    if (!physical) {
	HTRequest_addError(request, ERR_FATAL, NO, HTERR_FORBIDDEN,
			   NULL, 0, "HTRuleFilter");
	return HT_ERROR;
    }
    HTAnchor_setPhysical(anchor, physical);
    HT_FREE(physical);
    return HT_OK;
}
コード例 #6
0
ファイル: HTFile.c プロジェクト: BackupTheBerlios/texlive
PUBLIC int HTLoadFile (SOCKET soc, HTRequest * request)
{
    file_info *file;			      /* Specific access information */
    HTNet * net = HTRequest_net(request);
    HTParentAnchor * anchor = HTRequest_anchor(request);

    HTTRACE(PROT_TRACE, "HTLoadFile.. Looking for `%s\'\n" _ 
			    HTAnchor_physical(anchor));
    if ((file = (file_info *) HT_CALLOC(1, sizeof(file_info))) == NULL)
	HT_OUTOFMEM("HTLoadFILE");
    file->state = FS_BEGIN;
    file->net = net;
    HTNet_setContext(net, file);
    HTNet_setEventCallback(net, FileEvent);
    HTNet_setEventParam(net, file);  /* callbacks get http* */

    return FileEvent(soc, file, HTEvent_BEGIN);	    /* get it started - ops is ignored */
}
コード例 #7
0
ファイル: HTNewsRq.c プロジェクト: stefanhusmann/Amaya
/*	NewsPost_start
**	--------------
**	NNTP needs two extra headers: "From" and "Newsgroups".
**	Take the newsgroups from the Postweb model as destinations for this
**	anchor.
**	Return YES if OK else NO
*/
PRIVATE BOOL NewsPost_start (HTStream * me, HTRequest * request)
{
    char linebuf[128];		/* @@@ */
    HTChunk *header = me->buffer;
    HTUserProfile * up = HTRequest_userProfile(request);
    const char * mailaddress = HTUserProfile_email(up);
    if (mailaddress) {
	sprintf(linebuf, "From: %s%c%c", mailaddress, CR, LF);
	HTChunk_puts(header, linebuf);
    }

    /*
    **	Find all the newsgroups we are posting to by looking at all the
    **  destinations from the source of this request.
    ** 	First the main link and then the sub links
    */
    HTChunk_puts(header, "Newsgroups :");    
    if (HTRequest_isDestination(request)) {
	HTRequest *src_req = HTRequest_source(request);
	HTParentAnchor *src_anchor = HTRequest_anchor(src_req);
	HTLink *link = HTAnchor_mainLink((HTAnchor *) src_anchor);
	HTAnchor *dest = HTLink_destination(link);
	HTMethod method = HTLink_method(link);
	if (link && method == METHOD_POST &&
	    HTLink_result(link) == HT_LINK_NONE) {
	    char *desturl = HTAnchor_physical((HTParentAnchor *) dest);
	    char *access = HTParse(desturl, "", PARSE_ACCESS);
	    if (!strcasecomp(access, "news") || !strcasecomp(access, "nntp")) {
		char *newsgroup = HTParse(desturl, "", PARSE_PATH);
		HTUnEscape(newsgroup);
		HTCleanTelnetString(newsgroup);
		HTChunk_puts(header, newsgroup);
		HT_FREE(newsgroup);
	    }
	    HT_FREE(access);
	}

	/* DO FOR ALL SUB ANCHOR DESTINATION S AS WELL */
	
    }
    HTTRACE(PROT_TRACE, "News Tx..... %s" _ HTChunk_data(header));
    return YES;
}
コード例 #8
0
ファイル: HTNews.c プロジェクト: ChatanW/WebDaM
PUBLIC int HTLoadNews (SOCKET soc, HTRequest * request)
{
    news_info *news;
    HTParentAnchor *anchor = HTRequest_anchor(request);
    HTNet * net = HTRequest_net(request);
    char * url = HTAnchor_physical(anchor);

    HTTRACE(PROT_TRACE, "NNTP........ Looking for `%s\'\n" _ url);
    if ((news = (news_info *) HT_CALLOC(1, sizeof(news_info))) == NULL)
	HT_OUTOFMEM("HTLoadNews");
    news->cmd = HTChunk_new(128);
    news->state = NEWS_BEGIN;
    news->net = net;
    HTNet_setContext(net, news);
    HTNet_setEventCallback(net, NewsEvent);
    HTNet_setEventParam(net, news);  /* callbacks get http* */

    return NewsEvent(soc, news, HTEvent_BEGIN);		/* get it started - ops is ignored */
}
コード例 #9
0
ファイル: HTTPReq.c プロジェクト: Hiroyuki-Nagata/libwww
/*	HTTP09Request
**	-------------
**	Makes a HTTP/0.9 request
*/
PRIVATE int HTTP09Request (HTStream * me, HTRequest * request)
{
    HTParentAnchor * anchor = HTRequest_anchor(request);
    char * addr = HTAnchor_physical(anchor);
    if (!me->url) me->url = HTParse(addr, "", PARSE_PATH|PARSE_PUNCTUATION);
    if (me->state == 0) {
	int status = PUTS("GET ");
	if (status != HT_OK) return status;
	me->state++;
    }
    if (me->state == 1) {
	int status = PUTS(me->url);
	if (status != HT_OK) return status;
	me->state++;
    }
    PUTC(CR);
    PUTC(LF);
    HTTRACE(PROT_TRACE, "HTTP........ Generating HTTP/0.9 Request\n");
    return HT_OK;
}
コード例 #10
0
ファイル: HTSocket.c プロジェクト: ChatanW/WebDaM
PUBLIC int HTLoadSocket (SOCKET soc, HTRequest * request)
{
    raw_info * raw;			    /* Specific protocol information */
    HTNet * net = HTRequest_net(request);
    HTTRACE(PROT_TRACE, "Load socket. Setting up socket for accept\n");
    if ((raw = (raw_info *) HT_CALLOC(1, sizeof(raw_info))) == NULL)
      HT_OUTOFMEM("HTLoadSocket");
    raw->state = RAW_BEGIN;
    raw->net = net;
    raw->request = request;
    HTNet_setContext(net, raw);
    HTNet_setEventCallback(net, SocketEvent);
    HTNet_setEventParam(net, raw);

    /* Start listening on a socket */
    if (HTHost_listen(NULL, net, HTAnchor_physical(HTRequest_anchor(request))) == HT_ERROR)
	return SocketEvent(soc, raw, HTEvent_CLOSE);

    /* Get it started - ops is ignored */
    return SocketEvent(soc, raw, HTEvent_BEGIN);
}
コード例 #11
0
ファイル: HTFWriter.c プロジェクト: kotohvost/yui
/*	Take action using a system command
**	----------------------------------
**
**	Creates temporary file, writes to it, executes system command
**	on end-document.  The suffix of the temp file can be given
**	in case the application is fussy, or so that a generic opener can
**	be used.
*/
PUBLIC HTStream* HTSaveAndExecute ARGS5(
	HTRequest *,		request,
	void *,			param,
	HTFormat,		input_format,
	HTFormat,		output_format,
	HTStream *,		output_stream)

#ifdef unix
#define REMOVE_FILE unlink
#endif
#ifdef VMS
#define REMOVE_FILE unlink		/* ok? */
#endif

#ifdef REMOVE_FILE
{
    char *fnam, *physical;

    HTStream* me;

    if (HTSecure) {
	HTAlert("Can't save data to file -- please run WWW locally");
	return HTBlackHole();
    }

    if (!HTSaveLocallyDir) {
	if (TRACE) fprintf(stderr, "Save and execute turned off");
	return HTBlackHole();
    }

    me = (HTStream*)calloc(sizeof(*me),1);
    me = (HTStream*)calloc(sizeof(*me), 1);
    if (me == NULL) outofmem(__FILE__, "Save and execute");
    me->isa = &HTFWriter;

    /* Let's find a hash name for this file */
    physical = HTAnchor_physical(request->anchor);
    if ( !physical )
       physical = request->anchor->address;
    if ((fnam = HTFWriter_filename(HTSaveLocallyDir,
				   physical,
				   HTFileSuffix(input_format),
				   1000)) == NULL) {
	HTAlert("Can't find a suitable file name");
	return NULL;
    }

    me->request = request;	/* won't be freed */
    me->fp = fopen (fnam, "w");
    if (!me->fp) {
	HTAlert("Can't open temporary file!");
	free(fnam);
	free(me);
	return NULL;
    }
    StrAllocCopy(me->filename, fnam);

/*	Make command to process file
*/
    me->end_command = (char *)malloc (
			(strlen (param) + 10+ 3*strlen(fnam))
			 * sizeof (char));
    if (me == NULL) outofmem(__FILE__, "SaveAndExecute");

    sprintf (me->end_command, param, fnam, fnam, fnam);

    me->remove_on_close = NO;

    me->announce = NO;
    free (fnam);
    return me;
}
コード例 #12
0
ファイル: HTGuess.c プロジェクト: BackupTheBerlios/texlive
PRIVATE int HTGuess_flush (HTStream * me)
{
    if (!me->transparent) {
	HTResponse * response = me->response;

	/*
	**  First we look for magic tokens and evaluate the contents of the buffer
	**  that we are investigating. 
	*/
	if (me->cnt) {
	    HTTRACE(STREAM_TRACE, "GUESSING.... Result of content analysis: Text=%d%% Newlines=%d%% Ctrl=%d%% High=%d%%\n" _ 
			(int)(100*me->text_cnt/me->cnt + 0.5) _ 
			(int)(100*me->lf_cnt  /me->cnt + 0.5) _ 
			(int)(100*me->ctrl_cnt/me->cnt + 0.5) _ 
			(int)(100*me->high_cnt/me->cnt + 0.5));
	}
	
	if (!me->ctrl_cnt ||
	    me->text_cnt + me->lf_cnt >= 16 * (me->ctrl_cnt + me->high_cnt)) {
	    char *ptr;
	    /* some kind of text */
	    
	    *me->write_ptr = 0;	/* terminate buffer */
	    
	    if (me->high_cnt > 0)
		HTResponse_setContentTransferEncoding(response, WWW_CODING_8BIT);
	    else
		HTResponse_setContentTransferEncoding(response, WWW_CODING_7BIT);
	    
	    if (is_html(me->buffer))
		HTResponse_setFormat(response, HTAtom_for("text/html"));
	    
	    else if (!strncmp(me->buffer, "%!", 2))
		HTResponse_setFormat(response, HTAtom_for("application/postscript"));
	    
	    else if (strstr(me->buffer, "#define") &&
		     strstr(me->buffer, "_width") &&
		     strstr(me->buffer, "_bits"))
		HTResponse_setFormat(response, HTAtom_for("image/x-xbitmap"));
	    
	    else if ((ptr = strstr(me->buffer, "converted with BinHex"))!=NULL)
		HTResponse_setContentTransferEncoding(response, WWW_CODING_MACBINHEX);

	    else if (!strncmp(me->buffer, "begin ", 6))
		HTResponse_setContentTransferEncoding(response, WWW_CODING_BASE64);

	    else
		HTResponse_setFormat(response, WWW_PLAINTEXT);
	}
	else {
	    if (!strncmp(me->buffer, "GIF", 3))
		HTResponse_setFormat(response, WWW_GIF);

	    else if (!strncmp(me->buffer, "\377\330\377\340", 4))
		HTResponse_setFormat(response, WWW_JPEG);

	    else if (!strcmp(me->buffer, "MM"))	/* MM followed by a zero */
		HTResponse_setFormat(response, WWW_TIFF);

 	    else if (!strncmp(me->buffer, "\211PNG\r\n\032\n", 8))
 		HTResponse_setFormat(response, WWW_PNG);

	    else if (!strncmp(me->buffer, ".snd", 4))
		HTResponse_setFormat(response, WWW_AUDIO);

	    else if (!strncmp(me->buffer, "\037\235", 2))
		HTResponse_addEncoding(response, WWW_CODING_COMPRESS);

	    else if (!strncmp(me->buffer, "\037\213", 2))
		HTResponse_addEncoding(response, WWW_CODING_GZIP);

	    else
		HTResponse_setFormat(response, WWW_BINARY);
	}
	
	/*
	**  If we couldn't find any magic tokens then we try and look at the suffix
	**  of the URL file name and use our own bindings to see if that gives any
	**  results.
	*/
	if (HTResponse_format(response) == WWW_UNKNOWN) {
	    HTParentAnchor * anchor = HTRequest_anchor(me->request);
	    char * addr = HTAnchor_physical(anchor);
	    HTTRACE(STREAM_TRACE, "GUESSING.... Hmm - trying local bindings\n");
	    HTBind_getResponseBindings (response, addr);
	}

	/*
	**  If nothing worked then give up and say binary...
	*/
	if (HTResponse_format(response) == WWW_UNKNOWN) {
	    HTTRACE(STREAM_TRACE, "GUESSING.... That's it - I'm giving up!\n");
	    HTResponse_setFormat(response, WWW_BINARY);
	}
		
	HTTRACE(STREAM_TRACE, "Guessed..... Content-Type `%s\'\n" _ HTAtom_name(HTResponse_format(response)));

	/*
	**  Set up the new stream stack with the type we figured out 
	*/
	if ((me->target = HTStreamStack(HTResponse_format(response),
					me->output_format, me->output_stream,
					me->request, NO)) == NULL) {
	    HTTRACE(STREAM_TRACE, "HTGuess..... Can't convert media type\n");
	    me->target = HTErrorStream();
	}
	me->transparent = YES;
	return PUT_BLOCK(me->buffer, me->cnt);
    }
    return HT_OK;
}
コード例 #13
0
ファイル: HTFile.c プロジェクト: BackupTheBerlios/texlive
PRIVATE int FileEvent (SOCKET soc, void * pVoid, HTEventType type)
{
    file_info *file = pVoid;			      /* Specific access information */
    int status = HT_ERROR;
    HTNet * net = file->net;
    HTRequest * request = HTNet_request(net);
    HTParentAnchor * anchor = HTRequest_anchor(request);

    /*
    ** Initiate a new file structure and bind to request structure
    ** This is actually state FILE_BEGIN, but it can't be in the state
    ** machine as we need the structure first.
    */
    if (type == HTEvent_CLOSE) {				      /* Interrupted */
	HTRequest_addError(request, ERR_FATAL, NO, HTERR_INTERRUPTED,
			   NULL, 0, "HTLoadFile");
	FileCleanup(request, HT_INTERRUPTED);
	return HT_OK;
    }


    /* Now jump into the machine. We know the state from the previous run */
    while (1) {
	switch (file->state) {
	case FS_BEGIN:

	    /* We only support safe (GET, HEAD, etc) methods for the moment */
	    if (!HTMethod_isSafe(HTRequest_method(request))) {
		HTRequest_addError(request, ERR_FATAL, NO, HTERR_NOT_ALLOWED,
				   NULL, 0, "HTLoadFile");
		file->state = FS_ERROR;
		break;
	    }

	    /* Check whether we have access to local disk at all */
	    if (HTLib_secure()) {
		HTTRACE(PROT_TRACE, "LoadFile.... No access to local file system\n");
		file->state = FS_TRY_FTP;
		break;
	    }
	    file->local = HTWWWToLocal(HTAnchor_physical(anchor), "",
				       HTRequest_userProfile(request));
	    if (!file->local) {
		file->state = FS_TRY_FTP;
		break;
	    }

	    /* Create a new host object and link it to the net object */
	    {
		HTHost * host = NULL;
		if ((host = HTHost_new("localhost", 0)) == NULL) return HT_ERROR;
		HTNet_setHost(net, host);
		if (HTHost_addNet(host, net) == HT_PENDING) {
		    HTTRACE(PROT_TRACE, "HTLoadFile.. Pending...\n");
		    /* move to the hack state */
		    file->state = FS_PENDING;
		    return HT_OK;
		}
	    }
	    file->state = FS_DO_CN;
	    break;

	case FS_PENDING:
	    /*
	    ** 2000/08/10 JK : This is a funny state. Because of the
	    ** internal libwww stacks, when doing multiple local
	    ** requests (e.g., while using the Robot), we need to ask
	    ** again for the host object. If we had jumped directly to
	    ** the FS_DO_CN state, libwww would have blocked because
	    ** of socket starvation.
	    ** This state is similar to FS_BEGINNING, but just requests 
	    ** the host object. 
	    ** YES. THIS IS AN UGLY HACK!!
	    */
	    {
		HTHost * host = NULL;
		if ((host = HTHost_new("localhost", 0)) == NULL) return HT_ERROR;
		HTNet_setHost(net, host);
		if (HTHost_addNet(host, net) == HT_PENDING) {
		    HTTRACE(PROT_TRACE, "HTLoadFile.. Pending...\n");
		    file->state = FS_PENDING;
		    return HT_OK;
		}
	    }
	    file->state = FS_DO_CN;
	    break;

	case FS_DO_CN:
	    /*
	    ** If we have to do content negotiation then find the object that
	    ** fits best into either what the client has indicated in the
	    ** accept headers or what the client has registered on its own.
	    ** The object chosen can in fact be a directory! However, content
	    ** negotiation only makes sense if we can read the directory!
	    ** We stat the file in order to find the size and to see it if
	    ** exists.
	    */
	    if (HTRequest_negotiation(request) &&
		HTMethod_isSafe(HTRequest_method(request))) {
 		char * conneg = HTMulti(request, file->local,&file->stat_info);
		if (conneg) {
		    HT_FREE(file->local);
		    file->local = conneg;
		    HTAnchor_setPhysical(anchor, conneg);
		    HTTRACE(PROT_TRACE, "Load File... Found `%s\'\n" _ conneg);
		} else {
		    HTTRACE(PROT_TRACE, "Load File... Not found - even tried content negotiation\n");
		    HTRequest_addError(request, ERR_FATAL, NO, HTERR_NOT_FOUND,
				       NULL, 0, "HTLoadFile");
		    file->state = FS_ERROR;
		    break;
		}
	    } else {
		if (HT_STAT(file->local, &file->stat_info) == -1) {
		    HTTRACE(PROT_TRACE, "Load File... Not found `%s\'\n" _ file->local);
		    HTRequest_addError(request, ERR_FATAL, NO, HTERR_NOT_FOUND,
				       NULL, 0, "HTLoadFile");
		    file->state = FS_ERROR;
		    break;
		}
	    }

	    /*
	    ** Check to see if the 'localname' is in fact a directory.
	    ** Note that we can't do a HEAD on a directory
	    */
	    if (((file->stat_info.st_mode) & S_IFMT) == S_IFDIR) {
		if (HTRequest_method(request) == METHOD_GET)
		    file->state = FS_PARSE_DIR;
		else {
		    HTRequest_addError(request, ERR_INFO, NO, HTERR_NO_CONTENT,
				       NULL, 0, "HTLoadFile");
		    file->state = FS_NO_DATA;
		}
		break;
	    }

	    /*
	    ** If empty file then only serve it if it is editable. We also get
	    ** the bindings for the file suffixes in lack of better bindings
	    */
	    {
		BOOL editable = HTEditable(file->local, &file->stat_info);
		if (file_suffix_binding) HTBind_getAnchorBindings(anchor);
		if (editable) HTAnchor_appendAllow(anchor, METHOD_PUT);

		/* Set the file size */
		if (file->stat_info.st_size)
		    HTAnchor_setLength(anchor, file->stat_info.st_size);

		/* Set the file last modified time stamp */
		if (file->stat_info.st_mtime > 0)
		    HTAnchor_setLastModified(anchor, file->stat_info.st_mtime);

		/* Check to see if we can edit it */
		if (!editable && !file->stat_info.st_size) {
		    HTRequest_addError(request, ERR_INFO, NO, HTERR_NO_CONTENT,
				       NULL, 0, "HTLoadFile");
		    file->state = FS_NO_DATA;
		} else {
		    file->state = (HTRequest_method(request)==METHOD_GET) ? 
			FS_NEED_OPEN_FILE : FS_GOT_DATA;
		}
	    }
	    break;

	  case FS_NEED_OPEN_FILE:
	    status = HTFileOpen(net, file->local, HT_FB_RDONLY);
	    if (status == HT_OK) {
		/* 
		** Create the stream pipe FROM the channel to the application.
		** The target for the input stream pipe is set up using the
		** stream stack.
		*/
		{
		    HTStream * rstream = HTStreamStack(HTAnchor_format(anchor),
						       HTRequest_outputFormat(request),
						       HTRequest_outputStream(request),
						       request, YES);
		    HTNet_setReadStream(net, rstream);
		    HTRequest_setOutputConnected(request, YES);
		}

		/*
		** Create the stream pipe TO the channel from the application
		** and hook it up to the request object
		*/
		{
		    HTOutputStream * output = HTNet_getOutput(net, NULL, 0);
		    HTRequest_setInputStream(request, (HTStream *) output);
		}

		/*
		** Set up concurrent read/write if this request isn't the
		** source for a PUT or POST. As source we don't start reading
		** before all destinations are ready. If destination then
		** register the input stream and get ready for read
		*/
		if (HTRequest_isSource(request) && !HTRequest_destinationsReady(request))
		    return HT_OK;
		HTRequest_addError(request, ERR_INFO, NO, HTERR_OK, NULL, 0,
				   "HTLoadFile");
		file->state = FS_NEED_BODY;

		/* If we are _not_ using preemptive mode and we are Unix fd's
		** then return here to get the same effect as when we are
		** connecting to a socket. That way, HTFile acts just like any
		** other protocol module even though we are in fact doing
		** blocking connect
		*/
		if (HTEvent_isCallbacksRegistered()) {
		    if (!HTRequest_preemptive(request)) {
			if (!HTNet_preemptive(net)) {
			    HTTRACE(PROT_TRACE, "HTLoadFile.. Returning\n");
			    HTHost_register(HTNet_host(net), net, HTEvent_READ);
			} else if (!file->timer) {
			    HTTRACE(PROT_TRACE, "HTLoadFile.. Returning\n");
			    file->timer =
				HTTimer_new(NULL, ReturnEvent, file, 1, YES, NO);
			}
			return HT_OK;
		    }
		}
	    } else if (status == HT_WOULD_BLOCK || status == HT_PENDING)
		return HT_OK;
	    else {
		HTRequest_addError(request, ERR_INFO, NO, HTERR_INTERNAL,
				   NULL, 0, "HTLoadFile");
		file->state = FS_ERROR;		       /* Error or interrupt */
	    }
	    break;

	  case FS_NEED_BODY:
	    status = HTHost_read(HTNet_host(net), net);
	    if (status == HT_WOULD_BLOCK)
		return HT_OK;
	    else if (status == HT_LOADED || status == HT_CLOSED) {
		file->state = FS_GOT_DATA;
	    } else {
		HTRequest_addError(request, ERR_INFO, NO, HTERR_FORBIDDEN,
				   NULL, 0, "HTLoadFile");
		file->state = FS_ERROR;
	    }
	    break;

	  case FS_PARSE_DIR:
	    status = HTFile_readDir(request, file);
	    if (status == HT_LOADED)
		file->state = FS_GOT_DATA;
	    else
		file->state = FS_ERROR;
	    break;

	  case FS_TRY_FTP:
	    {
		char *url = HTAnchor_physical(anchor);
		HTAnchor *anchor;
		char *newname = NULL;
		StrAllocCopy(newname, "ftp:");
		if (!strncmp(url, "file:", 5))
		    StrAllocCat(newname, url+5);
		else
		    StrAllocCat(newname, url);
		anchor = HTAnchor_findAddress(newname);
		HTRequest_setAnchor(request, anchor);
		HT_FREE(newname);
		FileCleanup(request, HT_IGNORE);
		return HTLoad(request, YES);
	    }
	    break;

	  case FS_GOT_DATA:
	    FileCleanup(request, HT_LOADED);
	    return HT_OK;
	    break;

	  case FS_NO_DATA:
	    FileCleanup(request, HT_NO_DATA);
	    return HT_OK;
	    break;

	  case FS_RETRY:
	    FileCleanup(request, HT_RETRY);
	    return HT_OK;
	    break;

	  case FS_ERROR:
	    FileCleanup(request, HT_ERROR);
	    return HT_OK;
	    break;
	}
    } /* End of while(1) */
}
コード例 #14
0
ファイル: HTFSave.c プロジェクト: svagionitis/libwww
/*	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();
}
コード例 #15
0
ファイル: HTFile.c プロジェクト: BackupTheBerlios/texlive
/*	HTFile_readDir
**	--------------
**	Reads the directory "path"
**	Returns:
**		HT_ERROR	Error
**		HT_FORBIDDEN	Directory reading not allowed
**		HT_LOADED	Successfully read the directory
*/
PRIVATE int HTFile_readDir (HTRequest * request, file_info *file)
{
#ifdef HAVE_READDIR
    DIR * dp;
    struct stat file_info;
    HTParentAnchor * anchor = HTRequest_anchor(request);
    char *url = HTAnchor_physical(anchor);
    char fullname[HT_MAX_PATH+1];
    char *name;
    HTTRACE(PROT_TRACE, "Reading..... directory\n");
    if (dir_access == HT_DIR_FORBID) {
	HTRequest_addError(request, ERR_FATAL, NO, HTERR_FORBIDDEN,
		   NULL, 0, "HTFile_readDir");
	return HT_FORBIDDEN;
    }
    
    /* Initialize path name for stat() */
    if (*(name = (url+strlen(url)-1)) != '/') {
	char *newurl = NULL;
	StrAllocCopy(newurl, url);
	StrAllocCat(newurl, "/");
	HT_FREE(file->local);
	file->local = HTWWWToLocal(newurl, "", HTRequest_userProfile(request));
	HT_FREE(newurl);
    }
    strcpy(fullname, file->local);
    name = fullname+strlen(fullname);		 /* Point to end of fullname */

    /* Check if access is enabled */
    if (dir_access == HT_DIR_SELECTIVE) {
	strcpy(name, DEFAULT_DIR_FILE);
	if (HT_STAT(fullname, &file_info)) {
	    HTTRACE(PROT_TRACE, "Read dir.... `%s\' not found\n" _ DEFAULT_DIR_FILE);
	    HTRequest_addError(request, ERR_FATAL, NO, HTERR_FORBIDDEN,
		       NULL, 0, "HTFile_readDir");
	    return HT_FORBIDDEN;
	}
    }

    if ((dp = opendir(file->local))) {
	struct dirent * dirbuf;
	HTDir *dir = HTDir_new(request, dir_show, dir_key);
	char datestr[20];
	char sizestr[10];
	HTFileMode mode;
#ifdef HT_REENTRANT
	struct dirent result;				    /* For readdir_r */
#endif

#ifdef HAVE_READDIR_R_2
        while ((dirbuf = (struct dirent *) readdir_r(dp, &result)))
#elif defined(HAVE_READDIR_R_3)
        while (readdir_r(dp, &result, &dirbuf) == 0)
#else
	while ((dirbuf = readdir(dp)))
#endif /* HAVE_READDIR_R_2 */
	{
	    /* Current and parent directories are never shown in list */
#ifdef HAVE_DIRENT_INO
	    if (!dirbuf->d_ino ||
		!strcmp(dirbuf->d_name, ".") || !strcmp(dirbuf->d_name, ".."))
#else
	    if (!strcmp(dirbuf->d_name, ".") || !strcmp(dirbuf->d_name, ".."))
#endif
		continue;

	    /* Make a lstat on the file */
	    strcpy(name, dirbuf->d_name);
	    if (HT_LSTAT(fullname, &file_info)) {
		HTTRACE(PROT_TRACE, "Read dir.... lstat failed: %s\n" _ fullname);
		continue;
	    }

	    /* Convert stat info to fit our setup */
	    if (((mode_t) file_info.st_mode & S_IFMT) == S_IFDIR) {
#ifdef VMS
		char *dot = strstr(name, ".DIR");      /* strip .DIR part... */
		if (dot) *dot = '\0';
#endif /* VMS */
		mode = HT_IS_DIR;
		if (dir_show & HT_DS_SIZE) strcpy(sizestr, "-");
	    } else {
		mode = HT_IS_FILE;
		if (dir_show & HT_DS_SIZE)
		    HTNumToStr(file_info.st_size, sizestr, 10);
	    }
	    if (dir_show & HT_DS_DATE)
		HTDateDirStr(&file_info.st_mtime, datestr, 20);

	    /* Add to the list */
	    if (HTDir_addElement(dir, name, datestr, sizestr, mode) != YES)
		break;
	}
	closedir(dp);
	HTDir_free(dir);
	return HT_LOADED;
    } else {
	HTRequest_addSystemError(request,  ERR_FATAL, errno, NO, "opendir");
	return HT_ERROR;
    }
#else
    return HT_ERROR;	/* needed for WWW_MSWINDOWS */
#endif /* HAVE_READDIR */
}
コード例 #16
0
ファイル: HTTPReq.c プロジェクト: Hiroyuki-Nagata/libwww
/*	HTTPMakeRequest
**	---------------
**	Makes a HTTP/1.0-1.1 request header.
*/
PRIVATE int HTTPMakeRequest (HTStream * me, HTRequest * request)
{
    HTMethod method = HTRequest_method(request);
    HTRqHd request_mask = HTRequest_rqHd(request);
    HTParentAnchor * anchor = HTRequest_anchor(request);
    char * etag = HTAnchor_etag(anchor);
    char crlf[3];
    char qstr[10];
    *crlf = CR; *(crlf+1) = LF; *(crlf+2) = '\0';

    /* Generate the HTTP/1.x RequestLine */
    if (me->state == 0) {
	if (method != METHOD_INVALID) {
	    PUTS(HTMethod_name(method));
	    PUTC(' ');
	} else
	    PUTS("GET ");
	me->state++;
    }

    /*
    **  Generate the Request URI. If we are using full request URI then it's
    **  easy. Otherwise we must filter out the path part of the URI.
    **  In case it's a OPTIONS request then if there is no pathinfo then use
    **  a * instead. If we use a method different from GET or HEAD then use
    **  the content-location if available.
    */
    if (me->state == 1) {
	char * abs_location = NULL;
	char * addr = HTAnchor_physical(anchor);
	char * location;

        /* JK: If the application specified a content-location (which is
           stored in the request in default put-name!), we use it instead
           of the URL that's being saved to. This is like having a user
           defined Content-Location */
        location = HTRequest_defaultPutName (request);
        if (location)
	  {
	    if (HTURL_isAbsolute (location))
	      {
		char * relative;
		relative = HTRelative (location, location);
		abs_location = HTParse (relative + 2, addr, PARSE_ALL);
		HT_FREE (relative);
	      }
	    else
	      abs_location = HTParse (location, addr, PARSE_ALL);
	    addr = abs_location;
	  }

#if 0
	/*
	**  We don't use the content-location any more as it is superseeded
	**  by etags and the combination of the two might do more harm than
	**  good (The etag is not guaranteed to be unique over multiple URIs)
	*/

	/*
	**  If we are using a method different from HEAD and GET then use
	**  the Content-Location if available, else the Request-URI.
	*/
	if (!HTMethod_isSafe(method)) {
	    char * location = HTAnchor_location(anchor);
	    if (location) {
		if (HTURL_isAbsolute(location))
		    addr = location;
		else {
		    /*
		    **  We have a content-location but it is relative and
		    **  must expand it either to the content-base or to
		    **  the Request-URI itself.
		    */
		    char * base = HTAnchor_base(anchor);
		    abs_location = HTParse(location, base, PARSE_ALL);
		    addr = abs_location;
		}
	    }
	}
#endif

	/*
	**  If we are using a proxy or newer versions of HTTP then we can
	**  send the full URL. Otherwise we only send the path.
	*/
	if (HTRequest_fullURI(request))
	    StrAllocCopy(me->url, addr);
	else {
	    me->url = HTParse(addr, "", PARSE_PATH | PARSE_PUNCTUATION);
	    if (method == METHOD_OPTIONS) {
		/*
		** We don't preserve the final slash or lack of same through
		** out the code. This is mainly for optimization reasons
		** but it gives a problem OPTIONS. We can either send a "*"
		** or a "/" but not both. For now we send a "*".
		*/
		if (!strcmp(me->url, "/")) *me->url = '*';
	    }
	}
	HT_FREE(abs_location);
	me->state++;
    }

    /*
    **  Now send the URL that we have put together
    */
    if (me->state == 2) {
	int status = HT_OK;
	if ((status = PUTS(me->url)) != HT_OK) return status;
	me->state++;

#if 0
	fprintf(stderr, "Requesting '%s'\n", me->url);
#endif

    }
    PUTC(' ');

    /*
    **  Send out the version number. If we know it is a HTTP/1.0 server we
    **  are talking to then use HTTP/1.0, else use HTTP/1.1 as default version
    **  number
    */
    if (me->version == HTTP_10)
	PUTS(HTTP_VERSION_10);
    else
	PUTS(HTTP_VERSION);
    PUTBLOCK(crlf, 2);

    /* Request Headers */
    if (request_mask & HT_C_ACCEPT_TYPE) {
	HTFormat format = HTRequest_outputFormat(request);
	
	/*
	** If caller has specified a specific output format then use this.
	** Otherwise use all the registered converters to generate the 
	** accept header
	*/
	if (format == WWW_PRESENT) {
	    int list;
	    HTList *cur;
	    BOOL first=YES;
	    for (list=0; list<2; list++) {
		if ((!list && ((cur = HTFormat_conversion()) != NULL)) ||
		    (list && ((cur = HTRequest_conversion(request))!=NULL))) {
		    HTPresentation * pres;
		    while ((pres=(HTPresentation *) HTList_nextObject(cur))) {
			if (pres->rep_out==WWW_PRESENT && pres->quality<=1.0) {
			    if (first) {
				PUTS("Accept: ");
				first=NO;
			    } else
				PUTC(',');
			    PUTS(HTAtom_name(pres->rep));
			    if (pres->quality < 1.0 && pres->quality >= 0.0) {
				sprintf(qstr, ";q=%1.1f", pres->quality);
				PUTS(qstr);
			    }
			}
		    }
		}
	    }
	    if (!first) PUTBLOCK(crlf, 2);
	} else {

	    /*
	    **  If we have an explicit output format then only send
	    **  this one if not this is an internal libwww format
	    **	of type www/<star>
	    */
	    if (!HTMIMEMatch(WWW_INTERNAL, format)) {
		PUTS("Accept: ");
		PUTS(HTAtom_name(format));
		PUTBLOCK(crlf, 2);
	    }
	}	
    }
    if (request_mask & HT_C_ACCEPT_CHAR) {
	int list;
	HTList *cur;
	BOOL first=YES;
	for (list=0; list<2; list++) {
	    if ((!list && ((cur = HTFormat_charset()) != NULL)) ||
		(list && ((cur = HTRequest_charset(request)) != NULL))) {
		HTAcceptNode *pres;
		while ((pres = (HTAcceptNode *) HTList_nextObject(cur))) {
		    if (first) {
			PUTS("Accept-Charset: ");
			first=NO;
		    } else
			PUTC(',');
		    PUTS(HTAtom_name(pres->atom));
		    if (pres->quality < 1.0 && pres->quality >= 0.0) {
			sprintf(qstr, ";q=%1.1f", pres->quality);
			PUTS(qstr);
		    }
		}
	    }
	}
	if (!first) PUTBLOCK(crlf, 2);
    }
    if (request_mask & HT_C_ACCEPT_ENC) {
	int list;
	HTList *cur;
	BOOL first=YES;
	for (list=0; list<2; list++) {
	    if ((!list && ((cur = HTFormat_contentCoding()) != NULL)) ||
		(list && ((cur = HTRequest_encoding(request)) != NULL))) {
		HTCoding * pres;
		while ((pres = (HTCoding *) HTList_nextObject(cur))) {
		    double quality = HTCoding_quality(pres);
		    if (first) {
			PUTS("Accept-Encoding: ");
			first = NO;
		    } else
			PUTC(',');
		    PUTS(HTCoding_name(pres));
		    if (quality < 1.0 && quality >= 0.0) {
			sprintf(qstr, ";q=%1.1f", quality);
			PUTS(qstr);
		    }
		}
	    }
	}
	if (!first) PUTBLOCK(crlf, 2);
    }
    if (request_mask & HT_C_ACCEPT_TE) {
	int list;
	HTList *cur;
	BOOL first=YES;
	for (list=0; list<2; list++) {
	    if ((!list && ((cur = HTFormat_transferCoding()) != NULL)) ||
		(list && ((cur = HTRequest_transfer(request)) != NULL))) {
		HTCoding * pres;
		while ((pres = (HTCoding *) HTList_nextObject(cur))) {
		    double quality = HTCoding_quality(pres);
		    const char * coding = HTCoding_name(pres);
		    if (first) {
			PUTS("TE: ");
			first = NO;
		    } else
			PUTC(',');

		    /* Special check for "chunked" which is translated to "trailers" */
		    if (!strcasecomp(coding, "chunked"))
			PUTS("trailers");
		    else
			PUTS(coding);
		    if (quality < 1.0 && quality >= 0.0) {
			sprintf(qstr, ";q=%1.1f", quality);
			PUTS(qstr);
		    }
		}
	    }
	}
	if (!first) PUTBLOCK(crlf, 2);
    }
    if (request_mask & HT_C_ACCEPT_LAN) {
	int list;
	HTList *cur;
	BOOL first=YES;
	for (list=0; list<2; list++) {
	    if ((!list && ((cur = HTFormat_language()) != NULL)) ||
		(list && ((cur = HTRequest_language(request)) != NULL))) {
		HTAcceptNode *pres;
		while ((pres = (HTAcceptNode *) HTList_nextObject(cur))) {
		    if (first) {
			PUTS("Accept-Language: ");
			first=NO;
		    } else
			PUTC(',');
		    PUTS(HTAtom_name(pres->atom));
		    if (pres->quality < 1.0 && pres->quality >= 0.0) {
			sprintf(qstr, ";q=%1.1f", pres->quality);
			PUTS(qstr);
		    }
		}
	    }
	}
	if (!first) PUTBLOCK(crlf, 2);
    }
    if (request_mask & HT_C_AUTH) {
	HTAssocList * cur = HTRequest_credentials(request);
	if (cur) {				    /* Access authentication */
	    HTAssoc * pres;
	    while ((pres = (HTAssoc *) HTAssocList_nextObject(cur))) {
		PUTS(HTAssoc_name(pres));
		PUTS(": ");
		PUTS(HTAssoc_value(pres));
		PUTBLOCK(crlf, 2);
	    }
	}
    }
    if (request_mask & HT_C_EXPECT) {
	HTAssocList * cur = HTRequest_expect(request);
	if (cur) {
	    BOOL first=YES;
	    HTAssoc * pres;
	    while ((pres = (HTAssoc *) HTAssocList_nextObject(cur))) {
		char * value = HTAssoc_value(pres);
		if (first) {
		    PUTS("Expect: ");
		    first = NO;
		} else
		    PUTC(',');

		/* Output the name */
		PUTS(HTAssoc_name(pres));

		/* Only output the value if not empty string */
		if (*value) {
		    PUTS("=");
		    PUTS(value);
		}
	    }
	    PUTBLOCK(crlf, 2);
	}
    }
    if (request_mask & HT_C_FROM) {
	HTUserProfile * up = HTRequest_userProfile(request);
	const char * mailaddress = HTUserProfile_email(up);
	if (mailaddress) {
	    PUTS("From: ");
	    PUTS(mailaddress);
	    PUTBLOCK(crlf, 2);
	}
    }
    if (request_mask & HT_C_HOST) {
	char *orig = HTAnchor_address((HTAnchor *) anchor);
	char *host = HTParse(orig, "", PARSE_HOST);
	char hostace[256];
#if 0
	/* Keep the port number for HTTP/1.1 compliance */
	char *ptr = strchr(host, ':');		     /* Chop off port number */
	if (ptr) *ptr = '\0';
#endif
        PUTS("Host: ");
    /****** still have to check UTF8toACE with port number */
    if (!HTACEfromUTF8 (host, hostace, 255)) {
	    PUTS(hostace);
	}
	else {
	    PUTS(host); /* this may be dangerous, but helps server side debugging */
        HTTRACE(PROT_TRACE, "HTTP........ Error: Cannot convert to ACE: `%s\'\n" _ host);
	}
	PUTBLOCK(crlf, 2);
	HT_FREE(orig);
	HT_FREE(host);
    }

    /*
    **  In the "If-*" series of headers, the ones related to etags have higher
    **  priority than the date relates ones. That is, if we have a etag then
    **  use that, otherwise use the date. First we check for range, match, and
    **  unmodified-since.
    */
    if (request_mask & HT_C_IF_RANGE && etag) {
	PUTS("If-Range: \"");
	PUTS(etag);
	PUTC('"');
	PUTBLOCK(crlf, 2);
	HTTRACE(PROT_TRACE, "HTTP........ If-Range using etag `%s\'\n" _ etag);
    } else if (request_mask & HT_C_IF_MATCH_ANY) {
	PUTS("If-Match: *");
	PUTBLOCK(crlf, 2);
	HTTRACE(PROT_TRACE, "HTTP........ If-Match using `*\'\n");
    } else if (request_mask & HT_C_IF_MATCH && etag) {
	PUTS("If-Match: \"");
	PUTS(etag);
	PUTC('"');
	PUTBLOCK(crlf, 2);
	HTTRACE(PROT_TRACE, "HTTP........ If-Match using etag `%s\'\n" _ etag);
    } else if (request_mask & HT_C_IF_UNMOD_SINCE) {
	time_t lm = HTAnchor_lastModified(anchor);
	if (lm > 0) {
	    PUTS("If-Unmodified-Since: ");
	    PUTS(HTDateTimeStr(&lm, NO));
	    PUTBLOCK(crlf, 2);
	    HTTRACE(PROT_TRACE, "HTTP........ If-Unmodified-Since `%s\'\n" _ HTDateTimeStr(&lm, NO));
	}
    }

    /*
    **  If-None-Match and If-Modified-Since are equivalent except that the
    **  first uses etags and the second uses dates. Etags have precedence over
    **  dates.
    */
    if (request_mask & HT_C_IF_NONE_MATCH_ANY) {
	PUTS("If-None-Match: *");
	PUTBLOCK(crlf, 2);
	HTTRACE(PROT_TRACE, "HTTP........ If-None-Match using `*\'\n");
    } else if (request_mask & HT_C_IF_NONE_MATCH && etag) {
	PUTS("If-None-Match: \"");
	PUTS(etag);
	PUTC('"');
	PUTBLOCK(crlf, 2);
	HTTRACE(PROT_TRACE, "HTTP........ If-None-Match `%s\'\n" _ etag);
    }
    if (request_mask & HT_C_IMS) {
	time_t lm = HTAnchor_lastModified(anchor);
	if (lm > 0) {
	    PUTS("If-Modified-Since: ");
	    PUTS(HTDateTimeStr(&lm, NO));
	    PUTBLOCK(crlf, 2);
	    HTTRACE(PROT_TRACE, "HTTP........ If-Modified-Since `%s\'\n" _ HTDateTimeStr(&lm, NO));
	}
    }

    /*
    **  Max forwards is mainly for TRACE where we want to be able to stop the
    **  TRACE at a specific location un the message path.
    */
    if (request_mask & HT_C_MAX_FORWARDS) {
	int hops = HTRequest_maxForwards(request);
	if (hops >= 0) {
	    sprintf(qstr, "%d", hops);
	    PUTS("Max-Forwards: ");
	    PUTS(qstr);
	    PUTBLOCK(crlf, 2);
	}
    }

    /*
    **  Range requests. For now, we only take the first entry registered for
    **  this request. This means that you can only send a single "unit" and
    **  then a set of range within this unit. This is in accordance with 
    **  HTTP/1.1. Multiple units will go on multiple lines.
    */
    if (request_mask & HT_C_RANGE) {
	HTAssocList * cur = HTRequest_range(request);
	if (cur) {				    	   /* Range requests */
	    HTAssoc * pres;
	    while ((pres = (HTAssoc *) HTAssocList_nextObject(cur))) {
		PUTS("Range: ");
		PUTS(HTAssoc_name(pres));			     /* Unit */
		PUTS("=");
		PUTS(HTAssoc_value(pres));	  /* Ranges within this unit */
		PUTBLOCK(crlf, 2);
	    }
	}
    }
    if (request_mask & HT_C_REFERER) {
	HTParentAnchor * parent_anchor = HTRequest_parent(request);
	if (parent_anchor) {
	    char * act = HTAnchor_address((HTAnchor *) anchor);
	    char * parent = HTAnchor_address((HTAnchor *) parent_anchor);
#if 1
	    char * relative = HTRelative(parent, act);
#else
	    char * relative = HTParse(parent, act,
				      PARSE_ACCESS|PARSE_HOST|PARSE_PATH|PARSE_PUNCTUATION);
#endif
	    if (relative && *relative) {
		PUTS("Referer: ");
		PUTS(relative);
		PUTBLOCK(crlf, 2);
	    }
	    HT_FREE(act);
	    HT_FREE(parent);
	    HT_FREE(relative);
	}
    }
    if (request_mask & HT_C_USER_AGENT) {
	PUTS("User-Agent: ");
	PUTS(HTLib_appName());
	PUTC('/');
	PUTS(HTLib_appVersion());
	PUTC(' ');
	PUTS(HTLib_name());
	PUTC('/');
	PUTS(HTLib_version());
	PUTBLOCK(crlf, 2);
    }
    HTTRACE(PROT_TRACE, "HTTP........ Generating HTTP/1.x Request Headers\n");
    return HT_OK;
}
コード例 #17
0
ファイル: HTNews.c プロジェクト: ChatanW/WebDaM
PRIVATE int NewsEvent (SOCKET soc, void * pVoid, HTEventType type)
{
    news_info *news = (news_info *)pVoid;
    int status = HT_ERROR;
    HTNet * net = news->net;
    HTRequest * request = HTNet_request(net);
    HTParentAnchor * anchor = HTRequest_anchor(request);
    char * url = HTAnchor_physical(anchor);
    HTHost * host = HTNet_host(net);
    
    /*
    ** Initiate a new nntp structure and bind to request structure
    ** This is actually state NNTP_BEGIN, but it can't be in the state
    ** machine as we need the structure first.
    */
    if (type == HTEvent_CLOSE) {			      /* Interrupted */
	HTRequest_addError(request, ERR_FATAL, NO, HTERR_INTERRUPTED,
			   NULL, 0, "HTLoadHTTP");
	HTNewsCleanup(request, HT_INTERRUPTED);
	return HT_OK;
    } else
	news = (news_info *) HTNet_context(net);		/* Get existing copy */

    /* Now jump into the machine. We know the state from the previous run */
    while (1) {
        switch (news->state) {
          case NEWS_BEGIN:
	    news->state = (!strchr(url, '@') && strchr(url, '*')) ?
		NEWS_SEEK_CACHE : NEWS_NEED_CONNECTION;
	    break;

	case NEWS_SEEK_CACHE:
	    if (HTNewsCache_before(request, NULL, 0) == HT_LOADED)
		news->state = NEWS_SUCCESS;
	    else
		news->state = NEWS_NEED_CONNECTION;
	    break;

	  case NEWS_NEED_CONNECTION: 		/* Let's set up a connection */
	    if (!strncasecomp(url, "news:", 5)) {
		HTUserProfile * up = HTRequest_userProfile(request);
		char * newshost = HTUserProfile_news(up);
		StrAllocCopy(news->name, url+5);
		if (newshost) {
		    char *newshack = NULL;    /* Then we can use HTParse :-) */
		    StrAllocCopy(newshack, "news://");
		    StrAllocCat(newshack, newshost);
		    status = HTHost_connect(host, net, (char *) newshack);
		    host = HTNet_host(net);
		    HT_FREE(newshack);
		} else
		    news->state = NEWS_ERROR;
	    } else if (!strncasecomp(url, "nntp:", 5)) {
		news->name = HTParse(url, "", PARSE_PATH);
		status = HTHost_connect(host, net, url);
		host = HTNet_host(net);
	    } else {
		HTTRACE(PROT_TRACE, "News........ Huh?");
		news->state = NEWS_ERROR;
            }
            if (status == HT_OK) {
		BOOL greeting = NO;

		/* Set up the persistent connection */
		if (!HTNet_persistent(net)) {
		    HTNet_setPersistent(net, YES, HT_TP_SINGLE);
		    greeting = YES;
		}

		/*
		** Check the protocol class to see if we have connected to a
		** the right class of server, in this case HTTP.
		*/
		{
		    HTHost * host = HTNet_host(net);
		    char * s_class = HTHost_class(host);
		    if (s_class && strcasecomp(s_class, "nntp")) {
			HTRequest_addError(request, ERR_FATAL, NO, HTERR_CLASS,
					   NULL, 0, "HTLoadNews");
			news->state = NEWS_ERROR;
			break;
		    }
		    HTHost_setClass(host, "nntp");
		}

		/* 
		** Create the stream pipe FROM the channel to the application.
		** The target for the input stream pipe is set up using the
		** stream stack.
		*/
		{
		    HTStream * rstream = HTNewsStatus_new(request, news, host);
		    HTNet_setReadStream(net, rstream);
		    HTRequest_setOutputConnected(request, YES);
		}

		/*
		** Create the stream pipe TO the channel from the application
		** and hook it up to the request object
		*/
		{
		    HTOutputStream * output = HTNet_getOutput(net, NULL, 0);
		    HTRequest_setInputStream(request, (HTStream *) output);
		}

		news->state = greeting ? NEWS_NEED_GREETING : NEWS_NEED_SWITCH;

	    } else if (status == HT_WOULD_BLOCK || status == HT_PENDING)
		return HT_OK;
	    else
		news->state = NEWS_ERROR;
	    break;

	  case NEWS_NEED_GREETING:
	    status = HTHost_read(HTNet_host(net), net);
	    if (status == HT_WOULD_BLOCK)
		return HT_OK;
	    else if (status == HT_LOADED) {
		if (news->repcode/100 == 2)
		    news->state = NEWS_NEED_SWITCH;
		else
		    news->state = NEWS_ERROR;
	    } else
		news->state = NEWS_ERROR;
	    break;

	  case NEWS_NEED_SWITCH:
	  {
	      HTMethod method = HTRequest_method(request);
	      /*
	      ** Find out what to ask the news server. Syntax of address is
	      **	xxx@yyy		Article
	      **	<xxx@yyy>	Same article
	      **	xxxxx		News group (no "@")
	      */
	      if (method == METHOD_GET) {
		  if (strchr(url, '@')) {				  /* ARTICLE */
		      if (*(news->name) != '<') {		  /* Add '<' and '>' */
			  char *newart;
			  if ((newart = (char  *) HT_MALLOC(strlen(news->name)+3)) == NULL)
			      HT_OUTOFMEM("HTLoadNews");
			  sprintf(newart, "<%s>", news->name);
			  HT_FREE(news->name);
			  news->name = newart;
		      }
		      news->state = NEWS_NEED_ARTICLE;
		  } else if (strchr(url, '*'))
		      news->state = NEWS_NEED_LIST;
		  else
		      news->state = NEWS_NEED_GROUP;
	      } else if (method == METHOD_POST)
		  news->state = NEWS_NEED_POST;
	      else {
		  HTRequest_addError(request, ERR_FATAL, NO,
				     HTERR_NOT_IMPLEMENTED,NULL, 0,"HTLoadNews");
		  news->state = NEWS_ERROR;
	      }
	      HTUnEscape(news->name);
	      HTCleanTelnetString(news->name);
	  }
	  break;

	  case NEWS_NEED_ARTICLE:
	    if (!news->sent) {
		status = SendCommand(request, news, "ARTICLE", news->name);
		if (status == HT_WOULD_BLOCK)
		    return HT_OK;
		else if (status == HT_ERROR)
		    news->state = NEWS_ERROR;
		news->format = WWW_MIME;

		/*
		** Set the default content type to plain text as news servers
		** almost never send any useful information about the length
		** of the body or the type - the success of MIME!
		*/
		HTAnchor_setFormat(anchor, WWW_PLAINTEXT);
		news->sent = YES;
	    } else {
		status = HTHost_read(HTNet_host(net), net);
		if (status == HT_WOULD_BLOCK)
		    return HT_OK;
		else if (status == HT_OK)
		    news->state = NEWS_NEED_BODY;
		else if (status == HT_LOADED) {
		    news->state = (news->repcode/100 == 2) ?
			NEWS_SUCCESS : NEWS_ERROR;
		} else
		    news->state = NEWS_ERROR;
		news->sent = NO;
	    }
	    break;

#if HT_LISTGROUP
	  case NEWS_NEED_LGRP:
	    if (!news->sent) {
		status = SendCommand(request, news, "LIST", "NEWSGROUPS");
		if (status == HT_WOULD_BLOCK)
		    return HT_OK;
		else if (status == HT_ERROR)
		    news->state = NEWS_ERROR;
 		news->format = WWW_NNTP_LIST;
		news->sent = YES;
	    } else {
		status = HTHost_read(HTNet_host(net), net);
		if (status == HT_WOULD_BLOCK)
		    return HT_OK;
		else if (status == HT_OK)
		    news->state = NEWS_NEED_BODY;
		else if (status == HT_LOADED) {
		    news->state = (news->repcode/100 == 2) ?
			NEWS_SUCCESS : NEWS_NEED_LIST;
		} else
		    news->state = NEWS_ERROR;
		news->sent = NO;
	    }
	    break;
#endif /* HT_LISTGROUP */

	  case NEWS_NEED_LIST:
	    if (!news->sent) {
		status = SendCommand(request, news, "LIST", NULL);
		if (status == HT_WOULD_BLOCK)
		    return HT_OK;
		else if (status == HT_ERROR)
		    news->state = NEWS_ERROR;
		news->format = WWW_NNTP_LIST;
		news->sent = YES;
	    } else {
		status = HTHost_read(HTNet_host(net), net);
		if (status == HT_WOULD_BLOCK)
		    return HT_OK;
		else if (status == HT_OK)
		    news->state = NEWS_NEED_BODY;
		else if (status == HT_LOADED) {
		    news->state = (news->repcode/100 == 2) ?
			NEWS_SUCCESS : NEWS_ERROR;
		} else
		    news->state = NEWS_ERROR;
		news->sent = NO;
	    }
	    break;

	  case NEWS_NEED_GROUP:
	    if (!news->sent) {
		status = SendCommand(request, news, "GROUP", news->name);
		if (status == HT_WOULD_BLOCK)
		    return HT_OK;
		else if (status == HT_ERROR)
		    news->state = NEWS_ERROR;
		news->sent = YES;
	    } else {
		status = HTHost_read(HTNet_host(net), net);
		if (status == HT_WOULD_BLOCK)
		    return HT_OK;
		else if (status == HT_LOADED) {
		    if (news->repcode/100 == 2) {
			if (sscanf(news->reply, "%d%d%d", &news->total,
				   &news->first, &news->last) == 3) {
			    if (MaxArt && news->total>MaxArt)
				news->last = news->first-MaxArt;
			    news->current = news->first;

			    /* If no content in this group */
			    if (news->first == news->last) {
				HTRequest_addError(request, ERR_FATAL, NO,
						   HTERR_NO_CONTENT,
						   NULL, 0, "HTLoadNews");
				news->state = NEWS_NO_DATA;
				break;
			    }
			    news->state = NEWS_NEED_XOVER;
			} else
			    news->state = NEWS_ERROR;
		    } else
			news->state = NEWS_ERROR;
		} else
		    news->state = NEWS_ERROR;
		news->sent = NO;
	    }
	    break;

	  case NEWS_NEED_XOVER:
	    if (!news->sent) {
		char buf[20];
		sprintf(buf, "%d-%d", news->first, news->last);
		status = SendCommand(request, news, "XOVER", buf);
		if (status == HT_WOULD_BLOCK)
		    return HT_OK;
		else if (status == HT_ERROR)
		    news->state = NEWS_ERROR;
		news->format = WWW_NNTP_OVER;
		news->sent = YES;
	    } else {
		status = HTHost_read(HTNet_host(net), net);
		if (status == HT_WOULD_BLOCK)
		    return HT_OK;
		else if (status == HT_OK)
		    news->state = NEWS_NEED_BODY;
		else if (status == HT_LOADED) {
		    if (news->repcode/100 == 2)
			news->state = NEWS_SUCCESS;
		    else {
			news->format = WWW_NNTP_HEAD;
			news->state = NEWS_NEED_HEAD;
		    }
		} else
		    news->state = NEWS_ERROR;
		news->sent = NO;
	    }
	    break;

	  case NEWS_NEED_HEAD:
	    if (!news->sent) {
		char buf[10];
		sprintf(buf, "%d", news->current++);
		status = SendCommand(request, news, "HEAD", buf);
		if (status == HT_WOULD_BLOCK)
		    return HT_OK;
		else if (status == HT_ERROR)
		    news->state = NEWS_ERROR;
		news->sent = YES;
	    } else {
		status = HTHost_read(HTNet_host(net), net);
		if (status == HT_WOULD_BLOCK)
		    return HT_OK;
		else if (status == HT_LOADED) {
		    if (news->repcode/100 == 2) {
			if (news->current > news->last)
			    news->state = NEWS_SUCCESS;
		    } else
			news->state = NEWS_ERROR;
		} else
		    news->state = NEWS_ERROR;
		news->sent = NO;
	    }
	    break;

	  case NEWS_NEED_POST:
	  {
	      HTStream * oldinput = HTRequest_inputStream(request);
	      HTStream * newinput =
		  HTNewsPost_new(request, HTBuffer_new(oldinput, request,512));
	      HTRequest_setInputStream(request, newinput);
	      
	      /* Remember to convert to CRLF */

	  }
	  news->state = NEWS_NEED_BODY;
	  break;

          case NEWS_NEED_BODY:
            if (type == HTEvent_WRITE || type == HTEvent_BEGIN) {
		if (HTRequest_isDestination(request)) {
		    HTRequest * source = HTRequest_source(request);
		    HTNet * srcnet = HTRequest_net(source);
		    if (srcnet) {
			HTHost_register(HTNet_host(srcnet), srcnet, HTEvent_READ);
			HTHost_unregister(HTNet_host(srcnet), srcnet, HTEvent_WRITE);
		    }
		    return HT_OK;
		}

		/*
		**  Should we use the input stream directly or call the post
		**  callback function to send data down to the network?
		*/
		{
		    HTStream * input = HTRequest_inputStream(request);
		    HTPostCallback * pcbf = HTRequest_postCallback(request);
		    if (pcbf) {
			status = pcbf(request, input);
			if (status == HT_PAUSE || status == HT_LOADED)
			    type = HTEvent_READ;
		    } else {
			status = (*input->isa->flush)(input);
			type = HTEvent_READ;
		    }
		    if (status == HT_WOULD_BLOCK) return HT_OK;
		}
		status = request->PostCallback ?
                    request->PostCallback(request, request->input_stream) :
			(*request->input_stream->isa->flush)(request->input_stream);
 		if (status == HT_WOULD_BLOCK)
                    return HT_OK;
                else 	
                    type = HTEvent_READ;	  /* Trick to ensure that we do READ */
	    } else if (type == HTEvent_READ) {
                status = HTHost_read(HTNet_host(net), net);
		if (status == HT_WOULD_BLOCK)
		    return HT_OK;
                else if (status == HT_LOADED)
		    news->state = NEWS_SUCCESS;
		else
		    news->state = NEWS_ERROR;
	    } else {
		news->state = NEWS_ERROR;
	    }
	    break;
		
	  case NEWS_SUCCESS:
	    HTNewsCleanup(request, HT_LOADED);
	    return HT_OK;
	    break;

	case NEWS_NO_DATA:
	    HTNewsCleanup(request, HT_NO_DATA);
	    return HT_OK;
	    break;

	  case NEWS_ERROR:
	    HTNewsCleanup(request, HT_NOT_FOUND);
	    return HT_OK;
	    break;
	}
    } /* End of while(1) */
}