summaryrefslogblamecommitdiffstats
path: root/c/src/libnetworking/rtems_webserver/handler.c
blob: 88693bf9a6ceedb0eab70440f054f737eb54e821 (plain) (tree)
1
2
3
4


                                   
                                                                       
















                                                                                
                                                                                              
                                                                                                               
                                                                                                   


                                                                                
                                                                   

                                                                                   
                                       







                                                                                




                                         









                                                                                









                                                                                  
                 

                                           
         













































































                                                                                      
                                                             














































































































                                                                                  

                        
















                                                                                     
                                         






                                                                                             
                                                                               







                                                                             

































































                                                                                                 
                                                                                
/*
 * handler.c -- URL handler support
 *
 * Copyright (c) GoAhead Software Inc., 1995-2000. All Rights Reserved.
 *
 * See the file "license.txt" for usage and redistribution license requirements
 */

/******************************** Description *********************************/

/*
 *	This module implements a URL handler interface and API to permit
 *	the addition of user definable URL processors.
 */

/********************************* Includes ***********************************/

#include	"wsIntrn.h"

/*********************************** Locals ***********************************/

static websUrlHandlerType	*websUrlHandler;			/* URL handler list */
static int					websUrlHandlerMax;			/* Number of entries */
static int					urlHandlerOpenCount = 0;	/* count of apps */

/**************************** Forward Declarations ****************************/

static int 	websUrlHandlerSort(const void *p1, const void *p2);
static int 	websPublishHandler(webs_t wp, char_t *urlPrefix, char_t *webDir, 
				int sid, char_t *url, char_t *path, char_t *query);
static int	websTidyUrl(webs_t wp);

/*********************************** Code *************************************/
/*
 *	Initialize the URL handler module
 */

int websUrlHandlerOpen()
{
	if (++urlHandlerOpenCount == 1) {
		websAspOpen();
		websUrlHandler = NULL;
		websUrlHandlerMax = 0;
	}
	return 0;
}

/******************************************************************************/
/*
 *	Close the URL handler module
 */

void websUrlHandlerClose()
{
	websUrlHandlerType *sp;

	if (--urlHandlerOpenCount <= 0) {
		websAspClose();
		for (sp = websUrlHandler; sp < &websUrlHandler[websUrlHandlerMax];
			sp++) {
			bfree(B_L, sp->urlPrefix);
			if (sp->webDir) {
				bfree(B_L, sp->webDir);
			}
		}
		bfree(B_L, websUrlHandler);
		websUrlHandlerMax = 0;
	}
}

/******************************************************************************/
/*
 *	Define a new URL handler. urlPrefix is the URL prefix to match. webDir is 
 *	an optional root directory path for a web directory. arg is an optional
 *	arg to pass to the URL handler. flags defines the matching order. Valid
 *	flags include WEBS_HANDLER_LAST, WEBS_HANDLER_FIRST. If multiple users 
 *	specify last or first, their order is defined alphabetically by the 
 *	urlPrefix.
 */

int websUrlHandlerDefine(char_t *urlPrefix, char_t *webDir, int arg,
		int (*handler)(webs_t wp, char_t *urlPrefix, char_t *webdir, int arg, 
		char_t *url, char_t *path, char_t *query), int flags)
{
	websUrlHandlerType	*sp;
	int					len;

	a_assert(urlPrefix);
	a_assert(handler);

/*
 *	Grow the URL handler array to create a new slot
 */
	len = (websUrlHandlerMax + 1) * sizeof(websUrlHandlerType);
	if ((websUrlHandler = brealloc(B_L, websUrlHandler, len)) == NULL) {
		return -1;
	}
	sp = &websUrlHandler[websUrlHandlerMax++];
	memset(sp, 0, sizeof(websUrlHandlerType));

	sp->urlPrefix = bstrdup(B_L, urlPrefix);
	sp->len = gstrlen(sp->urlPrefix);
	if (webDir) {
		sp->webDir = bstrdup(B_L, webDir);
	} else {
		sp->webDir = bstrdup(B_L, T(""));
	}
	sp->handler = handler;
	sp->arg = arg;
	sp->flags = flags;

/*
 *	Sort in decreasing URL length order observing the flags for first and last
 */
	qsort(websUrlHandler, websUrlHandlerMax, sizeof(websUrlHandlerType), 
		websUrlHandlerSort);
	return 0;
}

/******************************************************************************/
/*
 *	Delete an existing URL handler. We don't reclaim the space of the old 
 *	handler, just NULL the entry. Return -1 if handler is not found.
 */

int websUrlHandlerDelete(int (*handler)(webs_t wp, char_t *urlPrefix, 
	char_t *webDir, int arg, char_t *url, char_t *path, char_t *query))
{
	websUrlHandlerType	*sp;
	int					i;

	for (i = 0; i < websUrlHandlerMax; i++) {
		sp = &websUrlHandler[i];
		if (sp->handler == handler) {
			sp->handler = NULL;
			return 0;
		}
	}
	return -1;
}

/******************************************************************************/
/*
 *	Sort in decreasing URL length order observing the flags for first and last
 */

static int websUrlHandlerSort(const void *p1, const void *p2)
{
	websUrlHandlerType	*s1, *s2;
	int					rc;

	a_assert(p1);
	a_assert(p2);

	s1 = (websUrlHandlerType*) p1;
	s2 = (websUrlHandlerType*) p2;

	if ((s1->flags & WEBS_HANDLER_FIRST) || (s2->flags & WEBS_HANDLER_LAST)) {
		return -1;
	}

	if ((s2->flags & WEBS_HANDLER_FIRST) || (s1->flags & WEBS_HANDLER_LAST)) {
		return 1;
	}

	if ((rc = gstrcmp(s1->urlPrefix, s2->urlPrefix)) == 0) {
		if (s1->len < s2->len) {
			return 1;
		} else if (s1->len > s2->len) {
			return -1;
		}
	}
	return -rc; 
}

