49 const Cc = Components.classes;
50 const Ci = Components.interfaces;
51 const Cr = Components.results;
52 const Cu = Components.utils;
53 const CC = Components.Constructor;
75 dumpn(
"###!!! ASSERTION" + (
msg ?
": " +
msg :
"!"));
76 dumpn(
"###!!! Stack follows:");
78 var stack =
new Error().stack.split(/\n/);
79 dumpn(stack.map(
function(
val) {
return "###!!! " +
val; }).join(
"\n"));
81 throw Cr.NS_ERROR_ABORT;
89 this.description = description;
95 return this.code +
" " + this.description;
132 for (var
i = 0;
i < arr.length;
i++)
133 obj[arr[
i]] = arr[
i];
141 for (var
i = x;
i <=
y;
i++)
182 var stack =
new Error().stack.split(/\n/).slice(2);
183 stack.forEach(
dumpn);
194 if (!gRootPrefBranch)
196 gRootPrefBranch =
Cc[
"@mozilla.org/preferences-service;1"]
197 .getService(
Ci.nsIPrefBranch);
211 "nsIBinaryInputStream",
214 "nsIBinaryOutputStream",
217 "nsIScriptableInputStream",
223 "nsIFileInputStream",
226 "nsIConverterInputStream",
229 "nsIWritablePropertyBag2");
231 "nsISupportsString");
257 const wkdayStrings = [
"Sun",
"Mon",
"Tue",
"Wed",
"Thu",
"Fri",
"Sat"];
258 const monthStrings = [
"Jan",
"Feb",
"Mar",
"Apr",
"May",
"Jun",
259 "Jul",
"Aug",
"Sep",
"Oct",
"Nov",
"Dec"];
270 function toTime(
date)
272 var hrs =
date.getUTCHours();
273 var rv = (hrs < 10) ?
"0" + hrs : hrs;
275 var mins =
date.getUTCMinutes();
277 rv += (mins < 10) ?
"0" + mins : mins;
279 var secs =
date.getUTCSeconds();
281 rv += (secs < 10) ?
"0" + secs : secs;
295 function toDate1(
date)
301 var rv = (day < 10) ?
"0" + day : day;
302 rv +=
" " + monthStrings[
month];
310 const fmtString =
"%wkday%, %date1% %time% GMT";
311 var rv = fmtString.replace(
"%wkday%", wkdayStrings[
date.getUTCDay()]);
312 rv = rv.replace(
"%time%", toTime(
date));
313 return rv.replace(
"%date1%", toDate1(
date));
323 var s =
"******************************\n";
327 if (typeof(
i) !=
"string" ||
328 (showMembers || (
i.length > 0 &&
i[0] !=
"_")))
329 s+=
" " +
i +
": " + o[
i] +
",\n";
332 s +=
"******************************";
342 gThreadManager =
Cc[
"@mozilla.org/thread-manager;1"].getService();
345 this._port = undefined;
359 this._doQuit =
false;
365 this._socketClosed =
true;
372 this._connectionGen = 0;
378 this._connections = {};
394 onSocketAccepted:
function(socket, trans)
396 dumpn(
"*** onSocketAccepted(socket=" + socket +
", trans=" + trans +
")");
398 dumpn(
">>> new connection on " + trans.host +
":" + trans.port);
401 const SEGMENT_COUNT = 1024;
404 var input = trans.openInputStream(0,
SEGMENT_SIZE, SEGMENT_COUNT)
405 .QueryInterface(
Ci.nsIAsyncInputStream);
406 var
output = trans.openOutputStream(
Ci.nsITransport.OPEN_BLOCKING, 0, 0);
410 dumpn(
"*** error opening transport streams: " + e);
411 trans.close(
Cr.NS_BINDING_ABORTED);
415 var connectionNumber = ++this._connectionGen;
419 var conn =
new Connection(input, output,
this, socket.port, trans.port,
428 input.asyncWait(reader, 0, 0, gThreadManager.mainThread);
435 dumpn(
"*** error in initial request-processing stages: " + e);
436 trans.close(
Cr.NS_BINDING_ABORTED);
440 this._connections[connectionNumber] = conn;
441 dumpn(
"*** starting connection " + connectionNumber);
454 onStopListening:
function(socket, status)
456 dumpn(
">>> shutting down server on port " + socket.port);
457 this._socketClosed =
true;
458 if (!this._hasOpenConnections())
460 dumpn(
"*** no open connections, notifying async from onStopListening");
469 dumpn(
"*** _notifyStopped async callback");
470 self._notifyStopped();
473 gThreadManager.currentThread
474 .dispatch(stopEvent,
Ci.nsIThread.DISPATCH_NORMAL);
483 start:
function(port)
486 throw Cr.NS_ERROR_ALREADY_INITIALIZED;
489 this._doQuit = this._socketClosed =
false;
497 prefs.getIntPref(
"network.http.max-connections-per-server") + 5;
504 dumpn(
">>> listening on port " + socket.port +
", " + maxConnections +
505 " pending connections");
506 socket.asyncListen(
this);
507 this._identity._initialize(port,
true);
508 this._socket = socket;
512 dumpn(
"!!! could not start server on port " + port +
": " + e);
513 throw Cr.NS_ERROR_NOT_AVAILABLE;
523 throw Cr.NS_ERROR_NULL_POINTER;
525 throw Cr.NS_ERROR_UNEXPECTED;
527 this._stopCallback = typeof
callback ===
"function"
529 :
function() { callback.onStopped(); };
531 dumpn(
">>> stopping listening on port " + this._socket.port);
532 this._socket.close();
537 this._identity._teardown();
539 this._doQuit =
false;
550 throw Cr.NS_ERROR_INVALID_ARG;
552 this._handler.registerFile(
path,
file);
558 registerDirectory:
function(
path, directory)
561 if (
path.charAt(0) !=
"/" ||
562 path.charAt(
path.length - 1) !=
"/" ||
564 (!directory.exists() || !directory.isDirectory())))
565 throw Cr.NS_ERROR_INVALID_ARG;
570 this._handler.registerDirectory(
path, directory);
584 registerPrefixHandler:
function(prefix,
handler)
586 this._handler.registerPrefixHandler(prefix,
handler);
592 registerErrorHandler:
function(code,
handler)
594 this._handler.registerErrorHandler(code,
handler);
600 setIndexHandler:
function(
handler)
602 this._handler.setIndexHandler(
handler);
608 registerContentType:
function(ext, type)
610 this._handler.registerContentType(ext, type);
618 return this._identity;
624 getState:
function(
path, k)
626 return this._handler._getState(
path, k);
632 setState:
function(
path, k, v)
634 return this._handler._setState(
path, k, v);
640 getSharedState:
function(k)
642 return this._handler._getSharedState(k);
648 setSharedState:
function(k, v)
650 return this._handler._setSharedState(k, v);
656 getObjectState:
function(k)
658 return this._handler._getObjectState(k);
664 setObjectState:
function(k, v)
666 return this._handler._setObjectState(k, v);
677 if (iid.equals(
Ci.nsIHttpServer) ||
678 iid.equals(
Ci.nsIServerSocketListener) ||
679 iid.equals(
Ci.nsISupports))
682 throw Cr.NS_ERROR_NO_INTERFACE;
693 isStopped:
function()
695 return this._socketClosed && !this._hasOpenConnections();
701 _hasOpenConnections:
function()
710 for (var n in this._connections)
716 _notifyStopped:
function()
719 NS_ASSERT(!this._hasOpenConnections(),
"should be done serving by now");
728 var callback = this._stopCallback;
729 this._stopCallback =
null;
738 dump(
"!!! error running onStopped callback: " + e +
"\n");
748 _connectionClosed:
function(connection)
750 NS_ASSERT(connection.number in
this._connections,
751 "closing a connection " +
this +
" that we never added to the " +
752 "set of open connections?");
753 NS_ASSERT(this._connections[connection.number] === connection,
754 "connection number mismatch? " +
755 this._connections[connection.number]);
756 delete this._connections[connection.number];
759 if (!this._hasOpenConnections() && this._socketClosed)
760 this._notifyStopped();
766 _requestQuit:
function()
768 dumpn(
">>> requesting a quit");
788 "(?:[a-z0-9](?:[a-z0-9-]*[a-z0-9])?\\.)*" +
790 "[a-z](?:[a-z0-9-]*[a-z0-9])?" +
793 "\\d+\\.\\d+\\.\\d+\\.\\d+" +
814 this._primaryScheme =
"http";
817 this._primaryHost =
"127.0.0.1"
820 this._primaryPort = -1;
826 this._defaultPort = -1;
840 this._locations = {
"xlocalhost": {} };
848 _initialize:
function(port, addSecondaryDefault)
850 if (this._primaryPort !== -1)
851 this.
add(
"http",
"localhost", port);
853 this.setPrimary(
"http",
"localhost", port);
854 this._defaultPort = port;
857 if (addSecondaryDefault)
858 this.
add(
"http",
"127.0.0.1", port);
866 _teardown:
function()
869 this.
remove(
"http",
"127.0.0.1", this._defaultPort);
873 if (this._primaryScheme ==
"http" &&
874 this._primaryHost ==
"localhost" &&
875 this._primaryPort == this._defaultPort)
879 var port = this._defaultPort;
880 this._defaultPort = -1;
881 this.
remove(
"http",
"localhost", port);
884 this._primaryPort = -1;
889 this.
remove(
"http",
"localhost", this._defaultPort);
898 if (this._primaryPort === -1)
899 throw Cr.NS_ERROR_NOT_INITIALIZED;
900 return this._primaryScheme;
908 if (this._primaryPort === -1)
909 throw Cr.NS_ERROR_NOT_INITIALIZED;
910 return this._primaryHost;
918 if (this._primaryPort === -1)
919 throw Cr.NS_ERROR_NOT_INITIALIZED;
920 return this._primaryPort;
926 add:
function(scheme, host, port)
928 this._validate(scheme, host, port);
930 var
entry = this._locations[
"x" + host];
932 this._locations[
"x" + host] = entry = {};
934 entry[port] = scheme;
940 remove:
function(scheme, host, port)
942 this._validate(scheme, host, port);
944 var entry = this._locations[
"x" + host];
948 var present = port in
entry;
951 if (this._primaryScheme == scheme &&
952 this._primaryHost == host &&
953 this._primaryPort == port &&
954 this._defaultPort !== -1)
958 this._primaryPort = -1;
959 this._initialize(this._defaultPort,
false);
968 has:
function(scheme, host, port)
970 this._validate(scheme, host, port);
972 return "x" + host in this._locations &&
973 scheme === this._locations[
"x" + host][port];
979 getScheme:
function(host, port)
981 this._validate(
"http", host, port);
983 var entry = this._locations[
"x" + host];
987 return entry[port] ||
"";
993 setPrimary:
function(scheme, host, port)
995 this._validate(scheme, host, port);
997 this.
add(scheme, host, port);
999 this._primaryScheme = scheme;
1000 this._primaryHost = host;
1001 this._primaryPort = port;
1010 _validate:
function(scheme, host, port)
1012 if (scheme !==
"http" && scheme !==
"https")
1014 dumpn(
"*** server only supports http/https schemes: '" + scheme +
"'");
1016 throw Cr.NS_ERROR_ILLEGAL_VALUE;
1020 dumpn(
"*** unexpected host: '" + host +
"'");
1021 throw Cr.NS_ERROR_ILLEGAL_VALUE;
1023 if (port < 0 || port > 65535)
1025 dumpn(
"*** unexpected port: '" + port +
"'");
1026 throw Cr.NS_ERROR_ILLEGAL_VALUE;
1051 dumpn(
"*** opening new connection " + number +
" on port " + outgoingPort);
1066 this._outgoingPort = outgoingPort;
1069 this.number = number;
1075 this.request =
null;
1078 this._closed = this._processed =
false;
1085 dumpn(
"*** closing connection " + this.number +
1086 " on port " + this._outgoingPort);
1089 this.output.close();
1090 this._closed =
true;
1093 server._connectionClosed(
this);
1097 server.stop(
function() { });
1107 process:
function(request)
1109 NS_ASSERT(!this._closed && !this._processed);
1111 this._processed =
true;
1113 this.request = request;
1114 this.server._handler.handleResponse(
this);
1127 processError:
function(code, request)
1129 NS_ASSERT(!this._closed && !this._processed);
1131 this._processed =
true;
1132 this.request = request;
1133 this.server._handler.handleError(code,
this);
1137 toString:
function()
1139 return "<Connection(" + this.number +
1140 (this.request ?
", " + this.request.path :
"") +
"): " +
1141 (this._closed ?
"closed" :
"open") +
">";
1183 this._connection = connection;
1198 this._contentLength = 0;
1204 this._metadata =
new Request(connection.port);
1213 this._lastHeaderName = this._lastHeaderValue = undefined;
1227 onInputStreamReady:
function(input)
1229 dumpn(
"*** onInputStreamReady(input=" + input +
") on thread " +
1230 gThreadManager.currentThread +
" (main is " +
1231 gThreadManager.mainThread +
")");
1232 dumpn(
"*** this._state == " + this._state);
1236 var
data = this._data;
1242 data.appendBytes(
readBytes(input, input.available()));
1246 if (e.result !==
Cr.NS_BASE_STREAM_CLOSED)
1248 dumpn(
"*** WARNING: unexpected error when reading from socket; will " +
1249 "be treated as if the input stream had been closed");
1250 dumpn(
"*** WARNING: actual error was: " + e);
1256 dumpn(
"*** onInputStreamReady called on a closed input, destroying " +
1258 this._connection.close();
1262 switch (this._state)
1265 NS_ASSERT(
false,
"invalid state: " + this._state);
1269 if (!this._processRequestLine())
1274 if (!this._processHeaders())
1279 this._processBody();
1283 input.asyncWait(
this, 0, 0, gThreadManager.currentThread);
1291 if (aIID.equals(
Ci.nsIInputStreamCallback) ||
1292 aIID.equals(
Ci.nsISupports))
1295 throw Cr.NS_ERROR_NO_INTERFACE;
1307 _processRequestLine:
function()
1313 var data = this._data;
1316 while ((readSuccess = data.readLine(line)) && line.value ==
"")
1317 dumpn(
"*** ignoring beginning blank line...");
1326 this._parseRequestLine(line.value);
1332 this._handleError(e);
1344 _processHeaders:
function()
1354 var
done = this._parseHeaders();
1357 var request = this._metadata;
1362 this._contentLength = request.hasHeader(
"Content-Length")
1363 ? parseInt(request.getHeader(
"Content-Length"), 10)
1365 dumpn(
"_processHeaders, Content-length=" + this._contentLength);
1373 this._handleError(e);
1385 _processBody:
function()
1393 if (this._contentLength > 0)
1395 var data = this._data.purge();
1396 var
count = Math.min(data.length,
this._contentLength);
1397 dumpn(
"*** loading data=" + data +
" len=" + data.length +
1398 " excess=" + (data.length - count));
1401 bos.writeByteArray(data, count);
1402 this._contentLength -=
count;
1405 dumpn(
"*** remaining body data len=" + this._contentLength);
1406 if (this._contentLength == 0)
1408 this._validateRequest();
1410 this._handleResponse();
1418 this._handleError(e);
1429 _validateRequest:
function()
1433 dumpn(
"*** _validateRequest");
1435 var metadata = this._metadata;
1436 var headers = metadata._headers;
1439 var identity = this._connection.server.identity;
1442 if (!headers.hasHeader(
"Host"))
1444 dumpn(
"*** malformed HTTP/1.1 or greater request with no Host header!");
1452 if (!metadata._host)
1455 var hostPort = headers.getHeader(
"Host");
1456 var colon = hostPort.indexOf(
":");
1464 host = hostPort.substring(0, colon);
1465 port = hostPort.substring(colon + 1);
1473 dumpn(
"*** malformed hostname (" + hostPort +
") in Host " +
1474 "header, 400 time");
1485 var scheme = identity.getScheme(host, port);
1488 dumpn(
"*** unrecognized hostname (" + hostPort +
") in Host " +
1489 "header, 400 time");
1493 metadata._scheme = scheme;
1494 metadata._host = host;
1495 metadata._port = port;
1501 "HTTP/1.0 doesn't allow absolute paths in the request line!");
1503 metadata._scheme = identity.primaryScheme;
1504 metadata._host = identity.primaryHost;
1505 metadata._port = identity.primaryPort;
1508 NS_ASSERT(identity.has(metadata._scheme, metadata._host, metadata._port),
1509 "must have a location we recognize by now!");
1521 _handleError:
function(e)
1526 var server = this._connection.server;
1533 dumpn(
"!!! UNEXPECTED ERROR: " + e +
1534 (e.lineNumber ?
", line " + e.lineNumber :
""));
1538 server._requestQuit();
1544 this._connection.processError(code, this._metadata);
1554 _handleResponse:
function()
1562 this._connection.process(this._metadata);
1574 _parseRequestLine:
function(line)
1578 dumpn(
"*** _parseRequestLine('" + line +
"')");
1580 var metadata = this._metadata;
1584 var request = line.split(/[ \
t]+/);
1585 if (!request || request.length != 3)
1588 metadata._method = request[0];
1591 var ver = request[2];
1592 var
match = ver.match(/^HTTP\/(\
d+\.\
d+)$/);
1601 throw "unsupported HTTP version";
1610 var fullPath = request[1];
1611 var serverIdentity = this._connection.server.identity;
1613 var scheme, host, port;
1615 if (fullPath.charAt(0) !=
"/")
1623 var
uri =
Cc[
"@mozilla.org/network/io-service;1"]
1624 .getService(
Ci.nsIIOService)
1626 fullPath = uri.path;
1627 scheme = uri.scheme;
1628 host = metadata._host = uri.asciiHost;
1632 if (scheme ===
"http")
1634 else if (scheme ===
"https")
1648 if (!serverIdentity.has(scheme, host, port) || fullPath.charAt(0) !=
"/")
1652 var splitter = fullPath.indexOf(
"?");
1656 metadata._path = fullPath;
1660 metadata._path = fullPath.substring(0, splitter);
1661 metadata._queryString = fullPath.substring(splitter + 1);
1664 metadata._scheme = scheme;
1665 metadata._host = host;
1666 metadata._port = port;
1678 _parseHeaders:
function()
1682 dumpn(
"*** _parseHeaders");
1684 var data = this._data;
1686 var headers = this._metadata._headers;
1687 var lastName = this._lastHeaderName;
1688 var lastVal = this._lastHeaderValue;
1693 NS_ASSERT(!((lastVal === undefined) ^ (lastName === undefined)),
1694 lastName === undefined ?
1695 "lastVal without lastName? lastVal: '" + lastVal +
"'" :
1696 "lastName without lastVal? lastName: '" + lastName +
"'");
1698 if (!data.readLine(line))
1701 this._lastHeaderName = lastName;
1702 this._lastHeaderValue = lastVal;
1706 var lineText = line.value;
1707 var firstChar = lineText.charAt(0);
1717 headers.setHeader(lastName, lastVal,
true);
1721 dumpn(
"*** e == " + e);
1734 else if (firstChar ==
" " || firstChar ==
"\t")
1745 lastVal += lineText;
1754 headers.setHeader(lastName, lastVal,
true);
1758 dumpn(
"*** e == " + e);
1763 var colon = lineText.indexOf(
":");
1771 lastName = lineText.substring(0, colon);
1772 lastVal = lineText.substring(colon + 1);
1820 appendBytes:
function(bytes)
1822 Array.prototype.push.apply(this._data, bytes);
1837 readLine:
function(out)
1839 var data = this._data;
1854 var line =
String.fromCharCode.apply(
null, data.splice(0, length + 2));
1855 out.value = line.substring(0, length);
1868 var data = this._data;
1881 return function(metadata, response) {
handler.handle(metadata, response); };
1891 response.setHeader(
"Content-Type",
"text/html",
false);
1903 <title>' + path +
'</title>\
1906 <h1>' + path +
'</h1>\
1907 <ol style="list-style-type: none">';
1909 var directory = metadata.getProperty(
"directory");
1910 NS_ASSERT(directory && directory.isDirectory());
1913 var files = directory.directoryEntries;
1914 while (files.hasMoreElements())
1916 var f = files.getNext().QueryInterface(
Ci.nsIFile);
1917 var
name = f.leafName;
1918 if (!f.isHidden() &&
1919 (name.charAt(name.length - 1) != HIDDEN_CHAR ||
1926 for (var
i = 0;
i < fileList.length;
i++)
1928 var
file = fileList[
i];
1931 var
name = file.leafName;
1933 name = name.substring(0, name.length - 1);
1934 var sep = file.isDirectory() ?
"/" :
"";
1951 response.bodyOutputStream.write(body, body.length);
1959 var dira = a.isDirectory(), dirb = b.isDirectory();
1966 var namea = a.leafName.toLowerCase(), nameb = b.leafName.toLowerCase();
1967 return nameb > namea ? -1 : 1;
1988 var comps =
path.split(
"/");
1989 for (var
i = 0, sz = comps.length;
i < sz;
i++)
1991 var comp = comps[
i];
1993 comps[
i] = comp + HIDDEN_CHAR;
1995 return comps.join(
"/");
2016 name = name.substring(0, name.length - 1);
2018 var headerFile =
file.parent;
2021 if (!headerFile.exists())
2026 Ci.nsIFileInputStream.CLOSE_ON_EOF);
2031 lis.QueryInterface(
Ci.nsIUnicharLineInputStream);
2033 var line = {
value:
""};
2034 var more = lis.readLine(line);
2036 if (!more && line.value ==
"")
2042 var status = line.value;
2043 if (status.indexOf(
"HTTP ") == 0)
2045 status = status.substring(5);
2046 var space = status.indexOf(
" ");
2047 var code, description;
2055 code = status.substring(0, space);
2056 description = status.substring(space + 1, status.length);
2059 response.setStatusLine(metadata.httpVersion, parseInt(code, 10), description);
2062 more = lis.readLine(line);
2066 while (more || line.value !=
"")
2069 var colon = header.indexOf(
":");
2071 response.setHeader(header.substring(0, colon),
2072 header.substring(colon + 1, header.length),
2076 more = lis.readLine(line);
2081 dumpn(
"WARNING: error in headers for " + metadata.path +
": " + e);
2119 this._pathDirectoryMap =
new FileMap();
2127 this._overridePaths = {};
2136 this._overridePrefixes = {};
2145 this._overrideErrors = {};
2151 this._mimeMappings = {};
2163 this._sharedState = {};
2166 this._objectState = {};
2181 handleResponse:
function(connection)
2183 var request = connection.request;
2184 var response =
new Response(connection);
2186 var
path = request.path;
2187 dumpn(
"*** path == " + path);
2193 if (path in this._overridePaths)
2197 dumpn(
"calling override for " + path);
2198 this._overridePaths[
path](request, response);
2202 let longestPrefix =
"";
2203 for (let prefix in this._overridePrefixes)
2205 if (prefix.length > longestPrefix.length &&
2206 path.substr(0, prefix.length) == prefix)
2208 longestPrefix = prefix;
2211 if (longestPrefix.length > 0)
2213 dumpn(
"calling prefix override for " + longestPrefix);
2214 this._overridePrefixes[longestPrefix](request, response);
2218 this._handleDefault(request, response);
2224 if (response.partiallySent())
2230 if (!(e instanceof HttpError))
2232 dumpn(
"*** unexpected error: e == " + e);
2238 dumpn(
"*** default: " + (path in this._defaultPaths));
2240 response =
new Response(connection);
2241 if (path in this._defaultPaths)
2242 this._defaultPaths[
path](request, response);
2249 if (response.partiallySent())
2255 var errorCode =
"internal";
2259 if (!(e instanceof HttpError))
2263 dumpn(
"*** errorCode == " + errorCode);
2265 response =
new Response(connection);
2266 this._handleError(errorCode, request, response);
2271 dumpn(
"*** error handling " + errorCode +
" error: " +
2272 "e2 == " + e2 +
", shutting down server");
2274 connection.server._requestQuit();
2280 response.complete();
2290 dumpn(
"*** unregistering '" + path +
"' mapping");
2291 delete this._overridePaths[
path];
2295 dumpn(
"*** registering '" + path +
"' as mapping to " +
file.path);
2299 this._overridePaths[
path] =
2300 function(request, response)
2305 response.setStatusLine(request.httpVersion, 200,
"OK");
2306 self._writeFileResponse(request,
file, response, 0,
file.fileSize);
2316 if (path.charAt(0) !=
"/")
2317 throw Cr.NS_ERROR_INVALID_ARG;
2319 this._handlerToField(
handler,
this._overridePaths, path);
2328 if (path.charAt(0) !=
"/" || path.charAt(path.length - 1) !=
"/")
2329 throw Cr.NS_ERROR_INVALID_ARG;
2331 this._handlerToField(
handler,
this._overridePrefixes, path);
2337 registerDirectory:
function(
path, directory)
2343 var
key = path.length == 1 ?
"" : path.substring(1, path.length - 1);
2347 if (key.charAt(0) ==
"/")
2348 throw Cr.NS_ERROR_INVALID_ARG;
2354 dumpn(
"*** mapping '" + path +
"' to the location " + directory.path);
2355 this._pathDirectoryMap.put(key, directory);
2359 dumpn(
"*** removing mapping for '" + path +
"'");
2360 this._pathDirectoryMap.put(key,
null);
2367 registerErrorHandler:
function(err,
handler)
2370 dumpn(
"*** WARNING: registering non-HTTP/1.1 error code " +
2371 "(" + err +
") handler -- was this intentional?");
2373 this._handlerToField(
handler, this._overrideErrors, err);
2379 setIndexHandler:
function(
handler)
2383 else if (typeof(
handler) !=
"function")
2392 registerContentType:
function(ext, type)
2395 delete this._mimeMappings[ext];
2397 this._mimeMappings[ext] =
headerUtils.normalizeFieldValue(type);
2412 _handlerToField:
function(
handler, dict,
key)
2415 if (typeof(
handler) ==
"function")
2436 _handleDefault:
function(metadata, response)
2438 dumpn(
"*** _handleDefault()");
2440 response.setStatusLine(metadata.httpVersion, 200,
"OK");
2442 var path = metadata.path;
2443 NS_ASSERT(path.charAt(0) ==
"/",
"invalid path: <" + path +
">");
2447 var
file = this._getFileForPath(path);
2451 if (file.exists() && file.isDirectory())
2453 file.append(
"index.html");
2454 if (!file.exists() || file.isDirectory())
2456 metadata._ensurePropertyBag();
2457 metadata._bag.setPropertyAsInterface(
"directory", file.parent);
2458 this._indexHandler(metadata, response);
2468 if (metadata._httpVersion.atLeast(
nsHttpVersion.HTTP_1_1) &&
2469 metadata.hasHeader(
"Range") &&
2470 this._getTypeFromFile(file) !==
SJS_TYPE)
2472 var rangeMatch = metadata.getHeader(
"Range").match(/^bytes=(\
d+)?-(\
d+)?$/);
2476 if (rangeMatch[1] !== undefined)
2477 start = parseInt(rangeMatch[1], 10);
2479 if (rangeMatch[2] !== undefined)
2480 end = parseInt(rangeMatch[2], 10);
2482 if (start === undefined && end === undefined)
2487 if (start === undefined)
2489 start = Math.max(0, file.fileSize - end);
2490 end = file.fileSize - 1;
2494 if (end === undefined || end >= file.fileSize)
2495 end = file.fileSize - 1;
2497 if (start !== undefined && start >= file.fileSize)
2502 response.setStatusLine(metadata.httpVersion, 200,
"OK");
2504 end = file.fileSize - 1;
2508 response.setStatusLine(metadata.httpVersion, 206,
"Partial Content");
2509 var contentRange =
"bytes " + start +
"-" + end +
"/" + file.fileSize;
2510 response.setHeader(
"Content-Range", contentRange);
2516 end = file.fileSize - 1;
2520 dumpn(
"*** handling '" + path +
"' as mapping to " + file.path +
" from " +
2521 start +
" to " + end +
" inclusive");
2522 this._writeFileResponse(metadata, file, response, start, end - start + 1);
2544 var type = this._getTypeFromFile(file);
2548 Ci.nsIFileInputStream.CLOSE_ON_EOF);
2554 s.importFunction(dump,
"dump");
2559 var path = metadata.path;
2560 s.importFunction(
function getState(k)
2562 return self._getState(path, k);
2564 s.importFunction(
function setState(k, v)
2566 self._setState(path, k, v);
2568 s.importFunction(
function getSharedState(k)
2570 return self._getSharedState(k);
2572 s.importFunction(
function setSharedState(k, v)
2574 self._setSharedState(k, v);
2576 s.importFunction(
function getObjectState(k, callback)
2580 s.importFunction(
function setObjectState(k, v)
2582 self._setObjectState(k, v);
2592 var line =
new Error().lineNumber;
2593 Cu.evalInSandbox(sis.read(file.fileSize), s);
2597 dumpn(
"*** syntax error in SJS at " + file.path +
": " + e);
2603 s.handleRequest(metadata, response);
2607 dump(
"*** error running SJS at " + file.path +
": " +
2610 ? e.lineNumber +
" in httpd.js"
2611 : (e.lineNumber - line)) +
"\n");
2624 response.setHeader(
"Last-Modified",
2630 response.setHeader(
"Content-Type", type,
false);
2632 response.setHeader(
"Content-Length",
"" + count,
false);
2635 Ci.nsIFileInputStream.CLOSE_ON_EOF);
2637 offset = offset || 0;
2638 count = count || file.fileSize;
2639 NS_ASSERT(offset === 0 || offset < file.fileSize,
"bad offset");
2641 NS_ASSERT(offset + count <= file.fileSize,
"bad total data size");
2649 if (fis instanceof
Ci.nsISeekableStream)
2650 fis.seek(
Ci.nsISeekableStream.NS_SEEK_SET, offset);
2661 function writeMore()
2663 gThreadManager.currentThread
2664 .dispatch(writeData,
Ci.nsIThread.DISPATCH_NORMAL);
2673 var chunkSize = Math.min(65536, count);
2679 var data = input.readByteArray(chunkSize);
2681 "incorrect data returned? got " + data.length +
2682 ", expected " + chunkSize);
2683 output.writeByteArray(data, data.length);
2712 response.processAsync();
2727 _getState:
function(
path, k)
2729 var state = this._state;
2730 if (path in state && k in state[path])
2731 return state[
path][k];
2746 _setState:
function(
path, k, v)
2748 if (typeof v !==
"string")
2749 throw new Error(
"non-string value passed");
2750 var state = this._state;
2751 if (!(path in state))
2765 _getSharedState:
function(k)
2767 var state = this._sharedState;
2782 _setSharedState:
function(k, v)
2784 if (typeof v !==
"string")
2785 throw new Error(
"non-string value passed");
2786 this._sharedState[k] = v;
2798 _getObjectState:
function(k)
2800 if (typeof k !==
"string")
2801 throw new Error(
"non-string key passed");
2802 return this._objectState[k] ||
null;
2814 _setObjectState:
function(k, v)
2816 if (typeof k !==
"string")
2817 throw new Error(
"non-string key passed");
2818 if (typeof v !==
"object")
2819 throw new Error(
"non-object value passed");
2820 if (v && !(
"QueryInterface" in v))
2822 throw new Error(
"must pass an nsISupports; use wrappedJSObject to ease " +
2823 "pain when using the server from JS");
2826 this._objectState[k] = v;
2840 _getTypeFromFile:
function(
file)
2844 var
name = file.leafName;
2845 var dot = name.lastIndexOf(
".");
2848 var ext = name.slice(dot + 1);
2849 if (ext in this._mimeMappings)
2850 return this._mimeMappings[ext];
2852 return Cc[
"@mozilla.org/uriloader/external-helper-app-service;1"]
2853 .getService(
Ci.nsIMIMEService)
2854 .getTypeFromFile(file);
2858 return "application/octet-stream";
2876 _getFileForPath:
function(
path)
2889 var pathMap = this._pathDirectoryMap;
2893 var tmp = path.substring(1);
2897 var file = pathMap.get(tmp);
2904 if (tmp == path.substring(1) &&
2906 tmp.charAt(tmp.length - 1) !=
"/")
2916 tmp = tmp.substring(0, tmp.lastIndexOf(
"/"));
2925 var parentFolder = file.parent;
2926 var dirIsRoot = (parentFolder ==
null);
2933 var leafPath = path.substring(tmp.length + 1);
2934 var comps = leafPath.split(
"/");
2935 for (var
i = 0, sz = comps.length;
i < sz;
i++)
2937 var comp = comps[
i];
2941 else if (comp ==
"." || comp ==
"")
2946 if (!dirIsRoot && file.equals(parentFolder))
2962 handleError:
function(errorCode, connection)
2964 var response =
new Response(connection);
2966 dumpn(
"*** error in request: " + errorCode);
2968 this._handleError(errorCode,
new Request(connection.port), response);
2988 _handleError:
function(errorCode, metadata, response)
2991 throw Cr.NS_ERROR_NULL_POINTER;
2993 var errorX00 = errorCode - (errorCode % 100);
2997 if (!(errorCode in HTTP_ERROR_CODES))
2998 dumpn(
"*** WARNING: requested invalid error: " + errorCode);
3008 if (errorCode in this._overrideErrors)
3009 this._overrideErrors[errorCode](metadata, response);
3011 this._defaultErrors[errorCode](metadata, response);
3015 if (response.partiallySent())
3022 if (errorX00 == errorCode)
3025 dumpn(
"*** error in handling for error code " + errorCode +
", " +
3026 "falling back to " + errorX00 +
"...");
3027 response =
new Response(response._connection);
3028 if (errorX00 in this._overrideErrors)
3029 this._overrideErrors[errorX00](metadata, response);
3030 else if (errorX00 in this._defaultErrors)
3031 this._defaultErrors[errorX00](metadata, response);
3038 if (response.partiallySent())
3045 dumpn(
"*** error in handling for error code " + errorX00 +
", falling " +
3050 response =
new Response(response._connection);
3051 if (500 in this._overrideErrors)
3052 this._overrideErrors[500](metadata, response);
3054 this._defaultErrors[500](metadata, response);
3058 dumpn(
"*** multiple errors in default error handlers!");
3059 dumpn(
"*** e == " + e +
", e2 == " + e2);
3065 response.complete();
3075 400:
function(metadata, response)
3078 response.setStatusLine(
"1.1", 400,
"Bad Request");
3079 response.setHeader(
"Content-Type",
"text/plain",
false);
3081 var body =
"Bad request\n";
3082 response.bodyOutputStream.write(body, body.length);
3084 403:
function(metadata, response)
3086 response.setStatusLine(metadata.httpVersion, 403,
"Forbidden");
3087 response.setHeader(
"Content-Type",
"text/html",
false);
3090 <head><title>403 Forbidden</title></head>\
3092 <h1>403 Forbidden</h1>\
3095 response.bodyOutputStream.write(body, body.length);
3097 404:
function(metadata, response)
3099 response.setStatusLine(metadata.httpVersion, 404,
"Not Found");
3100 response.setHeader(
"Content-Type",
"text/html",
false);
3103 <head><title>404 Not Found</title></head>\
3105 <h1>404 Not Found</h1>\
3107 <span style='font-family: monospace;'>" +
3109 "</span> was not found.\
3113 response.bodyOutputStream.write(body, body.length);
3115 416:
function(metadata, response)
3117 response.setStatusLine(metadata.httpVersion,
3119 "Requested Range Not Satisfiable");
3120 response.setHeader(
"Content-Type",
"text/html",
false);
3124 <title>416 Requested Range Not Satisfiable</title></head>\
3126 <h1>416 Requested Range Not Satisfiable</h1>\
3127 <p>The byte range was not valid for the\
3128 requested resource.\
3132 response.bodyOutputStream.write(body, body.length);
3134 500:
function(metadata, response)
3136 response.setStatusLine(metadata.httpVersion,
3138 "Internal Server Error");
3139 response.setHeader(
"Content-Type",
"text/html",
false);
3142 <head><title>500 Internal Server Error</title></head>\
3144 <h1>500 Internal Server Error</h1>\
3145 <p>Something's broken in this server and\
3146 needs to be fixed.</p>\
3149 response.bodyOutputStream.write(body, body.length);
3151 501:
function(metadata, response)
3153 response.setStatusLine(metadata.httpVersion, 501,
"Not Implemented");
3154 response.setHeader(
"Content-Type",
"text/html",
false);
3157 <head><title>501 Not Implemented</title></head>\
3159 <h1>501 Not Implemented</h1>\
3160 <p>This server is not (yet) Apache.</p>\
3163 response.bodyOutputStream.write(body, body.length);
3165 505:
function(metadata, response)
3167 response.setStatusLine(
"1.1", 505,
"HTTP Version Not Supported");
3168 response.setHeader(
"Content-Type",
"text/html",
false);
3171 <head><title>505 HTTP Version Not Supported</title></head>\
3173 <h1>505 HTTP Version Not Supported</h1>\
3174 <p>This server only supports HTTP/1.0 and HTTP/1.1\
3178 response.bodyOutputStream.write(body, body.length);
3187 "/":
function(metadata, response)
3189 response.setStatusLine(metadata.httpVersion, 200,
"OK");
3190 response.setHeader(
"Content-Type",
"text/html",
false);
3193 <head><title>httpd.js</title></head>\
3196 <p>If you're seeing this page, httpd.js is up and\
3197 serving requests! Now set a base path and serve some\
3202 response.bodyOutputStream.write(body, body.length);
3205 "/trace":
function(metadata, response)
3207 response.setStatusLine(metadata.httpVersion, 200,
"OK");
3208 response.setHeader(
"Content-Type",
"text/plain",
false);
3210 var body =
"Request-URI: " +
3211 metadata.scheme +
"://" + metadata.host +
":" + metadata.port +
3212 metadata.path +
"\n\n";
3213 body +=
"Request (semantically equivalent, slightly reformatted):\n\n";
3214 body += metadata.method +
" " + metadata.path;
3216 if (metadata.queryString)
3217 body +=
"?" + metadata.queryString;
3219 body +=
" HTTP/" + metadata.httpVersion +
"\r\n";
3221 var headEnum = metadata.headers;
3222 while (headEnum.hasMoreElements())
3224 var fieldName = headEnum.getNext()
3225 .QueryInterface(
Ci.nsISupportsString)
3227 body += fieldName +
": " + metadata.getHeader(fieldName) +
"\r\n";
3230 response.bodyOutputStream.write(body, body.length);
3262 delete this._map[
key];
3276 var
val = this._map[
key];
3277 return val ? val.clone() :
null;
3292 [0, 0, 0, 0, 0, 0, 0, 0,
3293 0, 0, 0, 0, 0, 0, 0, 0,
3294 0, 0, 0, 0, 0, 0, 0, 0,
3295 0, 0, 0, 0, 0, 0, 0, 0,
3297 0, 1, 0, 1, 1, 1, 1, 1,
3298 0, 0, 1, 1, 0, 1, 1, 0,
3299 1, 1, 1, 1, 1, 1, 1, 1,
3300 1, 1, 0, 0, 0, 0, 0, 0,
3302 0, 1, 1, 1, 1, 1, 1, 1,
3303 1, 1, 1, 1, 1, 1, 1, 1,
3304 1, 1, 1, 1, 1, 1, 1, 1,
3305 1, 1, 1, 0, 0, 0, 1, 1,
3307 1, 1, 1, 1, 1, 1, 1, 1,
3308 1, 1, 1, 1, 1, 1, 1, 1,
3309 1, 1, 1, 1, 1, 1, 1, 1,
3310 1, 1, 1, 0, 1, 0, 1];
3323 return (code >= 0 && code <= 31) || (code == 127);
3337 this._connection = connection;
3348 this._httpCode = 200;
3353 this._httpDescription =
"OK";
3369 this._ended =
false;
3374 this._bodyOutputStream =
null;
3382 this._bodyInputStream =
null;
3388 this._asyncCopier =
null;
3395 this._processAsync =
false;
3401 this._finished =
false;
3408 this._powerSeized =
false;
3417 get bodyOutputStream()
3420 throw Cr.NS_ERROR_NOT_AVAILABLE;
3422 if (!this._bodyOutputStream)
3426 this._bodyOutputStream = pipe.outputStream;
3427 this._bodyInputStream = pipe.inputStream;
3428 if (this._processAsync || this._powerSeized)
3429 this._startAsyncProcessor();
3432 return this._bodyOutputStream;
3438 write:
function(
data)
3441 throw Cr.NS_ERROR_NOT_AVAILABLE;
3443 var dataAsString =
String(data);
3444 this.bodyOutputStream.write(dataAsString, dataAsString.length);
3450 setStatusLine:
function(httpVersion, code, description)
3452 if (!this._headers || this._finished || this._powerSeized)
3453 throw Cr.NS_ERROR_NOT_AVAILABLE;
3454 this._ensureAlive();
3456 if (!(code >= 0 && code < 1000))
3457 throw Cr.NS_ERROR_INVALID_ARG;
3463 if (!httpVersion || httpVersion ==
"1.1")
3465 else if (httpVersion ==
"1.0")
3472 throw Cr.NS_ERROR_INVALID_ARG;
3482 for (var
i = 0;
i < description.length;
i++)
3483 if (
isCTL(description.charCodeAt(
i)) && description.charAt(
i) !=
"\t")
3484 throw Cr.NS_ERROR_INVALID_ARG;
3487 this._httpDescription = description;
3488 this._httpCode = code;
3489 this._httpVersion = httpVer;
3497 if (!this._headers || this._finished || this._powerSeized)
3498 throw Cr.NS_ERROR_NOT_AVAILABLE;
3499 this._ensureAlive();
3501 this._headers.setHeader(name, value, merge);
3507 processAsync:
function()
3510 throw Cr.NS_ERROR_UNEXPECTED;
3511 if (this._powerSeized)
3512 throw Cr.NS_ERROR_NOT_AVAILABLE;
3513 if (this._processAsync)
3515 this._ensureAlive();
3517 dumpn(
"*** processing connection " + this._connection.number +
" async");
3518 this._processAsync =
true;
3533 if (this._bodyOutputStream && !this._asyncCopier)
3534 this._startAsyncProcessor();
3540 seizePower:
function()
3542 if (this._processAsync)
3543 throw Cr.NS_ERROR_NOT_AVAILABLE;
3545 throw Cr.NS_ERROR_UNEXPECTED;
3546 if (this._powerSeized)
3548 this._ensureAlive();
3550 dumpn(
"*** forcefully seizing power over connection " +
3551 this._connection.number +
"...");
3557 if (this._asyncCopier)
3558 this._asyncCopier.cancel(
Cr.NS_BINDING_ABORTED);
3559 this._asyncCopier =
null;
3560 if (this._bodyOutputStream)
3564 while ((avail = input.available()) > 0)
3565 input.readByteArray(avail);
3568 this._powerSeized =
true;
3569 if (this._bodyOutputStream)
3570 this._startAsyncProcessor();
3578 if (!this._processAsync && !this._powerSeized)
3579 throw Cr.NS_ERROR_UNEXPECTED;
3583 dumpn(
"*** finishing connection " + this._connection.number);
3584 this._startAsyncProcessor();
3585 if (this._bodyOutputStream)
3586 this._bodyOutputStream.close();
3587 this._finished =
true;
3598 this._ensureAlive();
3599 return this._httpVersion.toString();
3608 this._ensureAlive();
3610 var codeString = (this._httpCode < 10 ?
"0" :
"") +
3611 (this._httpCode < 100 ?
"0" :
"") +
3620 get httpDescription()
3622 this._ensureAlive();
3624 return this._httpDescription;
3632 this._ensureAlive();
3634 return this._headers;
3640 getHeader:
function(
name)
3642 this._ensureAlive();
3644 return this._headers.getHeader(name);
3656 partiallySent:
function()
3658 dumpn(
"*** partiallySent()");
3659 return this._processAsync || this._powerSeized;
3666 complete:
function()
3668 dumpn(
"*** complete()");
3669 if (this._processAsync || this._powerSeized)
3671 NS_ASSERT(this._processAsync ^ this._powerSeized,
3672 "can't both send async and relinquish power");
3676 NS_ASSERT(!this.partiallySent(),
"completing a partially-sent response?");
3678 this._startAsyncProcessor();
3681 if (this._bodyOutputStream)
3682 this._bodyOutputStream.close();
3700 dumpn(
"*** abort(<" + e +
">)");
3703 var copier = this._asyncCopier;
3719 gThreadManager.currentThread.dispatch({
3722 dumpn(
"*** canceling copy asynchronously...");
3723 copier.cancel(
Cr.NS_ERROR_UNEXPECTED);
3725 },
Ci.nsIThread.DISPATCH_NORMAL);
3739 NS_ASSERT(!this._ended,
"ending this response twice?!?!");
3741 this._connection.close();
3742 if (this._bodyOutputStream)
3743 this._bodyOutputStream.close();
3745 this._finished =
true;
3758 _sendHeaders:
function()
3760 dumpn(
"*** _sendHeaders()");
3766 var statusLine =
"HTTP/" + this.httpVersion +
" " +
3767 this.httpCode +
" " +
3768 this.httpDescription +
"\r\n";
3772 var headers = this._headers;
3773 headers.setHeader(
"Connection",
"close",
false);
3774 headers.setHeader(
"Server",
"httpd.js",
false);
3775 if (!headers.hasHeader(
"Date"))
3776 headers.setHeader(
"Date",
toDateString(Date.now()),
false);
3784 if (!this._processAsync)
3786 dumpn(
"*** non-async response, set Content-Length");
3788 var bodyStream = this._bodyInputStream;
3789 var avail = bodyStream ? bodyStream.available() : 0;
3792 headers.setHeader(
"Content-Length",
"" + avail,
false);
3797 dumpn(
"*** header post-processing completed, sending response head...");
3800 var preamble = statusLine;
3803 var headEnum = headers.enumerator;
3804 while (headEnum.hasMoreElements())
3806 var fieldName = headEnum.getNext()
3807 .QueryInterface(
Ci.nsISupportsString)
3809 var values = headers.getHeaderValues(fieldName);
3810 for (var
i = 0, sz = values.length;
i < sz;
i++)
3811 preamble += fieldName +
": " + values[
i] +
"\r\n";
3817 var connection = this._connection;
3820 connection.output.write(preamble, preamble.length);
3827 dumpn(
"*** error writing headers to socket: " + e);
3833 this._headers =
null;
3841 _startAsyncProcessor:
function()
3843 dumpn(
"*** _startAsyncProcessor()");
3849 if (this._asyncCopier || this._ended)
3851 dumpn(
"*** ignoring second call to _startAsyncProcessor");
3858 if (this._powerSeized)
3859 this._headers =
null;
3861 this._sendHeaders();
3862 NS_ASSERT(this._headers ===
null,
"_sendHeaders() failed?");
3865 var response =
this;
3866 var connection = this._connection;
3869 if (!this._bodyInputStream)
3871 dumpn(
"*** empty body, response finished");
3878 onStartRequest:
function(request, context)
3880 dumpn(
"*** onStartRequest");
3883 onStopRequest:
function(request, cx, statusCode)
3885 dumpn(
"*** onStopRequest [status=0x" + statusCode.toString(16) +
"]");
3887 if (statusCode ===
Cr.NS_BINDING_ABORTED)
3889 dumpn(
"*** terminating copy observer without ending the response");
3893 if (!Components.isSuccessCode(statusCode))
3894 dumpn(
"*** WARNING: non-success statusCode in onStopRequest");
3902 if (aIID.equals(
Ci.nsIRequestObserver) ||
3903 aIID.equals(
Ci.nsISupports))
3906 throw Cr.NS_ERROR_NO_INTERFACE;
3910 dumpn(
"*** starting async copier of body data...");
3911 var copier = this._asyncCopier =
3913 copyObserver,
null);
3917 _ensureAlive:
function()
3919 NS_ASSERT(!this._ended,
"not handling response lifetime correctly");
3932 throw Cr.NS_ERROR_NOT_IMPLEMENTED;
3951 if (!input || !output || !
observer)
3952 throw Cr.NS_ERROR_NULL_POINTER;
3955 this._input = input;
3964 this._context = context;
3967 this._completed =
false;
3974 this.name =
"response-body-copy";
3977 this.status =
Cr.NS_OK;
3982 observer.onStartRequest(
this, context);
3983 this._waitForData();
3987 dumpn(
"!!! error starting copy: " + e);
3988 this.cancel(
Cr.NS_ERROR_UNEXPECTED);
4000 cancel:
function(status)
4002 dumpn(
"*** cancel(" + status.toString(16) +
")");
4004 if (this._completed)
4006 dumpn(
"*** ignoring cancel on already-canceled copier...");
4010 this._completed =
true;
4011 this.status = status;
4018 dumpn(
"*** onStopRequest async callback");
4021 self._observer.onStopRequest(
self,
self._context,
self.status);
4025 NS_ASSERT(
false,
"how are we throwing an exception here? " + e);
4029 gThreadManager.currentThread
4030 .dispatch(cancelEvent,
Ci.nsIThread.DISPATCH_NORMAL);
4037 isPending:
function()
4039 return !this._completed;
4051 onInputStreamReady:
function(input)
4053 dumpn(
"*** onInputStreamReady");
4054 if (this._completed)
4056 dumpn(
"*** ignoring stream-ready callback on a canceled copier...");
4063 var avail = input.available();
4064 var data = input.readByteArray(avail);
4065 this._output.writeByteArray(data, data.length);
4069 if (e ===
Cr.NS_BASE_STREAM_CLOSED ||
4070 e.result ===
Cr.NS_BASE_STREAM_CLOSED)
4072 this.cancel(
Cr.NS_OK);
4076 dumpn(
"!!! error copying from input to output: " + e);
4077 this.cancel(
Cr.NS_ERROR_UNEXPECTED);
4083 this.cancel(
Cr.NS_OK);
4085 this._waitForData();
4091 _waitForData:
function()
4093 dumpn(
"*** _waitForData");
4094 this._input.asyncWait(
this, 0, 1, gThreadManager.mainThread);
4100 if (iid.equals(
Ci.nsIRequest) ||
4101 iid.equals(
Ci.nsISupports) ||
4102 iid.equals(
Ci.nsIInputStreamCallback))
4107 throw Cr.NS_ERROR_NO_INTERFACE;
4128 normalizeFieldName:
function(fieldName)
4130 if (fieldName ==
"")
4131 throw Cr.NS_ERROR_INVALID_ARG;
4133 for (var
i = 0, sz = fieldName.length;
i < sz;
i++)
4137 dumpn(fieldName +
" is not a valid header field name!");
4138 throw Cr.NS_ERROR_INVALID_ARG;
4142 return fieldName.toLowerCase();
4158 normalizeFieldValue:
function(fieldValue)
4176 var
val = fieldValue.replace(/(?:(?:\r\n)?[ \
t]+)+/g,
" ");
4179 val = val.replace(/^ +/,
"").replace(/ +$/,
"");
4182 for (var
i = 0, len = val.length;
i < len;
i++)
4183 if (
isCTL(val.charCodeAt(
i)))
4184 throw Cr.NS_ERROR_INVALID_ARG;
4208 for (var
i = 0;
i <
str.length;
i++)
4209 s +=
"&#" +
str.charCodeAt(
i) +
";";
4225 var matches = /^(
\d+)\.(\
d+)$/.exec(versionString);
4227 throw "Not a valid HTTP version!";
4230 this.major = parseInt(matches[1], 10);
4233 this.minor = parseInt(matches[2], 10);
4235 if (isNaN(this.major) || isNaN(this.minor) ||
4236 this.major < 0 || this.minor < 0)
4237 throw "Not a valid HTTP version!";
4245 toString:
function ()
4247 return this.major +
"." + this.minor;
4257 equals:
function (otherVersion)
4259 return this.major == otherVersion.major &&
4260 this.minor == otherVersion.minor;
4264 atLeast:
function(otherVersion)
4266 return this.major > otherVersion.major ||
4267 (this.major == otherVersion.major &&
4268 this.minor >= otherVersion.minor);
4313 setHeader:
function(fieldName, fieldValue, merge)
4315 var name =
headerUtils.normalizeFieldName(fieldName);
4316 var value =
headerUtils.normalizeFieldValue(fieldValue);
4321 if (merge && name in this._headers)
4323 if (name ===
"www-authenticate" ||
4324 name ===
"proxy-authenticate" ||
4325 name ===
"set-cookie")
4327 this._headers[
name].push(value);
4332 NS_ASSERT(this._headers[name].length === 1,
4333 "how'd a non-special header have multiple values?")
4356 getHeader:
function(fieldName)
4358 return this.getHeaderValues(fieldName).join(
"\n");
4378 getHeaderValues:
function(fieldName)
4380 var name =
headerUtils.normalizeFieldName(fieldName);
4382 if (name in this._headers)
4383 return this._headers[
name];
4385 throw Cr.NS_ERROR_NOT_AVAILABLE;
4399 hasHeader:
function(fieldName)
4401 var name =
headerUtils.normalizeFieldName(fieldName);
4402 return (name in this._headers);
4414 for (var
i in this._headers)
4418 headers.push(supports);
4434 this._items = items;
4435 this._nextIndex = 0;
4441 return this._nextIndex < this._items.length;
4446 throw Cr.NS_ERROR_NOT_AVAILABLE;
4448 return this._items[
this._nextIndex++];
4452 if (
Ci.nsISimpleEnumerator.equals(aIID) ||
4453 Ci.nsISupports.equals(aIID))
4456 throw Cr.NS_ERROR_NO_INTERFACE;
4476 this._queryString =
"";
4479 this._scheme =
"http";
4482 this._host = undefined;
4490 this._bodyInputStream = bodyPipe.inputStream;
4493 this._bodyOutputStream = bodyPipe.outputStream;
4516 return this._scheme;
4542 return this._method;
4550 return this._httpVersion.toString();
4566 return this._queryString;
4574 getHeader:
function(
name)
4576 return this._headers.getHeader(name);
4582 hasHeader:
function(
name)
4584 return this._headers.hasHeader(name);
4592 return this._headers.enumerator;
4600 this._ensurePropertyBag();
4601 return this._bag.enumerator;
4607 get bodyInputStream()
4609 return this._bodyInputStream;
4615 getProperty:
function(
name)
4617 this._ensurePropertyBag();
4618 return this._bag.getProperty(name);
4622 _ensurePropertyBag:
function()
4638 function ci(outer, iid)
4641 throw Components.results.NS_ERROR_NO_AGGREGATION;
4642 return (
new ctor()).QueryInterface(iid);
4647 lockFactory:
function(lock) { },
4650 if (
Ci.nsIFactory.equals(aIID) ||
4651 Ci.nsISupports.equals(aIID))
4653 throw Cr.NS_ERROR_NO_INTERFACE;
4664 if (
Ci.nsIModule.equals(aIID) ||
4665 Ci.nsISupports.equals(aIID))
4667 throw Cr.NS_ERROR_NO_INTERFACE;
4671 registerSelf:
function(compMgr, fileSpec, location, type)
4673 compMgr = compMgr.QueryInterface(
Ci.nsIComponentRegistrar);
4675 for (var key in this._objects)
4677 var obj = this._objects[
key];
4678 compMgr.registerFactoryLocation(obj.CID, obj.className, obj.contractID,
4679 fileSpec, location, type);
4682 unregisterSelf:
function (compMgr, location, type)
4684 compMgr = compMgr.QueryInterface(
Ci.nsIComponentRegistrar);
4686 for (var key in this._objects)
4688 var obj = this._objects[
key];
4689 compMgr.unregisterFactoryLocation(obj.CID, location);
4694 if (!iid.equals(
Ci.nsIFactory))
4695 throw Cr.NS_ERROR_NOT_IMPLEMENTED;
4697 for (var key in this._objects)
4699 if (cid.equals(
this._objects[key].CID))
4700 return this._objects[key].factory;
4703 throw Cr.NS_ERROR_NO_INTERFACE;
4705 canUnload:
function(compMgr)
4715 CID: Components.ID(
"{54ef6f81-30af-4b1d-ac55-8ba811293e41}"),
4762 var lp =
Cc[
"@mozilla.org/file/local;1"]
4763 .createInstance(
Ci.nsILocalFile);
4764 lp.initWithPath(basePath);
4772 srv.registerDirectory(
"/", lp);
4773 srv.registerContentType(
"sjs",
SJS_TYPE);
4774 srv.identity.setPrimary(
"http",
"localhost", port);
4777 var thread = gThreadManager.currentThread;
4778 while (!srv.isStopped())
4779 thread.processNextEvent(
true);
4782 while (thread.hasPendingEvents())
4783 thread.processNextEvent(
true);
function readBytes(inputStream, count)
function stop(ch, cx, status, data)
nsString encodeURIComponent(const nsString &c)
function makeFactory(ctor)
function defaultIndexHandler(metadata, response)
function ServerIdentity()
function Connection(input, output, server, port, outgoingPort, number)
sbOSDControlService prototype className
function WriteThroughCopier(input, output, observer, context)
SafebrowsingApplicationMod prototype registerSelf
function nsHttpVersion(versionString)
function ServerHandler(server)
for(let i=0;i< aHistory.count;i++)
const WritablePropertyBag
sbDeviceFirmwareAutoCheckForUpdate prototype contractID
sbOSDControlService prototype QueryInterface
function RequestReader(connection)
ui plugin add("draggable","cursor",{start:function(e, ui){var t=$('body');if(t.css("cursor")) ui.options._cursor=t.css("cursor");t.css("cursor", ui.options.cursor);}, stop:function(e, ui){if(ui.options._cursor)$('body').css("cursor", ui.options._cursor);}})
function server(port, basePath)
function toDateString(date)
function NSGetModule(compMgr, fileSpec)
SafebrowsingApplicationMod prototype getClassObject
this _dialogInput val(dateText)
BogusChannel prototype loadGroup
function maybeAddHeaders(file, metadata, response)
function getRootPrefBranch()
function printObj(o, showMembers)
ExtensionSchemeMatcher prototype match
const ConverterInputStream
function NS_ASSERT(cond, msg)
function nsSimpleEnumerator(items)
SimpleArrayEnumerator prototype hasMoreElements
function Response(connection)
const ScriptableInputStream
function notImplemented()
function createHandlerFunc(handler)
function HttpError(code, description)
_getSelectedPageStyle s i
function toInternalPath(path, encoded)
const READER_IN_REQUEST_LINE