-/* $Id: httpd.js,v 1.28 2006/08/18 07:49:29 mmondor Exp $ */
+/* $Id: httpd.js,v 1.29 2006/08/19 11:36:57 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.28 2006/08/18 07:49:29 mmondor Exp $';
+const SERVER_CVSID = '$Id: httpd.js,v 1.29 2006/08/19 11:36:57 mmondor Exp $';
/*
- * Quick SID->appserv lookup table
+ * Quick SID->appserv FD lookup table
*/
var sid_table = {};
-/*
- * The SID object.
- * When calling the constructor with a non-null sid, lookup is first made in
- * the SID table to detect such SID with existing connection to an appserv
- * already exists, and if so, returns true. If such a connection doesn't
- * exist, an attempt to connect to an appserv and resume that SID is
- * performed, which on success causes true to be returned, or false on error
- * XXX which should probably redirect to an application-specific URL.
- * If sid is null, an attempt to connect to an appserv and to create a new SID
- * is performed, and on success new SID added into the table and true
- * returned. On error, false is returned (XXX which should also redirect to
- * an application-specific URL).
- * XXX Hrm several problems exist. First, we must first launch the connection
- * attempt but then return, to have a FD.state() function be called whenever
- * connection is established or failed. Then can we only proceed with
- * requests over that socket. Also, wouldn't it make more sense to return an
- * fd or null rather than true or false here?
- */
-function SID(sid)
-{
-}
-
-SID.prototype = {
-};
-
/*
'</sub></body></html>');
res.flush(fd, null);
- delete res;
}
/*
* Reset FD to a consistent known state, to use after accept(2).
- * To be passed current time in seconds since epoch, and unique id to be used
- * as an index.
+ * To be passed current time in seconds since epoch.
*/
-FD.prototype.init = function(time, idx)
+FD.prototype.http_init = function(time)
{
/* For differenciation after poll(2) */
this.stype = STYPE_HTTP;
this.stat = PSTAT_CONTINUE;
- /* Unique index */
- this.index = idx;
-
/* Empty request */
this.query_data = [];
this.query_data_length = 0;
fd.events = FD.POLLOUT;
fd.state = state_connect_appserv;
- if (++fdidx_count > 9999999)
- fdidx_count = fdidx_min + 1;
- fd.index = fdidx_count;
- set[fdidx_count] = fd;
-
fd.client_fd = this;
fd.sid = sid;
fd.set = set;
+ fd.appserv = s;
+
+ poll_set_add(fd);
} catch (x) {
err.put(x + " in appserv_connect()\n");
return false;
'application server. Please try again later.');
this.client_fd.state = state_close_success;
this.client_fd.events = FD.POLLOUT;
+ /*
this.set[this.index] = undefined;
+ this.vhost.server_put(this.appserv);
+ this.appserv = undefined;
+ */
return PSTAT_CLOSE_ERROR;
}
var fdidx_count = 0;
var fdidx_min = 0;
+var poll_set = {};
+
+function poll_set_add(fd)
+{
+
+ if (fdidx_count > 9999999)
+ fdidx_count = fdidx_min + 1;
+ fd.fdidx = fdidx_count++;
+ poll_set[fd.fdidx] = fd;
+}
+
+function poll_set_remove(fd)
+{
+
+ delete poll_set[fd.fdidx];
+}
+
+
+
/*
* Main program
*/
function main() {
var i;
var sess_gc_secs = 0;
- var set, fd, e, efd, flush;
+ var fd, e, efd, flush;
/*
* Populate vhosts database
}
/*
- * Create polling set object. Since arrays are sparce and would most
- * likely allocate too much room after a while, we're using an
- * associative object instead.
- */
- set = {};
-
- /*
* Initialize server
*/
for (i in listen) {
*/
fd.events = FD.POLLIN;
fd.stype = STYPE_LISTEN;
- set[fdidx_count++] = fd;
+ poll_set_add(fd);
} catch (x) {
err.put(x + " preparing listening socket\n");
}
/*
* Determine next to expire FD event, so that we can sleep
* as long as possible. Also get rid of expired requests.
+ * XXX Could be in a function
*/
var cur = Date.parse(new Date) / 1000;
var exp = cur + 3600;
var old;
- for (i in set) {
- if ((fd = set[i]) == undefined ||
- fd.stype == STYPE_LISTEN)
+ for (i in poll_set) {
+ if ((fd = poll_set[i]) == undefined ||
+ fd.stype != STYPE_HTTP)
continue;
if (fd.expires <= cur) {
/*
*/
fd.close();
counters_dec(fd);
- delete set[fd.index];
- delete fd;
+ poll_set_remove(fd);
continue;
}
if (fd.expires < exp)
* Poll our set of descriptors for events
*/
try {
- e = FD.poll(set, exp * 1000);
+ e = FD.poll(poll_set, exp * 1000);
} catch (x) {
err.put(x + " for poll(2)\n");
continue;
'allowed number of concurrent ' +
'connections.');
fd.close();
- efd = undefined;
- delete fd;
continue;
}
/*
* Setup client's initial state and
* add FD to polling set
*/
- if (++fdidx_count > 9999999)
- fdidx_count = fdidx_min + 1;
- fd.init(cur, fdidx_count);
- set[fdidx_count] = fd;
+ fd.http_init(cur);
+ poll_set_add(fd);
} catch (x) {
err.put(x + " at accept(2)\n");
fd.close();
- efd = undefined;
- delete fd;
}
continue;
}
try {
efd.close();
} catch (x) {}
- if (efd.stype == STYPE_APPSERV)
+ if (efd.stype == STYPE_APPSERV) {
+ /* Dismiss SID->FD table entry */
sid_table[efd.sid] = undefined;
- efd = undefined;
- counters_dec(e[i]);
- delete set[e[i].index];
- delete e[i];
+ /* appserv object back to pool */
+ efd.vhost.server_put(efd.appserv);
+ efd.appserv = undefined;
+ /*
+ * XXX Unlock any waiters and cause
+ * them to return a 500 error
+ */
+ }
+ counters_dec(efd);
+ poll_set_remove(efd);
}
}
}