summaryrefslogtreecommitdiffstats
path: root/cpukit/httpd/default.c
diff options
context:
space:
mode:
authorJoel Sherrill <joel.sherrill@OARcorp.com>1999-10-27 12:50:33 +0000
committerJoel Sherrill <joel.sherrill@OARcorp.com>1999-10-27 12:50:33 +0000
commitc1cdaa0ce8017b075487e6670f89eb4e715258ea (patch)
treed4571a02595d6cf6a24d40d6968d83ece3b7a574 /cpukit/httpd/default.c
parentNew files created by split of old imfs_handlers.c. (diff)
downloadrtems-c1cdaa0ce8017b075487e6670f89eb4e715258ea.tar.bz2
Patch from Emmanuel Raguet <raguet@crf.canon.fr> and Eric Valette
<valette@crf.canon.fr> 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@goahead.com> on 26 Oct 1999 about this port and got verbal approval to include it in RTEMS distributions.
Diffstat (limited to 'cpukit/httpd/default.c')
-rw-r--r--cpukit/httpd/default.c389
1 files changed, 389 insertions, 0 deletions
diff --git a/cpukit/httpd/default.c b/cpukit/httpd/default.c
new file mode 100644
index 0000000000..c485c22285
--- /dev/null
+++ b/cpukit/httpd/default.c
@@ -0,0 +1,389 @@
+/*
+ * default.c -- Default URL handler. Includes support for ASP.
+ *
+ * Copyright (c) Go Ahead Software Inc., 1995-1999. All Rights Reserved.
+ *
+ * See the file "license.txt" for usage and redistribution license requirements
+ */
+
+/******************************** Description *********************************/
+
+/*
+ * This module provides default URL handling and Active Server Page support.
+ *
+ * In many cases we don't check the return code of calls to websWrite as
+ * it is easier, smaller and non-fatal to continue even when the requesting
+ * browser has gone away.
+ */
+
+/********************************* Includes ***********************************/
+
+#include "wsIntrn.h"
+
+/*********************************** Locals ***********************************/
+
+static char_t *websDefaultPage; /* Default page name */
+static char_t *websDefaultDir; /* Default Web page directory */
+
+/**************************** Forward Declarations ****************************/
+
+static void websDefaultWriteEvent(webs_t wp);
+
+/*********************************** Code *************************************/
+/*
+ * Process a default URL request. This will validate the URL and handle "../"
+ * and will provide support for Active Server Pages. As the handler is the
+ * last handler to run, it always indicates that it has handled the URL
+ * by returning 1.
+ */
+
+int websDefaultHandler(webs_t wp, char_t *urlPrefix, char_t *webDir, int arg,
+ char_t *url, char_t *path, char_t* query)
+{
+ websStatType sbuf;
+ char_t *lpath, *tmp;
+ char_t *date;
+ int bytes, flags, nchars;
+
+ a_assert(websValid(wp));
+ a_assert(url && *url);
+ a_assert(path && *path);
+ a_assert(query);
+
+/*
+ * Validate the URL and ensure that ".."s don't give access to unwanted files
+ */
+ flags = websGetRequestFlags(wp);
+
+ if (websValidateUrl(wp, path) < 0) {
+ websError(wp, 500, T("Invalid URL %s"), url);
+ return 1;
+ }
+ lpath = websGetRequestLpath(wp);
+ nchars = gstrlen(lpath) - 1;
+ if (lpath[nchars] == '/' || lpath[nchars] == '\\') {
+ lpath[nchars] = '\0';
+ }
+
+/*
+ * If the file is a directory, redirect using the nominated default page
+ */
+ if (websPageIsDirectory(lpath)) {
+ nchars = gstrlen(path);
+ if (path[nchars-1] == '/' || path[nchars-1] == '\\') {
+ path[--nchars] = '\0';
+ }
+ nchars += gstrlen(websDefaultPage) + 2;
+ tmp = NULL;
+ gsnprintf(&tmp, nchars, T("%s/%s"), path, websDefaultPage);
+ websRedirect(wp, tmp);
+ bfreeSafe(B_L, tmp);
+ return 1;
+ }
+
+/*
+ * Open the document. Stat for later use.
+ */
+ if (websPageOpen(wp, lpath, path, SOCKET_RDONLY | SOCKET_BINARY,
+ 0666) < 0) {
+ websError(wp, 400,
+ T("Can't open document <b>%s</b><br>for URL <b>%s</b>"),
+ lpath, url);
+ return 1;
+ }
+ if (websPageStat(wp, lpath, path, &sbuf) < 0) {
+ websError(wp, 400, T("Can't stat page <b>%s</b><br>for URL <b>%s</b>"),
+ lpath, url);
+ }
+
+/*
+ * If the page has not been modified since the user last received it and it
+ * is not dynamically generated each time (ASP), then optimize request by
+ * sending a 304 Use local copy response
+ */
+ websStats.localHits++;
+#if WEBS_IF_MODIFIED_SUPPORT
+ if (flags & WEBS_IF_MODIFIED && !(flags & WEBS_ASP)) {
+ if (sbuf.mtime <= wp->since) {
+ websWrite(wp, T("HTTP/1.0 304 Use local copy\r\n"));
+
+ /* by license terms the following line of code must
+ * not be modified.
+ */
+ websWrite(wp, T("Server: GoAhead-Webs\r\n"));
+
+ if (flags && WEBS_KEEP_ALIVE) {
+ websWrite(wp, T("Connection: keep-alive\r\n"));
+ }
+ websWrite(wp, T("\r\n"));
+ websSetRequestFlags(wp, flags |= WEBS_HEADER_DONE);
+ websDone(wp, 304);
+ return 1;
+ }
+ }
+#endif
+
+/*
+ * Output the normal HTTP response header
+ */
+ if ((date = websGetDateString(NULL)) != NULL) {
+ websWrite(wp, T("HTTP/1.0 200 OK\r\nDate: %s\r\n"), date);
+
+/*
+ * By license terms the following line of code must not be modified.
+*/
+ websWrite(wp, T("Server: GoAhead-Webs\r\n"));
+ bfree(B_L, date);
+ }
+ flags |= WEBS_HEADER_DONE;
+
+/*
+ * If this is an ASP request, ensure the remote browser doesn't cache it.
+ * Send back both HTTP/1.0 and HTTP/1.1 cache control directives
+ */
+ if (flags & WEBS_ASP) {
+ bytes = 0;
+ websWrite(wp, T("Pragma: no-cache\r\nCache-Control: no-cache\r\n"));
+
+ } else {
+ if ((date = websGetDateString(&sbuf)) != NULL) {
+ websWrite(wp, T("Last-modified: %s\r\n"), date);
+ bfree(B_L, date);
+ }
+ bytes = sbuf.size;
+ }
+
+ if (bytes) {
+ websWrite(wp, T("Content-length: %d\r\n"), bytes);
+ websSetRequestBytes(wp, bytes);
+ }
+ websWrite(wp, T("Content-type: %s\r\n"), websGetRequestType(wp));
+
+ if ((flags & WEBS_KEEP_ALIVE) && !(flags & WEBS_ASP)) {
+ websWrite(wp, T("Connection: keep-alive\r\n"));
+ }
+ websWrite(wp, T("\r\n"));
+
+/*
+ * Evaluate ASP requests
+ */
+ if (flags & WEBS_ASP) {
+ if (websAspRequest(wp, lpath) < 0) {
+ return 1;
+ }
+ websDone(wp, 200);
+ return 1;
+ }
+
+/*
+ * All done if the browser did a HEAD request
+ */
+ if (flags & WEBS_HEAD_REQUEST) {
+ websDone(wp, 200);
+ return 1;
+ }
+/*
+ * For normal web documents, return the data via background write
+ */
+ websSetRequestSocketHandler(wp, SOCKET_WRITABLE, websDefaultWriteEvent);
+ return 1;
+}
+
+/******************************************************************************/
+/*
+ * Validate the URL path and process ".." path segments. Return -1 if the URL
+ * is bad.
+ */
+
+int websValidateUrl(webs_t wp, char_t *path)
+{
+ char_t *parts[64]; /* Array of ptr's to URL parts */
+ char_t *token, *dir, *lpath;
+ int i, len, npart;
+
+ a_assert(websValid(wp));
+ a_assert(path);
+
+ dir = websGetRequestDir(wp);
+ if (dir == NULL || *dir == '\0') {
+ return -1;
+ }
+
+/*
+ * Copy the string so we don't destroy the original
+ */
+ path = bstrdup(B_L, path);
+ websDecodeUrl(path, path, gstrlen(path));
+
+ len = npart = 0;
+ parts[0] = NULL;
+ token = gstrtok(path, 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("/"));
+ }
+
+/*
+ * Create local path for document. Need extra space all "/" and null.
+ */
+ if (npart) {
+ lpath = balloc(B_L, (gstrlen(dir) + 1 + len + 1) * sizeof(char_t));
+ gstrcpy(lpath, dir);
+
+ for (i = 0; i < npart; i++) {
+ gstrcat(lpath, T("/"));
+ gstrcat(lpath, parts[i]);
+ }
+ websSetRequestLpath(wp, lpath);
+ bfree(B_L, path);
+ bfree(B_L, lpath);
+
+ } else {
+ bfree(B_L, path);
+ return -1;
+ }
+ return 0;
+}
+
+/******************************************************************************/
+/*
+ * Do output back to the browser in the background. This is a socket
+ * write handler.
+ */
+
+static void websDefaultWriteEvent(webs_t wp)
+{
+ int len, wrote, flags, bytes, written;
+ char * buf;
+
+ a_assert(websValid(wp));
+
+ flags = websGetRequestFlags(wp);
+
+ wrote = 0;
+ bytes = 0;
+ written = websGetRequestWritten(wp);
+
+/*
+ * We only do this for non-ASP documents
+ */
+ if ( !(flags & WEBS_ASP)) {
+ bytes = websGetRequestBytes(wp);
+/*
+ * Note: websWriteBlock may return less than we wanted. It will return
+ * -1 on a socket error
+ */
+ if ((buf = balloc(B_L, PAGE_READ_BUFSIZE)) == NULL) {
+ websError(wp, 200, T("Can't get memory"));
+ }
+ else {
+ while ((len = websPageReadData(wp, buf, PAGE_READ_BUFSIZE)) > 0) {
+ if ((wrote = websWriteBlockData(wp, buf, len)) < 0) {
+ break;
+ }
+ written += wrote;
+ if (wrote != len) {
+ websPageSeek(wp, - (wrote - len));
+ break;
+ }
+ }
+/*
+ * Safety. If we are at EOF, we must be done
+ */
+ if (len == 0) {
+ a_assert(written >= bytes);
+ written = bytes;
+ }
+ bfree(B_L, buf);
+ }
+ }
+
+/*
+ * We're done if an error, or all bytes output
+ */
+ websSetRequestWritten(wp, written);
+ if (wrote < 0 || written >= bytes) {
+ websDone(wp, 200);
+ }
+}
+
+/******************************************************************************/
+/*
+ * Closing down. Free resources.
+ */
+
+void websDefaultClose()
+{
+ if (websDefaultPage) {
+ bfree(B_L, websDefaultPage);
+ }
+ if (websDefaultDir) {
+ bfree(B_L, websDefaultDir);
+ }
+}
+
+/******************************************************************************/
+/*
+ * Get the default page for URL requests ending in "/"
+ */
+
+char_t *websGetDefaultPage()
+{
+ return websDefaultPage;
+}
+
+/******************************************************************************/
+/*
+ * Get the default web directory
+ */
+
+char_t *websGetDefaultDir()
+{
+ return websDefaultDir;
+}
+
+/******************************************************************************/
+/*
+ * Set the default page for URL requests ending in "/"
+ */
+
+void websSetDefaultPage(char_t *page)
+{
+ a_assert(page && *page);
+
+ if (websDefaultPage) {
+ bfree(B_L, websDefaultPage);
+ }
+ websDefaultPage = bstrdup(B_L, page);
+}
+
+/******************************************************************************/
+/*
+ * Set the default web directory
+ */
+
+void websSetDefaultDir(char_t *dir)
+{
+ a_assert(dir && *dir);
+ if (websDefaultDir) {
+ bfree(B_L, websDefaultDir);
+ }
+ websDefaultDir = bstrdup(B_L, dir);
+}
+
+/******************************************************************************/
+