source: rtems/c/src/libnetworking/rtems_webserver/default.c @ c1cdaa0

4.104.114.84.95
Last change on this file since c1cdaa0 was c1cdaa0, checked in by Joel Sherrill <joel.sherrill@…>, on 10/27/99 at 12:50:33

Patch from Emmanuel Raguet <raguet@…> and Eric Valette
<valette@…> to add a port of the GoAhead? web server
(httpd) to the RTEMS build tree. They have successfully used
this BSP on i386/pc386 and PowerPC/mcp750.

Mark and Joel spoke with Nick Berliner <nickb@…> on
26 Oct 1999 about this port and got verbal approval to include
it in RTEMS distributions.

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