*** empty log message ***
authorMatthew Mondor <mmondor@pulsar-zone.net>
Sun, 20 Aug 2006 06:47:42 +0000 (06:47 +0000)
committerMatthew Mondor <mmondor@pulsar-zone.net>
Sun, 20 Aug 2006 06:47:42 +0000 (06:47 +0000)
mmsoftware/js/classes/js_fd.c
mmsoftware/js/js-sh/app/httpd/httpd.js

index d42b050..c66a4af 100644 (file)
@@ -1,4 +1,4 @@
-/* $Id: js_fd.c,v 1.5 2006/08/19 11:56:48 mmondor Exp $ */
+/* $Id: js_fd.c,v 1.6 2006/08/20 06:47:42 mmondor Exp $ */
 
 /*
  * Copyright (c) 2005, Matthew Mondor
@@ -453,10 +453,19 @@ static struct property_spec       fd_sprops[] = {
  * Miscelaneous static globals
  */
 
-/* XXX Should be initialized at main process startup ideally */
-static int     tcp_proto = -1;
-static char    *read_charbuf = NULL;
-static size_t  read_charbuf_size = 0;
+static int             tcp_proto = 4;
+
+/*
+ * These would cause problems with reentrancy.  These buffers should be FD
+ * specific to be thread-safe.
+ */
+
+/* Read buffer */
+static char            *read_charbuf = NULL;
+static size_t          read_charbuf_size = 0;
+
+/* Poll buffers */
+static struct poll_fds fds = { NULL, NULL, 0, 0 };
 
 
 
@@ -493,6 +502,14 @@ js_InitFDClass(JSContext *cx, JSObject *obj)
                }
        }
 
+       /* Initialize useful globals for performance */
+       {
+               struct protoent *pent;
+
+               if ((pent = getprotobyname("TCP")) != NULL)
+                       tcp_proto = pent->p_proto;
+       }
+
        return proto;
 }
 
@@ -1164,9 +1181,6 @@ fd_m_shutdown(JSContext *cx, JSObject *obj, uintN argc, jsval *argv,
 }
 
 /*
- * XXX Not thread safe ATM as it uses a static int with test-and-set operation
- * to only query the protocol database once.  This could be done at early
- * process initialization alternatively.
  * Unlike BSD/POSIX setsockopt(2), always requires a single integer value (-1
  * in the case of SO_LINGER to disable it, or the number of seconds to
  * linger to enable it).
@@ -1212,17 +1226,9 @@ fd_m_setsockopt(JSContext *cx, JSObject *obj, uintN argc, jsval *argv,
        /*
         * And for TCP_NODELAY which must use tcp_proto as level
         */
