-/* $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
* 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 };
}
}
+ /* Initialize useful globals for performance */
+ {
+ struct protoent *pent;
+
+ if ((pent = getprotobyname("TCP")) != NULL)
+ tcp_proto = pent->p_proto;
+ }
+
return proto;
}
}
/*
- * 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).
/*
* 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) {
}
/*
- * 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).
* 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) {
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)
{
* 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;
/*
* 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;
}
}
+ /* 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;
}
-/* $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
* 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 $';
*/
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;
*/
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,
* 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();
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,
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;
}
* 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);
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',