1 | /* |
---|
2 | * handler.c -- URL handler support |
---|
3 | * |
---|
4 | * Copyright (c) Go Ahead Software Inc., 1995-1999. 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 | |
---|
22 | static websUrlHandlerType* websUrlHandler; /* URL handler list */ |
---|
23 | static int websUrlHandlerMax; /* Number of entries */ |
---|
24 | |
---|
25 | /**************************** Forward Declarations ****************************/ |
---|
26 | |
---|
27 | static int websUrlHandlerSort(const void* p1, const void* p2); |
---|
28 | static int websPublishHandler(webs_t wp, char_t *urlPrefix, char_t *webDir, |
---|
29 | int sid, char_t *url, char_t *path, char_t *query); |
---|
30 | |
---|
31 | /*********************************** Code *************************************/ |
---|
32 | /* |
---|
33 | * Initialize the URL handler module |
---|
34 | */ |
---|
35 | |
---|
36 | int websUrlHandlerOpen() |
---|
37 | { |
---|
38 | websAspOpen(); |
---|
39 | return 0; |
---|
40 | } |
---|
41 | |
---|
42 | /******************************************************************************/ |
---|
43 | /* |
---|
44 | * Close the URL handler module |
---|
45 | */ |
---|
46 | |
---|
47 | void websUrlHandlerClose() |
---|
48 | { |
---|
49 | websUrlHandlerType* sp; |
---|
50 | |
---|
51 | websAspClose(); |
---|
52 | for (sp = websUrlHandler; sp < &websUrlHandler[websUrlHandlerMax]; sp++) { |
---|
53 | bfree(B_L, sp->urlPrefix); |
---|
54 | if (sp->webDir) { |
---|
55 | bfree(B_L, sp->webDir); |
---|
56 | } |
---|
57 | } |
---|
58 | bfree(B_L, websUrlHandler); |
---|
59 | websUrlHandlerMax = 0; |
---|
60 | } |
---|
61 | |
---|
62 | /******************************************************************************/ |
---|
63 | /* |
---|
64 | * Define a new URL handler. urlPrefix is the URL prefix to match. webDir is |
---|
65 | * an optional root directory path for a web directory. arg is an optional |
---|
66 | * arg to pass to the URL handler. flags defines the matching order. Valid |
---|
67 | * flags include WEBS_HANDLER_LAST, WEBS_HANDLER_FIRST. If multiple users |
---|
68 | * specify last or first, their order is defined alphabetically by the |
---|
69 | * urlPrefix. |
---|
70 | */ |
---|
71 | |
---|
72 | int websUrlHandlerDefine(char_t *urlPrefix, char_t *webDir, int arg, |
---|
73 | int (*handler)(webs_t wp, char_t *urlPrefix, char_t *webdir, int arg, |
---|
74 | char_t *url, char_t *path, char_t *query), int flags) |
---|
75 | { |
---|
76 | websUrlHandlerType *sp; |
---|
77 | int len; |
---|
78 | |
---|
79 | a_assert(urlPrefix); |
---|
80 | a_assert(handler); |
---|
81 | |
---|
82 | /* |
---|
83 | * Grow the URL handler array to create a new slot |
---|
84 | */ |
---|
85 | len = (websUrlHandlerMax + 1) * sizeof(websUrlHandlerType); |
---|
86 | if ((websUrlHandler = brealloc(B_L, websUrlHandler, len)) == NULL) { |
---|
87 | return -1; |
---|
88 | } |
---|
89 | sp = &websUrlHandler[websUrlHandlerMax++]; |
---|
90 | memset(sp, 0, sizeof(websUrlHandlerType)); |
---|
91 | |
---|
92 | sp->urlPrefix = bstrdup(B_L, urlPrefix); |
---|
93 | sp->len = gstrlen(sp->urlPrefix); |
---|
94 | if (webDir) { |
---|
95 | sp->webDir = bstrdup(B_L, webDir); |
---|
96 | } else { |
---|
97 | sp->webDir = bstrdup(B_L, T("")); |
---|
98 | } |
---|
99 | sp->handler = handler; |
---|
100 | sp->arg = arg; |
---|
101 | sp->flags = flags; |
---|
102 | |
---|
103 | /* |
---|
104 | * Sort in decreasing URL length order observing the flags for first and last |
---|
105 | */ |
---|
106 | qsort(websUrlHandler, websUrlHandlerMax, sizeof(websUrlHandlerType), |
---|
107 | websUrlHandlerSort); |
---|
108 | return 0; |
---|
109 | } |
---|
110 | |
---|
111 | /******************************************************************************/ |
---|
112 | /* |
---|
113 | * Delete an existing URL handler. We don't reclaim the space of the old |
---|
114 | * handler, just NULL the entry. Return -1 if handler is not found. |
---|
115 | */ |
---|
116 | |
---|
117 | int websUrlHandlerDelete(int (*handler)(webs_t wp, char_t *urlPrefix, |
---|
118 | char_t *webDir, int arg, char_t *url, char_t *path, char_t *query)) |
---|
119 | { |
---|
120 | websUrlHandlerType *sp; |
---|
121 | int i; |
---|
122 | |
---|
123 | for (i = 0; i < websUrlHandlerMax; i++) { |
---|
124 | sp = &websUrlHandler[i]; |
---|
125 | if (sp->handler == handler) { |
---|
126 | sp->handler = NULL; |
---|
127 | return 0; |
---|
128 | } |
---|
129 | } |
---|
130 | return -1; |
---|
131 | } |
---|
132 | |
---|
133 | /******************************************************************************/ |
---|
134 | /* |
---|
135 | * Sort in decreasing URL length order observing the flags for first and last |
---|
136 | */ |
---|
137 | |
---|
138 | static int websUrlHandlerSort(const void* p1, const void* p2) |
---|
139 | { |
---|
140 | websUrlHandlerType *s1, *s2; |
---|
141 | int rc; |
---|
142 | |
---|
143 | a_assert(p1); |
---|
144 | a_assert(p2); |
---|
145 | |
---|
146 | s1 = (websUrlHandlerType*) p1; |
---|
147 | s2 = (websUrlHandlerType*) p2; |
---|
148 | |
---|
149 | if ((s1->flags & WEBS_HANDLER_FIRST) || (s2->flags & WEBS_HANDLER_LAST)) { |
---|
150 | return -1; |
---|
151 | } |
---|
152 | |
---|
153 | if ((s2->flags & WEBS_HANDLER_FIRST) || (s1->flags & WEBS_HANDLER_LAST)) { |
---|
154 | return 1; |
---|
155 | } |
---|
156 | |
---|
157 | if ((rc = gstrcmp(s1->urlPrefix, s2->urlPrefix)) == 0) { |
---|
158 | if (s1->len < s2->len) { |
---|
159 | return 1; |
---|
160 | } else if (s1->len > s2->len) { |
---|
161 | return -1; |
---|
162 | } |
---|
163 | } |
---|
164 | return -rc; |
---|
165 | } |
---|
166 | |
---|
167 | /******************************************************************************/ |
---|
168 | /* |
---|
169 | * Publish a new web directory (Use the default URL handler) |
---|
170 | */ |
---|
171 | |
---|
172 | int websPublish(char_t *urlPrefix, char_t *path) |
---|
173 | { |
---|
174 | return websUrlHandlerDefine(urlPrefix, path, 0, websPublishHandler, 0); |
---|
175 | } |
---|
176 | |
---|
177 | /******************************************************************************/ |
---|
178 | /* |
---|
179 | * Return the directory for a given prefix. Ignore empty prefixes |
---|
180 | */ |
---|
181 | |
---|
182 | char_t *websGetPublishDir(char_t *path, char_t **urlPrefix) |
---|
183 | { |
---|
184 | websUrlHandlerType *sp; |
---|
185 | int i; |
---|
186 | |
---|
187 | for (i = 0; i < websUrlHandlerMax; i++) { |
---|
188 | sp = &websUrlHandler[i]; |
---|
189 | if (sp->urlPrefix[0] == '\0') { |
---|
190 | continue; |
---|
191 | } |
---|
192 | if (sp->handler && gstrncmp(sp->urlPrefix, path, sp->len) == 0) { |
---|
193 | if (urlPrefix) { |
---|
194 | *urlPrefix = sp->urlPrefix; |
---|
195 | } |
---|
196 | return sp->webDir; |
---|
197 | } |
---|
198 | } |
---|
199 | return NULL; |
---|
200 | } |
---|
201 | |
---|
202 | /******************************************************************************/ |
---|
203 | /* |
---|
204 | * Publish URL handler. We just patch the web page Directory and let the |
---|
205 | * default handler do the rest. |
---|
206 | */ |
---|
207 | |
---|
208 | static int websPublishHandler(webs_t wp, char_t *urlPrefix, char_t *webDir, |
---|
209 | int sid, char_t *url, char_t *path, char_t *query) |
---|
210 | { |
---|
211 | int len; |
---|
212 | |
---|
213 | a_assert(websValid(wp)); |
---|
214 | a_assert(path); |
---|
215 | |
---|
216 | /* |
---|
217 | * Trim the urlPrefix off the path and set the webdirectory. Add one to step |
---|
218 | * over the trailing '/' |
---|
219 | */ |
---|
220 | len = gstrlen(urlPrefix) + 1; |
---|
221 | websSetRequestPath(wp, webDir, &path[len]); |
---|
222 | return 0; |
---|
223 | } |
---|
224 | |
---|
225 | /******************************************************************************/ |
---|
226 | /* |
---|
227 | * See if any valid handlers are defined for this request. If so, call them |
---|
228 | * and continue calling valid handlers until one accepts the request. |
---|
229 | * Return true if a handler was invoked, else return FALSE. |
---|
230 | */ |
---|
231 | |
---|
232 | int websUrlHandlerRequest(webs_t wp) |
---|
233 | { |
---|
234 | websUrlHandlerType *sp; |
---|
235 | int i, first; |
---|
236 | |
---|
237 | a_assert(websValid(wp)); |
---|
238 | |
---|
239 | /* |
---|
240 | * Delete the socket handler as we don't want to start reading any |
---|
241 | * data on the connection as it may be for the next pipelined HTTP/1.1 |
---|
242 | * request if using Keep Alive |
---|
243 | */ |
---|
244 | socketDeleteHandler(wp->sid); |
---|
245 | wp->state = WEBS_PROCESSING; |
---|
246 | websStats.handlerHits++; |
---|
247 | |
---|
248 | websSetRequestPath(wp, websGetDefaultDir(), NULL); |
---|
249 | |
---|
250 | /* |
---|
251 | * We loop over each handler in order till one accepts the request. |
---|
252 | * The security handler will handle the request if access is NOT allowed. |
---|
253 | */ |
---|
254 | first = 1; |
---|
255 | for (i = 0; i < websUrlHandlerMax; i++) { |
---|
256 | sp = &websUrlHandler[i]; |
---|
257 | if (sp->handler && gstrncmp(sp->urlPrefix, wp->path, sp->len) == 0) { |
---|
258 | if (first) { |
---|
259 | websSetEnv(wp); |
---|
260 | first = 0; |
---|
261 | } |
---|
262 | if ((*sp->handler)(wp, sp->urlPrefix, sp->webDir, sp->arg, |
---|
263 | wp->url, wp->path, wp->query)) { |
---|
264 | return 1; |
---|
265 | } |
---|
266 | if (!websValid(wp)) { |
---|
267 | goahead_trace(0, |
---|
268 | T("webs: handler %s called websDone, but didn't return 1\n"), |
---|
269 | sp->urlPrefix); |
---|
270 | return 1; |
---|
271 | } |
---|
272 | } |
---|
273 | } |
---|
274 | /* |
---|
275 | * If no handler processed the request, then return an error. Note: It was |
---|
276 | * the handlers responsibility to call websDone |
---|
277 | */ |
---|
278 | if (i >= websUrlHandlerMax) { |
---|
279 | websError(wp, 200, T("No handler for this URL %s"), wp->url); |
---|
280 | } |
---|
281 | return 0; |
---|
282 | } |
---|
283 | |
---|
284 | /******************************************************************************/ |
---|