source: rtems/cpukit/httpd/default.c @ f22ebf0

4.104.114.84.95
Last change on this file since f22ebf0 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: 9.2 KB
Line 
1/*
2 * default.c -- Default URL handler. Includes support for ASP.
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 * $Id$
9 */
10
11/******************************** Description *********************************/
12
13/*
14 *      This module provides default URL handling and Active Server Page support.
15 *
16 *      In many cases we don't check the return code of calls to websWrite as
17 *      it is easier, smaller and non-fatal to continue even when the requesting
18 *      browser has gone away.
19 */
20
21/********************************* Includes ***********************************/
22
23#include        "wsIntrn.h"
24
25/*********************************** Locals ***********************************/
26
27static char_t   *websDefaultPage;                       /* Default page name */
28static char_t   *websDefaultDir;                        /* Default Web page directory */
29
30/**************************** Forward Declarations ****************************/
31
32static void websDefaultWriteEvent(webs_t wp);
33
34/*********************************** Code *************************************/
35/*
36 *      Process a default URL request. This will validate the URL and handle "../"
37 *      and will provide support for Active Server Pages. As the handler is the
38 *      last handler to run, it always indicates that it has handled the URL
39 *      by returning 1.
40 */
41
42int websDefaultHandler(webs_t wp, char_t *urlPrefix, char_t *webDir, int arg,
43                                                char_t *url, char_t *path, char_t *query)
44{
45        websStatType    sbuf;
46        char_t                  *lpath, *tmp, *date;
47        int                             bytes, flags, nchars;
48
49        a_assert(websValid(wp));
50        a_assert(url && *url);
51        a_assert(path);
52        a_assert(query);
53
54/*
55 *      Validate the URL and ensure that ".."s don't give access to unwanted files
56 */
57        flags = websGetRequestFlags(wp);
58
59        if (websValidateUrl(wp, path) < 0) {
60                websError(wp, 500, T("Invalid URL %s"), url);
61                return 1;
62        }
63        lpath = websGetRequestLpath(wp);
64        nchars = gstrlen(lpath) - 1;
65        if (lpath[nchars] == '/' || lpath[nchars] == '\\') {
66                lpath[nchars] = '\0';
67        }
68
69/*
70 *      If the file is a directory, redirect using the nominated default page
71 */
72        if (websPageIsDirectory(lpath)) {
73                nchars = gstrlen(path);
74                if (path[nchars-1] == '/' || path[nchars-1] == '\\') {
75                        path[--nchars] = '\0';
76                }
77                nchars += gstrlen(websDefaultPage) + 2;
78                fmtAlloc(&tmp, nchars, T("%s/%s"), path, websDefaultPage);
79                websRedirect(wp, tmp);
80                bfreeSafe(B_L, tmp);
81                return 1;
82        }
83
84/*
85 *      Open the document. Stat for later use.
86 */
87        if (websPageOpen(wp, lpath, path, SOCKET_RDONLY | SOCKET_BINARY,
88                                0666) < 0) {
89                        websError(wp, 400,
90                                T("Cannot open URL <b>%s</b>"), url);
91                        return 1;
92                }
93                if (websPageStat(wp, lpath, path, &sbuf) < 0) {
94                        websError(wp, 400, T("Cannot stat page for URL <b>%s</b>"),
95                                url);
96                        return 1;
97                }
98
99/*
100 *      If the page has not been modified since the user last received it and it
101 *      is not dynamically generated each time (ASP), then optimize request by
102 *      sending a 304 Use local copy response
103 */
104        websStats.localHits++;
105#if WEBS_IF_MODIFIED_SUPPORT
106        if (flags & WEBS_IF_MODIFIED && !(flags & WEBS_ASP)) {
107                if (sbuf.mtime <= wp->since) {
108                        websWrite(wp, T("HTTP/1.0 304 Use local copy\r\n"));
109
110/*
111 *                      by license terms the following line of code must
112 *                      not be modified.
113 */
114                        websWrite(wp, T("Server: %s\r\n"), WEBS_NAME);
115
116                        if (flags & WEBS_KEEP_ALIVE) {
117                                websWrite(wp, T("Connection: keep-alive\r\n"));
118                        }
119                        websWrite(wp, T("\r\n"));
120                        websSetRequestFlags(wp, flags |= WEBS_HEADER_DONE);
121                        websDone(wp, 304);
122                        return 1;
123                }
124        }
125#endif
126
127/*
128 *      Output the normal HTTP response header
129 */
130        if ((date = websGetDateString(NULL)) != NULL) {
131                websWrite(wp, T("HTTP/1.0 200 OK\r\nDate: %s\r\n"), date);
132
133/*
134 *              By license terms the following line of code must not be modified.
135 */
136                websWrite(wp, T("Server: %s\r\n"), WEBS_NAME);
137                bfree(B_L, date);
138        }
139        flags |= WEBS_HEADER_DONE;
140
141/*
142 *      If this is an ASP request, ensure the remote browser doesn't cache it.
143 *      Send back both HTTP/1.0 and HTTP/1.1 cache control directives
144 */
145        if (flags & WEBS_ASP) {
146                bytes = 0;
147                websWrite(wp, T("Pragma: no-cache\r\nCache-Control: no-cache\r\n"));
148
149        } else {
150                if ((date = websGetDateString(&sbuf)) != NULL) {
151                        websWrite(wp, T("Last-modified: %s\r\n"), date);
152                        bfree(B_L, date);
153                }
154                bytes = sbuf.size;
155        }
156
157        if (bytes) {
158                websWrite(wp, T("Content-length: %d\r\n"), bytes);
159                websSetRequestBytes(wp, bytes);
160        }
161        websWrite(wp, T("Content-type: %s\r\n"), websGetRequestType(wp));
162
163        if ((flags & WEBS_KEEP_ALIVE) && !(flags & WEBS_ASP)) {
164                websWrite(wp, T("Connection: keep-alive\r\n"));
165        }
166        websWrite(wp, T("\r\n"));
167
168/*
169 *      All done if the browser did a HEAD request
170 */
171        if (flags & WEBS_HEAD_REQUEST) {
172                websDone(wp, 200);
173                return 1;
174        }
175
176/*
177 *      Evaluate ASP requests
178 */
179        if (flags & WEBS_ASP) {
180                if (websAspRequest(wp, lpath) < 0) {
181                        return 1;
182                }
183                websDone(wp, 200);
184                return 1;
185        }
186
187#ifdef WEBS_SSL_SUPPORT
188        if (wp->flags & WEBS_SECURE) {
189                websDefaultWriteEvent(wp);
190        } else {
191                websSetRequestSocketHandler(wp, SOCKET_WRITABLE, websDefaultWriteEvent);
192        }
193#else
194/*
195 *      For normal web documents, return the data via background write
196 */
197        websSetRequestSocketHandler(wp, SOCKET_WRITABLE, websDefaultWriteEvent);
198#endif
199        return 1;
200}
201
202/******************************************************************************/
203/*
204 *      Validate the URL path and process ".." path segments. Return -1 if the URL
205 *      is bad.
206 */
207
208int websValidateUrl(webs_t wp, char_t *path)
209{
210        char_t  *parts[64];                                     /* Array of ptr's to URL parts */
211        char_t  *token, *dir, *lpath;
212        int             i, len, npart;
213
214        a_assert(websValid(wp));
215        a_assert(path);
216
217        dir = websGetRequestDir(wp);
218        if (dir == NULL || *dir == '\0') {
219                return -1;
220        }
221
222/*
223 *      Copy the string so we don't destroy the original
224 */
225        path = bstrdup(B_L, path);
226        websDecodeUrl(path, path, gstrlen(path));
227
228        len = npart = 0;
229        parts[0] = NULL;
230        token = gstrtok(path, T("/"));
231
232/*
233 *      Look at each directory segment and process "." and ".." segments
234 *      Don't allow the browser to pop outside the root web.
235 */
236        while (token != NULL) {
237                if (gstrcmp(token, T("..")) == 0) {
238                        if (npart > 0) {
239                                npart--;
240                        }
241
242                } else if (gstrcmp(token, T(".")) != 0) {
243                        parts[npart] = token;
244                        len += gstrlen(token) + 1;
245                        npart++;
246                }
247                token = gstrtok(NULL, T("/"));
248        }
249
250/*
251 *      Create local path for document. Need extra space all "/" and null.
252 */
253        if (npart || (gstrcmp(path, T("/")) == 0) || (path[0] == '\0')) {
254                lpath = balloc(B_L, (gstrlen(dir) + 1 + len + 1) * sizeof(char_t));
255                gstrcpy(lpath, dir);
256
257                for (i = 0; i < npart; i++) {
258                        gstrcat(lpath, T("/"));
259                        gstrcat(lpath, parts[i]);
260                }
261                websSetRequestLpath(wp, lpath);
262                bfree(B_L, path);
263                bfree(B_L, lpath);
264
265        } else {
266                bfree(B_L, path);
267                return -1;
268        }
269        return 0;
270}
271
272/******************************************************************************/
273/*
274 *      Do output back to the browser in the background. This is a socket
275 *      write handler.
276 */
277
278static void websDefaultWriteEvent(webs_t wp)
279{
280        int             len, wrote, flags, bytes, written;
281        char    *buf;
282
283        a_assert(websValid(wp));
284
285        flags = websGetRequestFlags(wp);
286
287        websMarkTime(wp);
288
289        wrote = bytes = 0;
290        written = websGetRequestWritten(wp);
291
292/*
293 *      We only do this for non-ASP documents
294 */
295        if ( !(flags & WEBS_ASP)) {
296                bytes = websGetRequestBytes(wp);
297/*
298 *              Note: websWriteDataNonBlock may return less than we wanted. It will
299 *              return -1 on a socket error
300 */
301                if ((buf = balloc(B_L, PAGE_READ_BUFSIZE)) == NULL) {
302                        websError(wp, 200, T("Can't get memory"));
303                }
304                else {
305                        while ((len = websPageReadData(wp, buf, PAGE_READ_BUFSIZE)) > 0) {
306                                if ((wrote = websWriteDataNonBlock(wp, buf, len)) < 0) {
307                                        break;
308                                }
309                                written += wrote;
310                                if (wrote != len) {
311                                        websPageSeek(wp, - (len - wrote));
312                                        break;
313                                }
314                        }
315/*
316 *                      Safety. If we are at EOF, we must be done
317 */
318                        if (len == 0) {
319                                a_assert(written >= bytes);
320                                written = bytes;
321                        }
322                        bfree(B_L, buf);
323                }
324        }
325
326/*
327 *      We're done if an error, or all bytes output
328 */
329        websSetRequestWritten(wp, written);
330        if (wrote < 0 || written >= bytes) {
331                websDone(wp, 200);
332        }
333}
334
335/******************************************************************************/
336/*
337 *      Closing down. Free resources.
338 */
339
340void websDefaultClose()
341{
342        if (websDefaultPage) {
343                bfree(B_L, websDefaultPage);
344                websDefaultPage = NULL;
345        }
346        if (websDefaultDir) {
347                bfree(B_L, websDefaultDir);
348                websDefaultDir = NULL;
349        }
350}
351
352/******************************************************************************/
353/*
354 *      Get the default page for URL requests ending in "/"
355 */
356
357char_t *websGetDefaultPage()
358{
359        return websDefaultPage;
360}
361
362/******************************************************************************/
363/*
364 *      Get the default web directory
365 */
366
367char_t *websGetDefaultDir()
368{
369        return websDefaultDir;
370}
371
372/******************************************************************************/
373/*
374 *      Set the default page for URL requests ending in "/"
375 */
376
377void websSetDefaultPage(char_t *page)
378{
379        a_assert(page && *page);
380
381        if (websDefaultPage) {
382                bfree(B_L, websDefaultPage);
383        }
384        websDefaultPage = bstrdup(B_L, page);
385}
386
387/******************************************************************************/
388/*
389 *      Set the default web directory
390 */
391
392void websSetDefaultDir(char_t *dir)
393{
394        a_assert(dir && *dir);
395        if (websDefaultDir) {
396                bfree(B_L, websDefaultDir);
397        }
398        websDefaultDir = bstrdup(B_L, dir);
399}
400
401/******************************************************************************/
402
Note: See TracBrowser for help on using the repository browser.