Huge News!Announcing our $40M Series B led by Abstract Ventures.Learn More
Socket
Sign inDemoInstall
Socket

web

Package Overview
Dependencies
Maintainers
1
Versions
3
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

web - npm Package Compare versions

Comparing version 0.0.1 to 0.0.2

2

package.json
{
"name": "web",
"version": "0.0.1",
"version": "0.0.2",
"description": "A small and fast web/http library for nodejs. (replaces the built-in http module)",

@@ -5,0 +5,0 @@ "main": "web.js",

@@ -54,5 +54,5 @@ # Web

// request.method is "GET", "POST", "PUT", etc..
// request.url is { pathname: "/foo/bar", query: "and=stuff" ...}
// request is still the request stream, but I'm thinking of moving
// it to a .body property.
// request.url is the raw request path "/foo/bar?and=stuff"
// request.headers is the raw array of request headers.
// request.body is the request body as a stream.

@@ -72,1 +72,122 @@ // respond(code, headers, body) is a function

## Built-in Middleware System
Unlike the `http` module, `web` makes it trivial to stack app layers. There is no need for a library because all that's needed is a simple function. Any function that implements the `(request, respond)` interface is a valid web application.
### Basic Logger Layer
Suppose you wanted to add a layer that logged all request and the response code the app gave them.
This can be done simple as:
```js
function logger(app) {
// Any per-layer startup logic would go here.
// We only need the app closure reference, so there is nothing else to do
return function(req, res) {
// Per request logic during the inward path would go here. Since
// we want to wait till the response code is generated, there is nothing
// to do.
// Forward to the next layer inward.
app(req, function (code, headers, body) {
// Here we've intercepted the response function and can do stuff on the
// way back out of the layers. We want to log the request and response.
console.log(req.method + " " + req.url.path + " " + code);
// Forward to the layers outward.
res(code, headers, body);
});
};
}
// Then to use this layer, we just wrap out app.
app = logger(app);
```
As you can see, there are places to do logic at several steps in a request and server lifetime.
## Request Object
The request object contains the following properties.
### req.method
This is the HTTP method in the request. It can have values like "GET", "POST", "PUT", "DELETE", and any other value the node http parser supports.
### req.headers
This is a hash of the headers with keys lowercases for easy access.
It can be used as:
```js
if (req.headers["content-type"] === "application/json") { ... }
```
### req.url
This is the result of node's url.parse on the http request url.
`req.url.path` contains the original raw string if desired.
`req.url.pathname` is the path alone without query strings.
### req.versionMajor, req.versionMinor
These two properties tell you the version of the http request. They are usually either (1, 0) or (1, 1) for HTTP 1.0 and HTTP 1.1.
### req.shouldKeepAlive
This is a hint set by node's http parser to tell the middleware if it should
keepalive the connection.
### req.upgrade
This is another hint set by node's http parser. It's true for upgrade request like websocket connections.
### req.body
This property is set by the web library. It's a readable node stream for the request body.
### req.rawHeaders
This is a raw array of alternating key/value pairs. For example, the headers from a curl request look like:
```js
req.rawHeaders = [
'User-Agent', 'curl/7.26.0',
'Host', 'localhost:8080',
'Accept', '*/*' ]
```
## Post response processing.
The built-in response function does a bit of post-processing after your app is
done to help your app be a proper http server. These post-processing filters can be configured in the socketHandler function's options argument.
### options.autoDate = true
This options adds a `Date` header with the current date as required by the HTTP spec if your response does not have a `Date` header.
### options.autoServer = "node.js " + process.version
Adds a `Server` header with the running version of node if you don't have a `Server` header. Set to some falsy value to disable or set to a new string to replace.
### options.autoContentLength = true
If your body is a known size (not streaming) and you leave out the `Content-Length` header, this will add one for you.
### options.autoChunked = true
If you leave out a `Content-Length` header and your body is streaming, it will replace your stream with a chunked encoded stream and set the proper `Transfer-Encoding: chunked` header for you.
### options.autoConnection = true
This will try to detect what the `Connection` header should be. Usually either `close` or `keep-alive`. Also it will update `req.shouldKeepAlive` which controls the tcp level connection behavior.

@@ -1,40 +0,12 @@

var middle = require('./middle');
var fs = require('fs');
function app(req, res) {
var isHead;
var method = req.method;
if (method === "HEAD") {
method = "GET";
isHead = true;
if (req.method === "GET" && req.url.path === "/") {
res(200, { "Content-Type": "text/plain" }, "Hello World\n");
}
if (!method === "GET") return res(404, {}, "");
// fs.open(__filename, "r", function (err, fd) {
// if (err) throw err;
// fs.fstat(fd, function (err, stat) {
// if (err) throw err;
// var input;
// if (isHead) {
// fs.close(fd);
// }
// else {
// input = fs.createReadStream(null, {fd:fd});
// }
// res(200, {
// "ETag": '"' + stat.ino.toString(36) + "-" + stat.size.toString(36) + "-" + stat.mtime.valueOf().toString(36) + '"',
// "Content-Type": "application/javascript",
// "Content-Length": stat.size
// }, input);
// });
// });
res(200, {
"Content-Type": "text/plain",
}, "Hello World\n");
else {
res(404, {}, "");
}
}
app = middle.autoHeaders(app);
app = middle.log(app);
var server = require('net').createServer(require('./web').socketHandler(app));

@@ -41,0 +13,0 @@ server.listen(8080, function () {

var HTTPParser = process.binding("http_parser").HTTPParser;
var Stream = require('stream').Stream;
var urlParse = require('url').parse;

@@ -59,3 +60,16 @@ var STATUS_CODES = {

exports.socketHandler = function (app) {
var defaults = {
autoDate: true,
autoServer: "node.js " + process.version,
autoContentLength: true,
autoChunked: true,
autoConnection: true,
};
exports.socketHandler = function (app, options) {
// Mix the options with the default config.
var config = Object.create(defaults);
for (var key in options) {
config[key] = options[key];
}
return function (client) {

@@ -65,40 +79,112 @@ var parser = new HTTPParser(HTTPParser.REQUEST);

parser.onHeadersComplete = function (info) {
info.__proto__ = Stream.prototype;
Stream.call(info);
req = info;
req.readable = true;
app(req, function (statusCode, headers, body) {
var reasonPhrase = STATUS_CODES[statusCode];
if (!reasonPhrase) {
throw new Error("Invalid response code " + statusCode);
function res(statusCode, headers, body) {
var hasContentLength, hasTransferEncoding, hasDate, hasServer;
for (var key in headers) {
switch (key.toLowerCase()) {
case "date": hasDate = true; continue;
case "server": hasServer = true; continue;
case "content-length": hasContentLength = true; continue;
case "transfer-encoding": hasTransferEncoding = true; continue;
}
var head = "HTTP/1.1 " + statusCode + " " + reasonPhrase + "\r\n";
for (var key in headers) {
head += key + ": " + headers[key] + "\r\n";
}
if (!hasDate && config.autoDate) {
headers["Date"] = (new Date).toUTCString();
}
if (!hasServer && config.autoServer) {
headers["Server"] = config.autoServer;
}
var isStreaming = body && typeof body === "object" && typeof body.pipe === "function";
if (body && !hasContentLength && !hasTransferEncoding) {
if (!isStreaming && config.autoContentLength) {
body += "";
headers["Content-Length"] = Buffer.byteLength(body);
hasContentLength = true;
}
head += "\r\n";
else if (config.autoChunked) {
headers["Transfer-Encoding"] = "chunked";
hasTransferEncoding = true;
var originalBody = body;
body = new Stream();
body.readable = true;
var isStreaming = body && typeof body === "object" && typeof body.pipe === "function";
originalBody.on("data", function (chunk) {
if (Buffer.isBuffer(chunk)) {
body.emit("data", chunk.length.toString(16).toUpperCase() + "\r\n");
body.emit("data", chunk);
body.emit("data", "\r\n");
return;
}
var length = Buffer.byteLength(chunk);
body.emit("data", toString(16).toUpperCase() + "\r\n" + chunk + "\r\n");
});
if (body && !isStreaming) head += body;
originalBody.on("end", function () {
body.emit("data", "0\r\n\r\n\r\n");
body.emit("end")
});
}
}
client.write(head);
if (!isStreaming) {
return done()
if (config.autoConnection) {
if (req.shouldKeepAlive && (hasContentLength || hasTransferEncoding || statusCode == 304)) {
headers["Connection"] = "keep-alive"
}
else {
headers["Connection"] = "close"
req.shouldKeepAlive = false
}
}
body.pipe(client);
body.on("end", done);
var reasonPhrase = STATUS_CODES[statusCode];
if (!reasonPhrase) {
throw new Error("Invalid response code " + statusCode);
}
var head = "HTTP/1.1 " + statusCode + " " + reasonPhrase + "\r\n";
for (var key in headers) {
head += key + ": " + headers[key] + "\r\n";
}
head += "\r\n";
});
if (body && !isStreaming) head += body;
client.write(head);
if (!isStreaming) {
return done()
}
body.pipe(client);
body.on("end", done);
}
function done() {
if (req.shouldKeepAlive) {
parser.reinitialize(HTTPParser.REQUEST);
}
else {
client.end();
}
}
parser.onHeadersComplete = function (info) {
info.body = new Stream();
info.body.readable = true;
req = info;
var rawHeaders = req.rawHeaders = req.headers;
var headers = req.headers = {};
for (var i = 0, l = rawHeaders.length; i < l; i += 2) {
headers[rawHeaders[i].toLowerCase()] = rawHeaders[i + 1];
}
req.url = urlParse(req.url);
app(req, res);
}
parser.onBody = function (buf, start, len) {
req.emit("data", buf.slide(start, len));
req.body.emit("data", buf.slide(start, len));
};
parser.onMessageComplete = function () {
req.emit("end");
req.body.emit("end");
};

@@ -115,11 +201,3 @@

function done() {
if (req.shouldKeepAlive) {
parser.reinitialize(HTTPParser.REQUEST);
}
else {
client.end();
}
}
};
};
SocketSocket SOC 2 Logo

Product

  • Package Alerts
  • Integrations
  • Docs
  • Pricing
  • FAQ
  • Roadmap
  • Changelog

Packages

npm

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc