source: rtems/cpukit/httpd/handler.c @ c55df85

4.104.114.84.95
Last change on this file since c55df85 was a6b4c0df, checked in by Joel Sherrill <joel.sherrill@…>, on 09/01/00 at 10:57:21

2000-08-30 Joel Sherrill <joel@…>

  • Merged version 2.1 of GoAhead? webserver. This update was submitted by Antti P Miettinen <antti.p.miettinen@…>.
  • NOTES, base64.c, ejIntrn.h, emfdb.c, emfdb.h, md5.h, md5c.c, um.c, um.h: New files.
  • wbase64.c: Removed.
  • Makefile.am, asp.c, balloc.c, default.c, ej.h, ejlex.c, ejparse.c, form.c, h.c, handler.c, mime.c, misc.c, ringq.c, rom.c, security.c, socket.c, sym.c, uemf.c, uemf.h, url.c, value.c, webcomp.c, webmain.c, webpage.c, webrom.c, webs.c, webs.h, websuemf.c, wsIntrn.h: Modified.
  • Property mode set to 100644
File size: 8.9 KB
Line 
1/*
2 * handler.c -- URL handler support
3 *
4 * Copyright (c) GoAhead Software Inc., 1995-2000. All Rights Reserved.
5 *
6 * See the file "license.txt" for usage and redistribution license requirements
7 */
8
9/******************************** Description *********************************/
10
11/*
12 *      This module implements a URL handler interface and API to permit
13 *      the addition of user definable URL processors.
14 */
15
16/********************************* Includes ***********************************/
17
18#include        "wsIntrn.h"
19
20/*********************************** Locals ***********************************/
21
22static websUrlHandlerType       *websUrlHandler;                        /* URL handler list */
23static int                                      websUrlHandlerMax;                      /* Number of entries */
24static int                                      urlHandlerOpenCount = 0;        /* count of apps */
25
26/**************************** Forward Declarations ****************************/
27
28static int      websUrlHandlerSort(const void *p1, const void *p2);
29static int      websPublishHandler(webs_t wp, char_t *urlPrefix, char_t *webDir,
30                                int sid, char_t *url, char_t *path, char_t *query);
31static int      websTidyUrl(webs_t wp);
32
33/*********************************** Code *************************************/
34/*
35 *      Initialize the URL handler module
36 */
37
38int websUrlHandlerOpen()
39{
40        if (++urlHandlerOpenCount == 1) {
41                websAspOpen();
42                websUrlHandler = NULL;
43                websUrlHandlerMax = 0;
44        }
45        return 0;
46}
47
48/******************************************************************************/
49/*
50 *      Close the URL handler module
51 */
52
53void websUrlHandlerClose()
54{
55        websUrlHandlerType *sp;
56
57        if (--urlHandlerOpenCount <= 0) {
58                websAspClose();
59                for (sp = websUrlHandler; sp < &websUrlHandler[websUrlHandlerMax];
60                        sp++) {
61                        bfree(B_L, sp->urlPrefix);
62                        if (sp->webDir) {
63                                bfree(B_L, sp->webDir);
64                        }
65                }
66                bfree(B_L, websUrlHandler);
67                websUrlHandlerMax = 0;
68        }
69}
70
71/******************************************************************************/
72/*
73 *      Define a new URL handler. urlPrefix is the URL prefix to match. webDir is
74 *      an optional root directory path for a web directory. arg is an optional
75 *      arg to pass to the URL handler. flags defines the matching order. Valid
76 *      flags include WEBS_HANDLER_LAST, WEBS_HANDLER_FIRST. If multiple users
77 *      specify last or first, their order is defined alphabetically by the
78 *      urlPrefix.
79 */
80
81int websUrlHandlerDefine(char_t *urlPrefix, char_t *webDir, int arg,
82                int (*handler)(webs_t wp, char_t *urlPrefix, char_t *webdir, int arg,
83                char_t *url, char_t *path, char_t *query), int flags)
84{
85        websUrlHandlerType      *sp;
86        int                                     len;
87
88        a_assert(urlPrefix);
89        a_assert(handler);
90
91/*
92 *      Grow the URL handler array to create a new slot
93 */
94        len = (websUrlHandlerMax + 1) * sizeof(websUrlHandlerType);
95        if ((websUrlHandler = brealloc(B_L, websUrlHandler, len)) == NULL) {
96                return -1;
97        }
98        sp = &websUrlHandler[websUrlHandlerMax++];
99        memset(sp, 0, sizeof(websUrlHandlerType));
100
101        sp->urlPrefix = bstrdup(B_L, urlPrefix);
102        sp->len = gstrlen(sp->urlPrefix);
103        if (webDir) {
104                sp->webDir = bstrdup(B_L, webDir);
105        } else {
106                sp->webDir = bstrdup(B_L, T(""));
107        }
108        sp->handler = handler;
109        sp->arg = arg;
110        sp->flags = flags;
111
112/*
113 *      Sort in decreasing URL length order observing the flags for first and last
114 */
115        qsort(websUrlHandler, websUrlHandlerMax, sizeof(websUrlHandlerType),
116                websUrlHandlerSort);
117        return 0;
118}
119
120/******************************************************************************/
121/*
122 *      Delete an existing URL handler. We don't reclaim the space of the old
123 *      handler, just NULL the entry. Return -1 if handler is not found.
124 */
125
126int websUrlHandlerDelete(int (*handler)(webs_t wp, char_t *urlPrefix,
127        char_t *webDir, int arg, char_t *url, char_t *path, char_t *query))
128{
129        websUrlHandlerType      *sp;
130        int                                     i;
131
132        for (i = 0; i < websUrlHandlerMax; i++) {
133                sp = &websUrlHandler[i];
134                if (sp->handler == handler) {
135                        sp->handler = NULL;
136                        return 0;
137                }
138        }
139        return -1;
140}
141
142/******************************************************************************/
143/*
144 *      Sort in decreasing URL length order observing the flags for first and last
145 */
146
147static int websUrlHandlerSort(const void *p1, const void *p2)
148{
149        websUrlHandlerType      *s1, *s2;
150        int                                     rc;
151
152        a_assert(p1);
153        a_assert(p2);
154
155        s1 = (websUrlHandlerType*) p1;
156        s2 = (websUrlHandlerType*) p2;
157
158        if ((s1->flags & WEBS_HANDLER_FIRST) || (s2->flags & WEBS_HANDLER_LAST)) {
159                return -1;
160        }
161
162        if ((s2->flags & WEBS_HANDLER_FIRST) || (s1->flags & WEBS_HANDLER_LAST)) {
163                return 1;
164        }
165
166        if ((rc = gstrcmp(s1->urlPrefix, s2->urlPrefix)) == 0) {
167                if (s1->len < s2->len) {
168                        return 1;
169                } else if (s1->len > s2->len) {
170                        return -1;
171                }
172        }
173        return -rc;
174}
175
176/******************************************************************************/
177/*
178 *      Publish a new web directory (Use the default URL handler)
179 */
180
181int websPublish(char_t *urlPrefix, char_t *path)
182{
183        return websUrlHandlerDefine(urlPrefix, path, 0, websPublishHandler, 0);
184}
185
186/******************************************************************************/
187/*
188 *      Return the directory for a given prefix. Ignore empty prefixes
189 */
190
191char_t *websGetPublishDir(char_t *path, char_t **urlPrefix)
192{
193        websUrlHandlerType      *sp;
194        int                                     i;
195
196        for (i = 0; i < websUrlHandlerMax; i++) {
197                sp = &websUrlHandler[i];
198                if (sp->urlPrefix[0] == '\0') {
199                        continue;
200                }
201                if (sp->handler && gstrncmp(sp->urlPrefix, path, sp->len) == 0) {
202                        if (urlPrefix) {
203                                *urlPrefix = sp->urlPrefix;
204                        }
205                        return sp->webDir;
206                }
207        }
208        return NULL;
209}
210
211/******************************************************************************/
212/*
213 *      Publish URL handler. We just patch the web page Directory and let the
214 *      default handler do the rest.
215 */
216
217static int websPublishHandler(webs_t wp, char_t *urlPrefix, char_t *webDir,
218        int sid, char_t *url, char_t *path, char_t *query)
219{
220        int             len;
221
222        a_assert(websValid(wp));
223        a_assert(path);
224
225/*
226 *      Trim the urlPrefix off the path and set the webdirectory. Add one to step
227 *      over the trailing '/'
228 */
229        len = gstrlen(urlPrefix) + 1;
230        websSetRequestPath(wp, webDir, &path[len]);
231        return 0;
232}
233
234/******************************************************************************/
235/*
236 *      See if any valid handlers are defined for this request. If so, call them
237 *      and continue calling valid handlers until one accepts the request.
238 *      Return true if a handler was invoked, else return FALSE.
239 */
240
241int websUrlHandlerRequest(webs_t wp)
242{
243        websUrlHandlerType      *sp;
244        int                                     i, first;
245
246        a_assert(websValid(wp));
247
248/*
249 *      Delete the socket handler as we don't want to start reading any
250 *      data on the connection as it may be for the next pipelined HTTP/1.1
251 *      request if using Keep Alive
252 */
253        socketDeleteHandler(wp->sid);
254        wp->state = WEBS_PROCESSING;
255        websStats.handlerHits++;
256       
257        websSetRequestPath(wp, websGetDefaultDir(), NULL);
258
259        websTidyUrl(wp);
260
261/*
262 *      We loop over each handler in order till one accepts the request.
263 *      The security handler will handle the request if access is NOT allowed.
264 */
265        first = 1;
266        for (i = 0; i < websUrlHandlerMax; i++) {
267                sp = &websUrlHandler[i];
268                if (sp->handler && gstrncmp(sp->urlPrefix, wp->path, sp->len) == 0) {
269                        if (first) {
270                                websSetEnv(wp);
271                                first = 0;
272                        }
273                        if ((*sp->handler)(wp, sp->urlPrefix, sp->webDir, sp->arg,
274                                        wp->url, wp->path, wp->query)) {
275                                return 1;
276                        }
277                        if (!websValid(wp)) {
278                                trace(0,
279                                T("webs: handler %s called websDone, but didn't return 1\n"),
280                                        sp->urlPrefix);
281                                return 1;
282                        }
283                }
284        }
285/*
286 *      If no handler processed the request, then return an error. Note: It is
287 *      the handlers responsibility to call websDone
288 */
289        if (i >= websUrlHandlerMax) {
290                websError(wp, 200, T("No handler for this URL %s"), wp->url);
291        }
292        return 0;
293}
294
295
296/******************************************************************************/
297/*
298 *      Tidy up the URL path. Return -1 if the URL is bad.
299 *  Used to eliminate repeated directory delimiters ('/').
300 */
301
302static int websTidyUrl(webs_t wp)
303{
304        char_t  *parts[64];                                     /* Array of ptr's to URL parts */
305        char_t  *token, *url, *tidyurl;
306        int             i, len, npart;
307
308        a_assert(websValid(wp));
309
310/*
311 *      Copy the string so we don't destroy the original (yet)
312 */
313        url = bstrdup(B_L, wp->url);
314        websDecodeUrl(url, url, gstrlen(url));
315
316        len = npart = 0;
317        parts[0] = NULL;
318        token = gstrtok(url, T("/"));
319
320/*
321 *      Look at each directory segment and process "." and ".." segments
322 *      Don't allow the browser to pop outside the root web.
323 */
324        while (token != NULL) {
325                if (gstrcmp(token, T("..")) == 0) {
326                        if (npart > 0) {
327                                npart--;
328                        }
329
330                } else if (gstrcmp(token, T(".")) != 0) {
331                        parts[npart] = token;
332                        len += gstrlen(token) + 1;
333                        npart++;
334                }
335                token = gstrtok(NULL, T("/"));
336        }
337
338/*
339 *      Re-construct URL. Need extra space all "/" and null.
340 */
341        if (npart || (gstrcmp(url, T("/")) == 0) || (url[0] == '\0')) {
342                tidyurl = balloc(B_L, (len + 2) * sizeof(char_t));
343                *tidyurl = '\0';
344
345                for (i = 0; i < npart; i++) {
346                        gstrcat(tidyurl, T("/"));
347                        gstrcat(tidyurl, parts[i]);
348                }
349
350                bfree(B_L, url);
351
352                bfree(B_L, wp->url);
353                wp->url = tidyurl;
354                return 0;
355        } else {
356                bfree(B_L, url);
357                return -1;
358        }
359}
360
361/******************************************************************************/
Note: See TracBrowser for help on using the repository browser.