-       if (optname == TCP_NODELAY) {
-               if (tcp_proto == -1) {
-                       struct protoent *pent;
-
-                       if ((pent = getprotobyname("TCP")) != NULL)
-                               tcp_proto = pent->p_proto;
-                       else
-                               tcp_proto = 4;  /* Generally allright */
-               }
+       if (optname == TCP_NODELAY)
                level = tcp_proto;
-       else
+       else
                level = SOL_SOCKET;
 
        if (setsockopt(jsfd->fd, level, optname, opt, optlen) == -1) {
@@ -1235,9 +1241,6 @@ fd_m_setsockopt(JSContext *cx, JSObject *obj, uintN argc, jsval *argv,
 }
 
 /*
- * XXX Not thread safe ATM as it uses a static int with test-and-set operation
- * to only query the protocol database once.  This could be done at early
- * process initialization alternatively.
  * Unlike BSD/POSIX getsockopt(2), always returns a single integer value (-1
  * in the case of SO_LINGER disabled, or the number of seconds assigned to
  * wait if enabled).
@@ -1276,17 +1279,9 @@ fd_m_getsockopt(JSContext *cx, JSObject *obj, uintN argc, jsval *argv,
         * And for TCP_NODELAY which must use TCP protocol number rather than
         * SOL_SOCKET level
         */
-       if (optname == TCP_NODELAY) {
-               if (tcp_proto == -1) {
-                       struct protoent *pent;
-
-                       if ((pent = getprotobyname("TCP")) != NULL)
-                               tcp_proto = pent->p_proto;
-                       else
-                               tcp_proto = 4;  /* Generally allright */
-               }
+       if (optname == TCP_NODELAY)
                level = tcp_proto;
-       else
+       else
                level = SOL_SOCKET;
 
        if (getsockopt(jsfd->fd, level, optname, opt, &optlen) == -1) {
@@ -1370,6 +1365,12 @@ fd_m_fcntl(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval)
        return JS_TRUE;
 }
 
+/*
+ * XXX Not thread-safe as it uses a global read buffer.  To avoid this, read
+ * buffers could be FD object specific instead, although this would not be as
+ * efficient (in case new FD objects are frequently created), and would
+ * require more redundant buffer memory.
+ */
 static JSBool
 fd_m_read(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval)
 {
@@ -1659,10 +1660,14 @@ err:
  * Static methods
  */
 
+/*
+ * XXX Not thread-safe as we are using global buffers.  To avoid this, these
+ * buffers would need to be PollSet object specific and we would need to
+ * provide such an object with FD add/remove methods.
+ */
 static JSBool
 fd_sm_poll(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval)
 {
-       struct poll_fds fds;
        int             nfds, timeout, i;
        JSObject        *array = NULL;
        jsint           index;
@@ -1696,17 +1701,27 @@ fd_sm_poll(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval)
        /*
         * Create our pollfd array, iterating through all FD objects of the
         * user-provided array object.
+        * XXX We ideally should use a buffer which we only need to grow as
+        * necessary, instead of having to reallocate memory every time.
+        * This however would introduce reentrency problems unless we used
+        * this buffer as part of a set object.  We potentially then could
+        * alternatively provide a PollSet object, along with add/remove
+        * methods...
         */
-       if ((fds.entries = malloc(sizeof(struct pollfd) * 16)) == NULL) {
-               QUEUE_EXCEPTION("Out of memory");
-               goto err;
-       }
-       if ((fds.info = malloc(sizeof(struct poll_fdsi) * 16)) == NULL) {
-               QUEUE_EXCEPTION("Out of memory");
-               goto err;
+       if (fds.entries == NULL && fds.info == NULL) {
+               if ((fds.entries = malloc(sizeof(struct pollfd) * 16))
+                   == NULL) {
+                       QUEUE_EXCEPTION("Out of memory");
+                       goto err;
+               }
+               if ((fds.info = malloc(sizeof(struct poll_fdsi) * 16))
+                   == NULL) {
+                       QUEUE_EXCEPTION("Out of memory");
+                       goto err;
+               }
+               fds.size = 16;
        }
        fds.count = 0;
-       fds.size = 16;
        if (!object_iterate(cx, JSVAL_TO_OBJECT(argv[0]), &fds,
            fd_sm_poll_mkset))
                goto err;
@@ -1758,17 +1773,21 @@ fd_sm_poll(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval)
                }
        }
 
+       /* We now use global buffers for performance
        free(fds.entries);
        free(fds.info);
+       */
 
        return JS_TRUE;
 
 err:
        *rval = OBJECT_TO_JSVAL(NULL);
+       /* We now use global buffers for performance
        if (fds.entries != NULL)
                free(fds.entries);
        if (fds.info != NULL)
                free(fds.info);
+        */
 
        return JS_FALSE;
 }
index 2f83084..a331cac 100644 (file)
@@ -1,4 +1,4 @@
-/* $Id: httpd.js,v 1.33 2006/08/20 05:32:28 mmondor Exp $ */
+/* $Id: httpd.js,v 1.34 2006/08/20 06:47:34 mmondor Exp $ */
 
 /*
  * Copyright (c) 2005-2006, Matthew Mondor
@@ -76,7 +76,7 @@
  * Server identification
  */
 const SERVER_VERSION = 'mmondor_js_httpd/0.1.0 (NetBSD)';
-const SERVER_CVSID = '$Id: httpd.js,v 1.33 2006/08/20 05:32:28 mmondor Exp $';
+const SERVER_CVSID = '$Id: httpd.js,v 1.34 2006/08/20 06:47:34 mmondor Exp $';
 
 
 
@@ -940,7 +940,7 @@ FD.prototype.parsePost = function(time)
  */
 FD.prototype.httpRespond = function(time)
 {
-       var path, fd, st, res, ext, mimetype, i, size, appserv_match, error;
+       var path, fd, st, res, ext, mimetype, i, size, appserv_match;
        /*
        var sess;
        */
@@ -956,19 +956,16 @@ FD.prototype.httpRespond = function(time)
                return PSTAT_CLOSE_SUCCESS;
        }
 
-       appserv_match = this.http_vhost.host_appmatch(path.virtual);
-
        /*
         * General strategy:
-        * 1) Verify if path matches appserver, if so ensure that client
-        *    supports cookies, then proceed with the forwarding code.
-        * 2) Attempt to open file, return 404 or 403 on failure.
+        * 1) Verify if path matches appserver.  If not, attempt to open file,
+        *    return 404 or 403 on failure.
         *    On success, if it consists of a directory, apply index path,
         *    match again against appserver paths, close fd and forward to
         *    appserver also if so.  If not, close dir fd and attempt to open
         *    again after applying index.  On failure, return 404 or 403.
-        * 3) If file successfully opened, upload it to client.
-        * 4) If to forward request to appserver, perform the following:
+        * 2) If file successfully opened, upload it to client.
+        * 3) If to forward request to appserver, perform the following:
         *
         * 1) Verify if session cookie provided.  If not, invoke appserver
         *    to create a new session and send new session cookie to client,
@@ -992,20 +989,9 @@ FD.prototype.httpRespond = function(time)
         * must be existing.
         */
 
-       /* XXX Verify if path matches appserver, if so forward request */
+       if (!(appserv_match = this.http_vhost.host_appmatch(path.virtual))) {
 
-       /*
-        * XXX
-        * Attempt to find requested file.
-        * If it consists of a directory, apply index, then match again against
-        * appserver matching, and if necessary attempt again to open file.
-        * If all fails, return 403 error.  If fd open to existing file,
-        * keep it open and continue downwards with the stat info already
-        * filled in.
-        */
-       if (!appserv_match) {
                fd = new FD();
-
                try {
                        fd.open(path.real, FD.O_RDONLY);
                        st = fd.fstat();
@@ -1015,8 +1001,9 @@ FD.prototype.httpRespond = function(time)
                        return PSTAT_CLOSE_SUCCESS;
                }
 
-               if ((st.st_mode & FD.S_IFDIR) != 0) {   /* Directory */
-                       error = false;
+               /* Directory? */
+               if ((st.st_mode & FD.S_IFDIR) != 0) {
+                       var error = false;
 
                        /*
                         * Refit URL to configured index,
@@ -1027,19 +1014,12 @@ FD.prototype.httpRespond = function(time)
                                fd.close();
                        } catch (x) {}
                        if (this.http_vhost.index.charAt(1) == '/') {
-                               /*
-                                * Index points to absolute path, so recompute
-                                * path
-                                */
-                               path = this.http_vhost.htdocs_root.
-                                   valid_virtual(this.http_vhost.index);
-                               if (!path)
+                               /* Recompute since index is fullpath */
+                               if (!(path = this.http_vhost.htdocs_root.
+                                   valid_virtual(this.http_vhost.index)))
                                        error = true;
                        } else {
-                               /*
-                                * We simply need to append the index path and
-                                * retry
-                                */
+                               /* Append index path and retry */
                                path.real += this.http_vhost.index;
                                path.virtual += this.http_vhost.index;
                        }
@@ -1048,13 +1028,10 @@ FD.prototype.httpRespond = function(time)
                         * Verify again if new index matches an appserv path
                         */
                        if (!error) {
-                               appserv_match = this.http_vhost.host_appmatch(
-                                   path.virtual);
+                               if (!(appserv_match = this.http_vhost.
+                                   host_appmatch(path.virtual))) {
 
-                               /*
-                                * Not under appserv, attempt to reopen file
-                                */
-                               if (!appserv_match) {
+                                       /* Attempt to reopen file */
                                        try {
                                                fd.open(path.real,
                                                    FD.O_RDONLY);
@@ -1106,53 +1083,6 @@ FD.prototype.httpRespond = function(time)
                return PSTAT_CLOSE_SUCCESS;
        }
 
-       /*
-        * We now want to verify if the client sent a valid session cookie.
-        * If it didn't, we present it with a page with meta-tag reload
-        * instructions to attempt to reload the originally supplied URL,
-        * and with a new session cookie.
-        * XXX Only necessary if not loading static data, and we need to get
-        * the new SID from the application server.
-        * We don't need to do this unless accessing an appserv handled path.
-        */
-       /*
-       if (this.http_vhost.appserv != undefined &&
-           this.http_sessid == undefined) {
-               var doc, sess;
-
-               doc = new HTTPReply(200, 'OK',
-                   'text/html; charset=' + options.default_charset);
-               doc.addNoCacheHeaders();
-
-               sess = new Session(time,
-                   (this.http_vhost.session_exp != undefined ?
-                   this.http_vhost.session_exp :
-                   options.default_session_exp));
-               sess.variables.count = 0;
-               doc.addHeader('Set-Cookie: SessionID=' + sess.sessid +
-                   '; expires=' +
-                   (new Date(sess.expires * 1000)).toGMTString() +
-                   '; path=/');
-               doc.addContent('<html><head><META HTTP-EQUIV="refresh" ' +
-                   'CONTENT="5; URL=' + path.virtual + '"><title>Cookies' +
-                   '</title></head><body><h1>Cookies</h1><p>We are ' +
-                   ' verifying if your browser supports HTTP cookies.  ' +
-                   'These are required to keep persistent session data ' +
-                   'among your connections.  The destination page should ' +
-                   'load automatically in a few seconds.</p>' +
-                   ' <p>If it doesn\'t, please ensure that HTTP cookies ' +
-                   'are enabled on your HTTP client and are accepted ' +
-                   'from this server.</p>' +
-                   '<p>If the page still does not load properly after a ' +
-                   'few seconds, please click on <a href="' + path.virtual +
-                   '">this link</a>.</p><br><sub>' + SERVER_VERSION +
-                   '<br>' + SERVER_CVSID + '</sub>');
-               doc.flush(this, null);
-
-               return PSTAT_CLOSE_SUCCESS;
-       }
-       */
-
        /* XXX */
        if (appserv_match) {
                http_error(this, 500, 'Internal Server Error',