/******************************************************************************/
/*
 *	Publish a new web directory (Use the default URL handler)
 */

int websPublish(char_t *urlPrefix, char_t *path)
{
	return websUrlHandlerDefine(urlPrefix, path, 0, websPublishHandler, 0);
}

/******************************************************************************/
/*
 *	Return the directory for a given prefix. Ignore empty prefixes
 */

char_t *websGetPublishDir(char_t *path, char_t **urlPrefix)
{
	websUrlHandlerType	*sp;
	int					i;

	for (i = 0; i < websUrlHandlerMax; i++) {
		sp = &websUrlHandler[i];
		if (sp->urlPrefix[0] == '\0') {
			continue;
		}
		if (sp->handler && gstrncmp(sp->urlPrefix, path, sp->len) == 0) {
			if (urlPrefix) {
				*urlPrefix = sp->urlPrefix;
			}
			return sp->webDir;
		}
	}
	return NULL;
}

/******************************************************************************/
/*
 *	Publish URL handler. We just patch the web page Directory and let the
 *	default handler do the rest.
 */

static int websPublishHandler(webs_t wp, char_t *urlPrefix, char_t *webDir, 
	int sid, char_t *url, char_t *path, char_t *query)
{
	int		len;

	a_assert(websValid(wp));
	a_assert(path);

/*
 *	Trim the urlPrefix off the path and set the webdirectory. Add one to step 
 *	over the trailing '/'
 */
	len = gstrlen(urlPrefix) + 1;
	websSetRequestPath(wp, webDir, &path[len]);
	return 0;
}

/******************************************************************************/
/*
 *	See if any valid handlers are defined for this request. If so, call them
 *	and continue calling valid handlers until one accepts the request. 
 *	Return true if a handler was invoked, else return FALSE.
 */

int websUrlHandlerRequest(webs_t wp)
{
	websUrlHandlerType	*sp;
	int					i, first;

	a_assert(websValid(wp));

/*
 *	Delete the socket handler as we don't want to start reading any
 *	data on the connection as it may be for the next pipelined HTTP/1.1
 *	request if using Keep Alive
 */
	socketDeleteHandler(wp->sid);
	wp->state = WEBS_PROCESSING;
	websStats.handlerHits++;
	
	websSetRequestPath(wp, websGetDefaultDir(), NULL);

	websTidyUrl(wp);

/*
 *	We loop over each handler in order till one accepts the request. 
 *	The security handler will handle the request if access is NOT allowed.
 */
	first = 1;
	for (i = 0; i < websUrlHandlerMax; i++) {
		sp = &websUrlHandler[i];
		if (sp->handler && gstrncmp(sp->urlPrefix, wp->path, sp->len) == 0) {
			if (first) {
				websSetEnv(wp);
				first = 0;
			}
			if ((*sp->handler)(wp, sp->urlPrefix, sp->webDir, sp->arg, 
					wp->url, wp->path, wp->query)) {
				return 1;
			}
			if (!websValid(wp)) {
				trace(0, 
				T("webs: handler %s called websDone, but didn't return 1\n"),
					sp->urlPrefix);
				return 1;
			}
		}
	}
/*
 *	If no handler processed the request, then return an error. Note: It is 
 *	the handlers responsibility to call websDone
 */
	if (i >= websUrlHandlerMax) {
		websError(wp, 200, T("No handler for this URL %s"), wp->url);
	}
	return 0;
}


/******************************************************************************/
/*
 *	Tidy up the URL path. Return -1 if the URL is bad.
 *  Used to eliminate repeated directory delimiters ('/').
 */

static int websTidyUrl(webs_t wp)
{
	char_t	*parts[64];					/* Array of ptr's to URL parts */
	char_t	*token, *url, *tidyurl;
	int		i, len, npart;

	a_assert(websValid(wp));

/*
 *	Copy the string so we don't destroy the original (yet)
 */
	url = bstrdup(B_L, wp->url);
	websDecodeUrl(url, url, gstrlen(url));

	len = npart = 0;
	parts[0] = NULL;
	token = gstrtok(url, T("/"));

/*
 *	Look at each directory segment and process "." and ".." segments
 *	Don't allow the browser to pop outside the root web. 
 */
	while (token != NULL) {
		if (gstrcmp(token, T("..")) == 0) {
			if (npart > 0) {
				npart--;
			}

		} else if (gstrcmp(token, T(".")) != 0) {
			parts[npart] = token;
			len += gstrlen(token) + 1;
			npart++;
		}
		token = gstrtok(NULL, T("/"));
	}

/*
 *	Re-construct URL. Need extra space all "/" and null.
 */
	if (npart || (gstrcmp(url, T("/")) == 0) || (url[0] == '\0')) {
		tidyurl = balloc(B_L, (len + 2) * sizeof(char_t));
		*tidyurl = '\0';

		for (i = 0; i < npart; i++) {
			gstrcat(tidyurl, T("/"));
			gstrcat(tidyurl, parts[i]);
		}

		bfree(B_L, url);

		bfree(B_L, wp->url);
		wp->url = tidyurl;
		return 0;
	} else {
		bfree(B_L, url);
		return -1;
	}
}

/******************************************************************************/