Comparing version 0.2.0 to 0.3.1
@@ -96,3 +96,3 @@ const rp = require("request-promise"); | ||
} catch(e) { | ||
assert(e.response.body == "Internal error" && e.statusCode == 500); | ||
assert(e.statusCode == 500); | ||
ok = true; | ||
@@ -107,3 +107,3 @@ } | ||
} catch(e) { | ||
assert(e.response.body == "Internal error" && e.statusCode == 500); | ||
assert(e.statusCode == 500); | ||
ok = true; | ||
@@ -121,3 +121,3 @@ } | ||
t2 = Date.now(); | ||
assert(e.response.body == "Internal error" && e.statusCode == 500); | ||
assert(e.statusCode == 500); | ||
if(Math.abs((t2 - t1) - 100) > 20) { | ||
@@ -130,2 +130,7 @@ throw new Error("Incorrect delay time"); | ||
/* | ||
console.log("Testing URL params"); | ||
assert((await rp.get(REMOTE + "/echo_params/hello/world")) == "hello world"); | ||
*/ | ||
console.log("Testing template rendering"); | ||
@@ -132,0 +137,0 @@ assert((await rp.get(REMOTE + "/template/" + template_param)) == expected_rendered_template); |
const lib = require("../lib.js"); | ||
const path = require("path"); | ||
let app = new lib.Ice({ | ||
let app = new lib.Application({ | ||
max_request_body_size: 100000 | ||
@@ -15,3 +15,3 @@ }); | ||
`.trim(); | ||
app.add_template("test.html", template); | ||
app.addTemplate("test.html", template); | ||
@@ -22,44 +22,44 @@ let my_path = path.join(__dirname, "server.js"); | ||
app.get("/get/sync", req => { | ||
return "OK"; | ||
app.get("/get/sync", (req, resp) => { | ||
resp.body("OK"); | ||
}); | ||
app.get("/get/async_immediate", async req => { | ||
return "OK"; | ||
app.get("/get/async_immediate", async (req, resp) => { | ||
resp.body("OK"); | ||
}); | ||
app.get("/get/async_delayed/:time", async req => { | ||
app.get("/get/async_delayed/:time", async (req, resp) => { | ||
let t = parseInt(req.params.time); | ||
await sleep(t); | ||
return "OK"; | ||
resp.body("OK"); | ||
}); | ||
app.post("/post/echo/raw", req => { | ||
return req.body(); | ||
app.post("/post/echo/raw", (req, resp) => { | ||
resp.body(req.body()); | ||
}); | ||
app.post("/post/echo/json", req => { | ||
return lib.Response.json(req.json()); | ||
app.post("/post/echo/json", (req, resp) => { | ||
resp.json(req.json()); | ||
}); | ||
app.post("/post/echo/form_to_json", req => { | ||
return lib.Response.json(req.form()); | ||
app.post("/post/echo/form_to_json", (req, resp) => { | ||
resp.json(req.form()); | ||
}); | ||
app.use("/session", new lib.Flag("init_session")); | ||
app.get("/session", req => { | ||
app.get("/session", (req, resp) => { | ||
let count = req.session.count || "0"; | ||
req.session.count = "" + (parseInt(count) + 1); | ||
return count.toString(); | ||
resp.body(count.toString()); | ||
}); | ||
app.get("/exception/sync", req => { | ||
app.get("/exception/sync", (req, resp) => { | ||
throw new Error("Sync exception"); | ||
}); | ||
app.get("/exception/async_immediate", async req => { | ||
app.get("/exception/async_immediate", async (req, resp) => { | ||
throw new Error("Async exception (immediate)"); | ||
}); | ||
app.get("/exception/async_delayed/:time", async req => { | ||
app.get("/exception/async_delayed/:time", async (req, resp) => { | ||
let t = parseInt(req.params.time); | ||
@@ -70,13 +70,13 @@ await sleep(t); | ||
app.get("/template/:param", req => { | ||
return new lib.Response({ | ||
template_name: "test.html", | ||
template_params: { | ||
param: req.params.param | ||
} | ||
app.get("/echo_params/:a/:b", (req, resp) => resp.body(req.params.a + " " + req.params.b)); | ||
app.get("/template/:param", (req, resp) => { | ||
resp.renderTemplate("test.html", { | ||
param: req.params.param | ||
}); | ||
}); | ||
app.get("/code", req => lib.Response.file(my_path)); | ||
app.get("/code", (req, resp) => resp.file(my_path)); | ||
app.prepare(); | ||
app.listen("127.0.0.1:5329"); |
107
lib_test.js
@@ -1,96 +0,43 @@ | ||
const lib = require("./lib.js"); | ||
const fs = require("fs"); | ||
const ice = require("./lib.js"); | ||
let app = new lib.Ice({ | ||
disable_request_logging: true, | ||
session_timeout_ms: 10000 | ||
const app = new ice.Application({ | ||
disable_request_logging: true | ||
}); | ||
function sleep(ms) { | ||
return new Promise(cb => setTimeout(() => cb(), ms)); | ||
} | ||
let template = ` | ||
<p>Template OK: {{ param }}</p> | ||
`.trim(); | ||
app.use("/static/", lib.static(".")); | ||
app.loadCervusModule("test", fs.readFileSync("test_module.bc")); | ||
app.get("/", req => "Root"); | ||
app.addTemplate("test.html", template); | ||
app.get("/hello_world", req => { | ||
return "Hello world!"; | ||
app.route("GET", "/hello_world", (req, resp) => { | ||
resp.body("Hello world!"); | ||
}); | ||
app.use("/time", req => { | ||
console.log(req); | ||
app.route("GET", "/echo_param/:p", (req, resp) => { | ||
resp.body(req.params.p); | ||
}); | ||
app.route("GET", "/request_id", (req, resp) => resp.body(req.custom.request_id)); | ||
app.route(["GET", "POST"], "/time", req => { | ||
let body = req.json(); | ||
let time; | ||
if(body && body.time) { | ||
time = body.time; | ||
} else { | ||
time = Date.now(); | ||
} | ||
return lib.Response.json({ | ||
formatted: new Date(time).toLocaleString() | ||
}); | ||
app.route("GET", "/hello_world_detached", (req, resp) => { | ||
resp.detach(); | ||
setImmediate(() => resp.body("Hello world! (Detached)").send()); | ||
}); | ||
app.use("/session", new lib.Flag("init_session")); | ||
app.get("/session", req => { | ||
let count = req.session.count || "0"; | ||
req.session.count = "" + (parseInt(count) + 1); | ||
return count.toString(); | ||
}); | ||
app.post("/form_to_json", req => { | ||
return lib.Response.json(req.form()); | ||
}); | ||
app.get("/cookies", req => { | ||
return new lib.Response({ | ||
cookies: { | ||
a: 1, | ||
b: 2 | ||
} | ||
app.route("GET", "/hello_world_stream", (req, resp) => { | ||
resp.stream(stream => { | ||
stream.write(Buffer.from("Hello world! (stream)")); | ||
stream.close(); | ||
}); | ||
}); | ||
app.get("/delay/:time", async req => { | ||
await sleep(parseInt(req.params.time)); | ||
return "OK"; | ||
}); | ||
app.route("GET", "/leak_request", (req, resp) => resp.detach()); | ||
app.get("/exception/sync", req => { | ||
throw new Error("Sync exception"); | ||
}); | ||
app.route("GET", "/render_template", (req, resp) => resp.renderTemplate("test.html", { | ||
param: new Date().toLocaleString() | ||
})); | ||
app.get("/exception/async/:delay", async req => { | ||
let delay = parseInt(req.params.delay); | ||
if(delay) await sleep(delay); | ||
throw new Error("Async exception"); | ||
}); | ||
app.get("/two_params/:a/:b", req => { | ||
return req.params.a + " " + req.params.b; | ||
}); | ||
let test_tpl = app.add_template("test.html", `Hello world! | ||
{{ date }} | ||
`); | ||
app.get("/template/render", req => { | ||
return new lib.Response({ | ||
template_name: "test.html", | ||
template_params: { | ||
date: new Date().toLocaleString() | ||
} | ||
}); | ||
}); | ||
app.get("/stats", req => { | ||
console.log(req.get_stats()); | ||
return lib.Response.json(req.get_stats(true)); | ||
}); | ||
app.listen("127.0.0.1:1122"); | ||
app.prepare(); | ||
app.listen("127.0.0.1:1479"); |
538
lib.js
const core = require("./build/Release/ice_node_core"); | ||
const stat = require("./stat.js"); | ||
module.exports.static = require("./static.js"); | ||
module.exports.Ice = Ice; | ||
function Ice(cfg) { | ||
if (!cfg) cfg = {}; | ||
module.exports.Application = Application; | ||
this.server = null; | ||
this.routes = []; | ||
function Application(cfg) { | ||
if(!(this instanceof Application)) { | ||
return new Application(...arguments); | ||
} | ||
if(!cfg) cfg = {}; | ||
this.server = new core.Server(cfg); | ||
this.routes = {}; | ||
this.flags = []; | ||
this.middlewares = []; | ||
this.templates = {}; | ||
this.config = { | ||
disable_request_logging: cfg.disable_request_logging || false, | ||
session_timeout_ms: cfg.session_timeout_ms || 600000, | ||
session_cookie: cfg.session_cookie || "ICE_SESSION_ID", | ||
max_request_body_size: cfg.max_request_body_size || null | ||
}; | ||
this.prepared = false; | ||
} | ||
Ice.prototype.route = function (methods, p, handler) { | ||
if (typeof (methods) == "string") methods = [methods]; | ||
if (!(methods instanceof Array)) throw new Error("The first parameter to `route` must be a string or array of strings."); | ||
if (typeof (p) != "string") throw new Error("Path must be a string"); | ||
if (typeof (handler) != "function") throw new Error("Handler must be a function"); | ||
methods = methods.map(v => v.toUpperCase()); | ||
let mm = {}; | ||
for (const v of methods) { | ||
mm[v] = true; | ||
} | ||
Application.prototype.route = function(methods, p, fn) { | ||
if(typeof(methods) == "string") methods = [ methods ]; | ||
let param_mappings = p.split("/").filter(v => v).map(v => v.startsWith(":") ? v.substr(1) : null); | ||
let self = this; | ||
this.routes.push({ | ||
path: p, | ||
methods: methods, | ||
param_mappings: param_mappings, | ||
handler: function (req) { | ||
if (!mm[req.method]) { | ||
return new Response({ | ||
status: 405, | ||
body: "Method not allowed" | ||
}).send(self, req.call_info); | ||
} | ||
let ok = r => { | ||
if (r instanceof Response) { | ||
r.send(self, req.call_info); | ||
} else { | ||
try { | ||
new Response({ | ||
body: r | ||
}).send(self, req.call_info); | ||
} catch (e) { | ||
err(e); | ||
let target; | ||
if(param_mappings.filter(v => v).length) { | ||
target = (req, resp) => { | ||
try { | ||
let params = {}; | ||
req.url.split("/").filter(v => v).map((v, index) => [param_mappings[index], v]).forEach(p => { | ||
if (p[0]) { | ||
params[p[0]] = p[1]; | ||
} | ||
} | ||
}; | ||
let err = e => { | ||
console.log(e); | ||
new Response({ | ||
status: 500, | ||
body: "Internal error" | ||
}).send(self, req.call_info); | ||
}; | ||
try { | ||
let r = handler(req); | ||
if (r && r.then) { | ||
r.then(ok, err); | ||
} else { | ||
ok(r); | ||
} | ||
}); | ||
req.params = params; | ||
} catch (e) { | ||
err(e); | ||
req.params = {}; | ||
} | ||
} | ||
return fn(req, resp); | ||
}; | ||
} else { | ||
target = fn; | ||
} | ||
methods.map(v => v.toUpperCase()).forEach(m => { | ||
this.routes[m + " " + p] = target; | ||
}); | ||
return this; | ||
} | ||
Ice.prototype.get = function (p, handler) { | ||
return this.route(["HEAD", "GET"], p, handler); | ||
Application.prototype.get = function(p, fn) { | ||
return this.route("GET", p, fn); | ||
} | ||
Ice.prototype.post = function (p, handler) { | ||
return this.route("POST", p, handler); | ||
Application.prototype.post = function(p, fn) { | ||
this.use(p, new Flag("read_body")); | ||
return this.route("POST", p, fn); | ||
} | ||
Ice.prototype.put = function (p, handler) { | ||
return this.route("PUT", p, handler); | ||
Application.prototype.put = function(p, fn) { | ||
this.use(p, new Flag("read_body")); | ||
return this.route("PUT", p, fn); | ||
} | ||
Ice.prototype.delete = function (p, handler) { | ||
return this.route("DELETE", p, handler); | ||
Application.prototype.delete = function(p, fn) { | ||
return this.route("DELETE", p, fn); | ||
} | ||
Ice.prototype.use = function (p, handler) { | ||
if (typeof (p) != "string") throw new Error("Prefix must be a string"); | ||
if (typeof (handler) != "function" && !(handler instanceof Flag)) throw new Error("Handler must be a function or flag"); | ||
Application.prototype.use = function(p, fn) { | ||
if(fn instanceof Flag) { | ||
this.flags.push({ | ||
prefix: p, | ||
name: fn.name | ||
}); | ||
} else { | ||
this.middlewares.push({ | ||
prefix: p, | ||
handler: fn | ||
}); | ||
} | ||
return this; | ||
} | ||
this.middlewares.push({ | ||
prefix: p, | ||
handler: handler | ||
}); | ||
Application.prototype.addTemplate = function(name, content) { | ||
this.server.addTemplate(name, content); | ||
return this; | ||
} | ||
Ice.prototype.add_template = function (name, content) { | ||
if (typeof (name) != "string") throw new Error("Name must be a string"); | ||
if (typeof (content) != "string") throw new Error("Content must be a string"); | ||
this.templates[name] = content; | ||
Application.prototype.loadCervusModule = function(name, data) { | ||
this.server.loadCervusModule(name, data); | ||
} | ||
Ice.prototype.listen = function (addr) { | ||
if (typeof (addr) != "string") throw new Error("Address must be a string"); | ||
if (this.server !== null) { | ||
throw new Error("Already listening"); | ||
Application.prototype.prepare = function() { | ||
if(this.prepared) { | ||
throw new Error("Application.prepare: Already prepared"); | ||
} | ||
this.server = core.create_server(); | ||
core.set_session_timeout_ms(this.server, this.config.session_timeout_ms); | ||
core.set_session_cookie_name(this.server, this.config.session_cookie); | ||
if(this.config.max_request_body_size) { | ||
core.set_max_request_body_size(this.server, this.config.max_request_body_size); | ||
} | ||
if(this.config.disable_request_logging) { | ||
core.disable_request_logging(this.server); | ||
} | ||
let routes = {}; | ||
for (const k in this.templates) { | ||
try { | ||
core.add_template(this.server, k, this.templates[k]); | ||
} catch (e) { | ||
console.log("Warning: Unable to add template: " + k); | ||
delete this.templates[k]; | ||
} | ||
for(const k in this.routes) { | ||
const p = k.split(" ")[1]; | ||
let mws = this.middlewares.filter(v => p.startsWith(v.prefix)); | ||
if(!routes[p]) routes[p] = {}; | ||
routes[p][k.split(" ")[0]] = generateEndpointHandler(mws, this.routes[k]); | ||
} | ||
let self = this; | ||
for(const p in routes) { | ||
let methodRoutes = routes[p]; | ||
let flags = this.flags.filter(v => p.startsWith(v.prefix)).map(v => v.name); | ||
for (const rt of this.routes) { | ||
let flags = []; | ||
if (rt.methods.indexOf("POST") != -1 || rt.methods.indexOf("PUT") != -1) { | ||
flags.push("read_body"); | ||
} | ||
let mws = this.middlewares.filter(v => rt.path.startsWith(v.prefix)); | ||
let flag_mws = mws.filter(v => v.handler instanceof Flag); | ||
mws = mws.filter(v => typeof (v.handler) == "function"); | ||
for (const f of flag_mws) { | ||
flags.push(f.handler.name); | ||
} | ||
core.add_endpoint(this.server, rt.path, async call_info => { | ||
let req = new Request(self, rt, call_info); | ||
for (const mw of mws) { | ||
try { | ||
await mw.handler(req, mw); | ||
} catch (e) { | ||
if (e instanceof Response) { | ||
e.send(self, call_info); | ||
} else { | ||
console.log(e); | ||
new Response({ | ||
status: 500, | ||
body: "Internal error" | ||
}).send(self, call_info); | ||
} | ||
return; | ||
} | ||
this.server.route(p, function(req) { | ||
let rt = methodRoutes[req.method()]; | ||
if(rt) { | ||
rt(req); | ||
} else { | ||
let resp = req.createResponse(); | ||
resp.status(405); | ||
resp.send(); | ||
} | ||
rt.handler(req); | ||
}, flags); | ||
} | ||
core.add_endpoint(this.server, "", call_info => this.not_found_handler(call_info)); | ||
core.listen(this.server, addr); | ||
}; | ||
this.server.route("", generateEndpointHandler(this.middlewares, (req, resp) => resp.status(404))); | ||
Ice.prototype.not_found_handler = async function (call_info) { | ||
let req = new Request(this, null, call_info); | ||
for (const mw of this.middlewares.filter(v => typeof(v.handler) == "function")) { | ||
if(req.url.startsWith(mw.prefix)) { | ||
try { | ||
await mw.handler(req, mw); | ||
} catch (e) { | ||
if (e instanceof Response) { | ||
e.send(this, call_info); | ||
} else { | ||
console.log(e); | ||
new Response({ | ||
status: 500, | ||
body: "Internal error" | ||
}).send(this, call_info); | ||
} | ||
return; | ||
} | ||
} | ||
this.prepared = true; | ||
this.route = null; | ||
this.use = null; | ||
} | ||
Application.prototype.listen = function(addr) { | ||
if(!this.prepared) { | ||
throw new Error("Not prepared"); | ||
} | ||
return new Response({ | ||
status: 404, | ||
body: "Not found" | ||
}).send(this, call_info); | ||
this.server.listen(addr); | ||
} | ||
module.exports.Request = Request; | ||
function Request(server, route, call_info) { | ||
this.server = server; | ||
this.route = route; | ||
this.call_info = call_info; | ||
//module.exports.Request = Request; | ||
let req_info = core.get_request_info(call_info); | ||
this.headers = req_info.headers; | ||
this.uri = req_info.uri; | ||
this.url = req_info.uri.split("?")[0]; | ||
this.remote_addr = req_info.remote_addr; | ||
this.method = req_info.method; | ||
function Request(inst) { | ||
if(!(this instanceof Request)) { | ||
return new Request(...arguments); | ||
} | ||
this.host = req_info.headers.host; | ||
this.inst = inst; | ||
this.cache = { | ||
uri: null, | ||
url: null, | ||
headers: null, | ||
cookies: null | ||
}; | ||
this.params = {}; | ||
this.session = new Proxy({}, { | ||
get: (t, k) => core.get_request_session_item(this.call_info, k), | ||
set: (t, k, v) => core.set_request_session_item(this.call_info, k, v) | ||
get: (t, k) => this.inst.sessionItem(k), | ||
set: (t, k, v) => this.inst.sessionItem(k, v) | ||
}); | ||
this._cookies = {}; | ||
this._params = null; | ||
let self = this; | ||
this.cookies = new Proxy({}, { | ||
get: (t, k) => { | ||
if (!self._cookies[k]) { | ||
self._cookies[k] = core.get_request_cookie(self.call_info, k); | ||
} | ||
return self._cookies[k]; | ||
} | ||
this.custom = new Proxy({}, { | ||
get: (t, k) => this.inst.customProperty(k) | ||
}); | ||
} | ||
this.params = new Proxy({}, { | ||
get: (t, k) => { | ||
if (!self._params) { | ||
try { | ||
let params = {}; | ||
self.url.split("/").filter(v => v).map((v, index) => [self.route.param_mappings[index], v]).forEach(p => { | ||
if (p[0]) { | ||
params[p[0]] = p[1]; | ||
} | ||
}); | ||
self._params = params; | ||
} catch (e) { | ||
self._params = {}; | ||
} | ||
} | ||
return self._params[k]; | ||
} | ||
}); | ||
Request.prototype.createResponse = function () { | ||
return new Response(this); | ||
} | ||
Request.prototype.body = function () { | ||
return core.get_request_body(this.call_info); | ||
Request.prototype.body = function() { | ||
return this.inst.body(); | ||
} | ||
Request.prototype.json = function () { | ||
Request.prototype.json = function() { | ||
let body = this.body(); | ||
if (!body) return null; | ||
try { | ||
return JSON.parse(body.toString()); | ||
} catch (e) { | ||
throw new Error("Request body is not valid JSON"); | ||
if(body) { | ||
return JSON.parse(body); | ||
} else { | ||
return null; | ||
} | ||
@@ -293,113 +192,144 @@ } | ||
Request.prototype.get_stats = function(load_system_stats = false) { | ||
if(load_system_stats) { | ||
stat.update_system_stats(this); | ||
Object.defineProperty(Request.prototype, "uri", { | ||
get: function() { | ||
return this.cache.uri || (this.cache.uri = this.inst.uri()) | ||
} | ||
return JSON.parse(core.get_stats_from_request(this.call_info)); | ||
} | ||
}); | ||
Request.prototype.set_custom_stat = function(k, v) { | ||
core.set_custom_stat(this.call_info, k, v); | ||
} | ||
Object.defineProperty(Request.prototype, "url", { | ||
get: function() { | ||
return this.cache.url || (this.cache.url = this.uri.split("?")[0]) | ||
} | ||
}); | ||
module.exports.Response = Response; | ||
function Response({ status = 200, headers = {}, cookies = {}, body = "", file = null, template_name = null, template_params = {} }) { | ||
// Do strict checks here because errors in Response.send() may cause memory leak & deadlock. | ||
Object.defineProperty(Request.prototype, "headers", { | ||
get: function() { | ||
return this.cache.headers || (this.cache.headers = this.inst.headers()) | ||
} | ||
}); | ||
if (typeof (status) != "number" || status < 100 || status >= 600) { | ||
throw new Error("Invalid status"); | ||
Object.defineProperty(Request.prototype, "cookies", { | ||
get: function() { | ||
return this.cache.cookies || (this.cache.cookies = this.inst.cookies()) | ||
} | ||
this.status = Math.floor(status); | ||
}); | ||
if (!headers || typeof (headers) != "object") { | ||
throw new Error("Invalid headers"); | ||
//module.exports.Response = Response; | ||
function Response(req) { | ||
if(!(this instanceof Response)) { | ||
return new Response(...arguments); | ||
} | ||
let transformed_headers = {}; | ||
for (const k in headers) { | ||
transformed_headers[k] = "" + headers[k]; | ||
} | ||
this.headers = transformed_headers; | ||
let transformed_cookies = {}; | ||
for (const k in cookies) { | ||
transformed_cookies[k] = "" + cookies[k]; | ||
if(!(req instanceof Request)) { | ||
throw new Error("Request required"); | ||
} | ||
this.cookies = transformed_cookies; | ||
this.body = null; | ||
this.template_name = null; | ||
this.file = null; | ||
this.inst = req.inst.createResponse(); | ||
this.detached = false; | ||
} | ||
if (body) { | ||
if (body instanceof Buffer) { | ||
this.body = body; | ||
} else { | ||
this.body = Buffer.from(body); | ||
} | ||
if (!this.body) throw new Error("Invalid body"); | ||
} else if (typeof (template_name) == "string") { | ||
this.template_name = template_name; | ||
if (!template_params || typeof (template_params) != "object") { | ||
throw new Error("Invalid template params"); | ||
} | ||
this.template_params = template_params; | ||
} else if (typeof (file) == "string") { | ||
this.file = file; | ||
} else { | ||
throw new Error("No valid body or template provided"); | ||
Response.from = function(req, data) { | ||
if(typeof(data) == "string" || data instanceof Buffer) { | ||
return new Response(req).body(data); | ||
} | ||
Object.freeze(this); | ||
throw new Error("Unable to convert data into Response"); | ||
} | ||
Response.prototype.send = function (server, call_info) { | ||
if (!(server instanceof Ice)) { | ||
console.log(server); | ||
throw new Error("Expecting a server instance. Got it."); | ||
Response.prototype.body = function(data) { | ||
if(!(data instanceof Buffer)) { | ||
data = Buffer.from(data); | ||
} | ||
let resp = core.create_response(); | ||
core.set_response_status(resp, this.status); | ||
for (const k in this.headers) { | ||
core.set_response_header(resp, k, this.headers[k]); | ||
} | ||
for (const k in this.cookies) { | ||
core.set_response_cookie(resp, k, this.cookies[k]); | ||
} | ||
if (this.body) { | ||
core.set_response_body(resp, this.body); | ||
} else if (this.template_name) { | ||
this.inst.body(data); | ||
return this; | ||
} | ||
Response.prototype.json = function(data) { | ||
return this.body(JSON.stringify(data)); | ||
} | ||
Response.prototype.file = function(p) { | ||
this.inst.file(p); | ||
return this; | ||
} | ||
Response.prototype.status = function(code) { | ||
this.inst.status(code); | ||
return this; | ||
} | ||
Response.prototype.header = function(k, v) { | ||
this.inst.header(k, v); | ||
return this; | ||
} | ||
Response.prototype.cookie = function(k, v) { | ||
this.inst.cookie(k, v); | ||
return this; | ||
} | ||
Response.prototype.renderTemplate = function(name, data) { | ||
this.inst.renderTemplate(name, JSON.stringify(data)); | ||
return this; | ||
} | ||
Response.prototype.stream = function(cb) { | ||
const stream = this.inst.stream(); | ||
setImmediate(() => cb(stream)); | ||
return this; | ||
} | ||
Response.prototype.send = function() { | ||
this.inst.send(); | ||
} | ||
Response.prototype.detach = function() { | ||
this.detached = true; | ||
} | ||
function generateEndpointHandler(mws, fn) { | ||
return async function(req) { | ||
req = new Request(req); | ||
let resp = req.createResponse(); | ||
for(const mw of mws) { | ||
// For dynamic dispatch | ||
if(!req.uri.startsWith(mw.prefix)) { | ||
continue; | ||
} | ||
try { | ||
// An exception from a middleware leads to a normal termination of the flow. | ||
await mw.handler(req, resp, mw); | ||
} catch(e) { | ||
resp.send(); | ||
return; | ||
} | ||
} | ||
try { | ||
core.render_template(call_info, resp, this.template_name, JSON.stringify(this.template_params)); | ||
} catch (e) { | ||
// An exception from an endpoint handler leads to an abnormal termination. | ||
await fn(req, resp); | ||
} catch(e) { | ||
console.log(e); | ||
resp.status(500).send(); | ||
return; | ||
} | ||
} else if (this.file) { | ||
core.set_response_file(resp, this.file); | ||
if(!resp.detached) resp.send(); | ||
} | ||
core.fire_callback(call_info, resp); | ||
}; | ||
Response.json = function (data) { | ||
return new Response({ | ||
headers: { | ||
"Content-Type": "application/json" | ||
}, | ||
body: JSON.stringify(data) | ||
}); | ||
} | ||
Response.file = function(path) { | ||
return new Response({ | ||
file: path | ||
}); | ||
} | ||
module.exports.Flag = Flag; | ||
function Flag(name) { | ||
if (typeof (name) != "string") { | ||
throw new Error("Flag name must be a string"); | ||
if(!(this instanceof Flag)) { | ||
return new Flag(...arguments); | ||
} | ||
this.name = name; | ||
Object.freeze(this); | ||
} | ||
module.exports.static = require("./static.js"); |
{ | ||
"name": "ice-node", | ||
"version": "0.2.0", | ||
"version": "0.3.1", | ||
"description": "Bindings for the Ice Web Framework", | ||
@@ -5,0 +5,0 @@ "main": "lib.js", |
@@ -6,3 +6,3 @@ const path = require("path"); | ||
p = path.resolve(p); | ||
return function (req, mw) { | ||
return function (req, resp, mw) { | ||
let url_path = req.url.substr(mw.prefix.length); | ||
@@ -15,10 +15,9 @@ while(url_path.startsWith("/")) { | ||
if(!target.startsWith(p + "/")) { | ||
throw new lib.Response({ | ||
status: 403, | ||
body: "Illegal request" | ||
}); | ||
resp.status(403).body("Illegal request"); | ||
throw null; | ||
} | ||
throw lib.Response.file(target); | ||
resp.file(target); | ||
throw null; | ||
} | ||
} |
60
test.js
const core = require("./build/Release/ice_node_core"); | ||
let server = core.create_server(); | ||
console.log(server); | ||
core.add_endpoint(server, "", call_info => { | ||
let resp = core.create_response(); | ||
core.set_response_status(resp, 404); | ||
core.set_response_body(resp, Buffer.from("Not found")); | ||
core.fire_callback(call_info, resp); | ||
let server = new core.Server({ | ||
disable_request_logging: true | ||
}); | ||
core.add_endpoint(server, "/hello_world", call_info => { | ||
core.get_request_info(call_info); | ||
let resp = core.create_response(); | ||
core.set_response_body(resp, Buffer.from("Hello world!")); | ||
core.fire_callback(call_info, resp); | ||
server.route("", req => { | ||
let resp = req.createResponse(); | ||
resp.status(404); | ||
resp.body(Buffer.from("Not found")); | ||
resp.send(); | ||
}); | ||
core.add_endpoint(server, "/delayed", call_info => { | ||
setTimeout(() => { | ||
let resp = core.create_response(); | ||
core.fire_callback(call_info, resp); | ||
}, 10); | ||
server.route("/hello_world", req => { | ||
let resp = req.createResponse(); | ||
resp.body(Buffer.from("Hello world!")); | ||
resp.send(); | ||
}); | ||
core.add_endpoint(server, "/echo", call_info => { | ||
let info = core.get_request_info(call_info); | ||
let body = core.get_request_body(call_info); | ||
let r = ` | ||
Remote address: ${info.remote_addr} | ||
Request URI: ${info.uri} | ||
Request method: ${info.method} | ||
Request body: | ||
${body} | ||
`.trim() + "\n"; | ||
let resp = core.create_response(); | ||
core.set_response_header(resp, "Content-Type", "text/plain"); | ||
core.set_response_body(resp, Buffer.from(r)); | ||
core.fire_callback(call_info, resp); | ||
}, ["read_body"]) | ||
core.listen(server, "127.0.0.1:1122"); | ||
server.route("/leak_request", req => { | ||
}); | ||
server.route("/leak_response", req => { | ||
req.createResponse(); | ||
}); | ||
server.route("/stream", req => { | ||
let resp = req.createResponse(); | ||
let stream = resp.stream(); | ||
resp.send(); | ||
stream.write(Buffer.from("Hello world! (Stream)")); | ||
stream.close(); | ||
}) | ||
server.listen("127.0.0.1:9132"); |
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
Major refactor
Supply chain riskPackage has recently undergone a major refactor. It may be unstable or indicate significant internal changes. Use caution when updating to versions that include significant changes.
Found 1 instance in 1 package
Mixed license
License(Experimental) Package contains multiple licenses.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
Mixed license
License(Experimental) Package contains multiple licenses.
Found 1 instance in 1 package
1214097
63
1829
2
2