function Point2ToPoint3(app) {
function pop(object, key, fallback) {
var value = object[key];
delete object[key];
return value || fallback;
}
return function(env) {
var request = {};
if (env.jsgi && env.version && env.jsgi.version.toString() == "0,3") {
return app(env);
}
// required top level
var required = {
method: "REQUEST_METHOD", // RFC 2616
version: "SERVER_PROTOCOL", // RFC 2616
scheme: "jsgi.url_scheme", // RFC 2616
host: "SERVER_NAME", // RFC 2616
port: "SERVER_PORT", // RFC 2616
scriptName: "SCRIPT_NAME", // RFC 3875: scriptPath?
pathInfo: "PATH_INFO", // RFC 3875: extraPath? Should we normalize /../?
queryString: "QUERY_STRING", // RFC 2616: query?
input: "jsgi.input"
};
for (var key in required) {
request[key] = pop(env, required[key]);
}
request.port = Number(request.port); // always an integer
request.version = request.version // parse, why not?
.split("/")[1] // ignore "HTTP/"
.split(" ")[0] // RFC 2616 allows an extension-version...huh?
.split(";")[0] // RFC 2616 doesn't allow params
.split(".")
.map(function(i) {
return Number(i);
});
// optional top level
var optional = {
authType: "AUTH_TYPE", // authenticationType?
pathTranslated: "PATH_TRANSLATED", // duplicate data, delete instead?
remoteAddr: "REMOTE_ADDR", // remoteAddress?
remoteHost: "REMOTE_HOST",
remoteIdent: "REMOTE_IDENT", // remoteIdentity?
remoteUser: "REMOTE_USER",
serverSoftware: "SERVER_SOFTWARE" // is this ever useful?
};
for (var key in optional) {
if (env[optional[key]]) {
request[key] = pop(env, optional[key]);
}
}
// headers
request.headers = {};
for (var key in env) {
if (key.length > 5 && key.indexOf("HTTP_" == 0)) {
var header = key.substring(5).replace(/_/g, "-").toLowerCase();
request.headers[header] = pop(env, key);
}
}
if (env.CONTENT_TYPE) {
request.headers["content-type"] = Number(pop(env, "CONTENT_TYPE"));
}
if (env.CONTENT_LENGTH) {
request.headers["content-length"] = String(pop(env, "CONTENT_LENGTH"));
}
// jsgi
request.jsgi = {};
delete env["jsgi.version"];
request.jsgi.version = [0, 3];
request.jsgi.errors = pop(env, "jsgi.errors");
request.jsgi.multithread = pop(env, "jsgi.multithread");
request.jsgi.multiprocess = pop(env, "jsgi.multiprocess");
request.jsgi.runonce = pop(env, "jsgi.run_once"); // runOnce?
request.jsgi.async = false; // no 0.2 servers support promises, right?
if (env.GATEWAY_INTERFACE) {
request.jsgi.cgi = env.GATEWAY_INTERFACE
.split("/")[1] // ignore "CGI/"
.split(" ")[0] // ignore anything trailing
.split(";")[0] // RFC 3875 doesn't allow params
.split(".")
.map(function(i) {
return Number(i);
});
delete env.GATEWAY_INTERFACE;
}
// env
// JSGI 0.2 doesn't require an iterable env so delete everything
// we know about and just stick everything else in request.env
request.env = env;
// TODO should we lint for changes like !scriptName.endsWith("/")?
return app(request);
}
}