Skip to content
Browse files

Remove http-adapter since it was moved to it's own repo

  • Loading branch information...
1 parent 83c17a1 commit eed24405c92376dfa0913626286991e4d6fd45e8 @creationix creationix committed Sep 20, 2012
View
21 http-adapter/LICENSE
@@ -1,21 +0,0 @@
-The MIT License
-
-Copyright (c) 2012 Ajax.org B.V
-
-Permission is hereby granted, free of charge, to any person obtaining a copy
-of this software and associated documentation files (the "Software"), to deal
-in the Software without restriction, including without limitation the rights
-to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
-copies of the Software, and to permit persons to whom the Software is
-furnished to do so, subject to the following conditions:
-
-The above copyright notice and this permission notice shall be included in
-all copies or substantial portions of the Software.
-
-THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
-AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
-OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
-THE SOFTWARE.
View
68 http-adapter/README.markdown
@@ -1,68 +0,0 @@
-# HTTP Adapter
-
-This module is a connect/stack middleware module that wraps a vfs instance and
-serves it via a HTTP RESTful interface.
-
-The module is a setup function that creates a middleware instance.
-
-```js
-var root = "http://localhost:8080/rest/";
-
-var vfs = require('vfs-local')({
- root: process.cwd(),
- httpRoot: root,
-});
-
-require('http').createServer(require('stack')(
- require('vfs-http-adapter')("/rest/", vfs)
-)).listen(8080);
-
-console.log("RESTful interface at " + root);
-```
-
-## `HEAD /any/path`
-
-All HEAD requests are converted to GET requests internally and act identical,
-except there is an internal flag in the vfs layer telling it to not stream the body.
-
-## `GET /path/to/file`
-
-Serve a file to the client as a stream. Supports etags and range requests.
-
-## `GET /directory/path/with/slash/`
-
-Serve a directory listing as a JSON document.
-
-This is served as a streaming json document with a weak etag (since the order
-of the entries is not defined.) It supports conditional GET requests
-
-See `vfs.readdir` below for the format of the JSON.
-
-## `PUT /path/to/file`
-
-Recieve a file from the client and save it to the vfs. The file body is streamed.
-
-## `PUT /directory/path/with/slash/`
-
-Create a directory
-
-## `DELETE /path/to/file`
-
-Delete a file.
-
-## `DELETE /directory/path/with/slash/`
-
-Delete a directory (not recursive)
-
-
-## `POST /path/to/target`
-
-POST is used for various adhoc commands that are useful but don't fit well into
-the RESTful paradigm. The client sends a JSON body containing the request information.
-
-Currently this includes:
-
- - {"renameFrom": from} - rename a file from `from` to `target`.
- - {"copyFrom": from} - copy a file from `from` to `target`.
- - {"linkTo": data} - create a symlink at `target` containing `data`.
-
View
317 http-adapter/multipart.js
@@ -1,317 +0,0 @@
-// Simple multipart parser for file uploads
-// Based loosly on Felix's node-formidable library
-// https://github.com/felixge/node-formidable
-
-var Stream = require('stream').Stream;
-var EventEmitter = require('events').EventEmitter;
-
-// Given an http request, it returns an event emitter that emits readable streams.
-module.exports = newParser
-function newParser(req, str) {
- var boundary = new Buffer(str);
- return new Parser(req, boundary);
-};
-
-// Parser states
-var DONE = 0x00;
-var BOUNDARY_START = 0x01;
-var BOUNDARY = 0x02;
-var BOUNDARY_END = 0x03;
-var HEADER_FIELD = 0x11;
-var HEADER_VALUE = 0x12;
-var HEADER_VALUE_END = 0x13;
-var HEADERS_ALMOST_DONE = 0x14;
-var PART_DATA = 0x21;
-var PART_END = 0x22;
-var END = 0x31;
-
-var states = {};
-states[DONE] = "DONE";
-states[BOUNDARY_START] = "BOUNDARY_START";
-states[BOUNDARY] = "BOUNDARY";
-states[BOUNDARY_END] = "BOUNDARY_END";
-states[HEADER_FIELD] = "HEADER_FIELD";
-states[HEADER_VALUE] = "HEADER_VALUE";
-states[HEADER_VALUE_END] = "HEADER_VALUE_END";
-states[HEADERS_ALMOST_DONE] = "HEADERS_ALMOST_DONE";
-states[PART_DATA] = "PART_DATA";
-states[PART_END] = "PART_END";
-states[END] = "END";
-
-var inherits = require('util').inherits;
-
-inherits(PartStream, Stream);
-function PartStream(input, headers) {
- this.headers = headers;
- this.readable = true;
- this.input = input;
- this.events = [];
-}
-
-PartStream.prototype.pause = function pause() {
- this.input.pause();
-};
-
-PartStream.prototype.resume = function resume() {
- this.input.resume();
-};
-
-inherits(Parser, EventEmitter);
-function Parser(input, boundary) {
- this.boundary = boundary;
- this.input = input;
- this.state = BOUNDARY_START;
- this.offset = 0; // The current offset in the entire stream
- this.index = 0; // index of bytes in current substream
- this.chunks = [];
- input.on("data", this.onData.bind(this));
- input.on("end", this.onEnd.bind(this));
-}
-Parser.prototype.error = function error(message) {
- this.emit("error", new Error(message));
-};
-// Flush the buffer
-Parser.prototype.flush = function flush() {
- for (var i = 0, l = this.chunks.length; i < l; i++) {
- this.stream.emit("data", this.chunks[i]);
- }
- this.chunks.length = 0;
-};
-Parser.prototype.onData = function onData(chunk) {
-
- var boundary = this.boundary;
- var stream = this.stream;
- var len = chunk.length;
- var start; // offset within chunk of start of current piece
- var partStart; // offset within chunk of data start
- var partEnd;
- var leftover;
- if (this.leftover !== undefined) {
- leftover = this.leftover;
- this.leftover = undefined;
- start = 0;
- }
-
- for (var i = 0; i < len; i++,this.offset++) {
- var c = chunk[i];
- // console.log({i:i,c:new Buffer([c]).toString(),s:states[this.state],l:leftover,ch:this.chunks});
- switch (this.state) {
-
- case BOUNDARY_START: // Matches the "--" prefix before the boundary string
- if (c !== 0x2d) {
- if (partEnd !== undefined) {
- partEnd = undefined;
- this.state = PART_DATA;
- }
- if (this.chunks.length) {
- this.flush(); // Flush any pending chunks that we weren't sure about
- this.state = PART_DATA;
- }
- if (this.state === PART_DATA) {
- i--;
- continue;
- }
- return this.error("Missing -- before boundary " + this.index);
- }
- if (this.index === 1) {
- this.state = BOUNDARY;
- this.index = 0;
- } else {
- this.index++;
- }
- break;
-
- case BOUNDARY: // Matches the boundary string
- if (c !== boundary[this.index]) {
- if (partEnd !== undefined) {
- partEnd = undefined;
- this.state = PART_DATA;
- }
- if (this.chunks.length) {
- this.flush(); // Flush any pending chunks that we weren't sure about
- this.state = PART_DATA;
- }
- if (this.state === PART_DATA) {
- i--;
- continue;
- }
- return this.error("Boundary mismatch " + this.index);
- }
- if (this.index === boundary.length - 1) {
- this.chunks.length = 0; // It was a boundary, throw away the buffer
- if (partEnd !== undefined) {
- partStart = partStart || 0;
- if (partStart < partEnd) {
- stream.emit("data", chunk.slice(partStart, partEnd));
- }
- partStart = undefined;
- partEnd = undefined;
- }
- if (stream) {
- stream.emit("end");
- this.stream = undefined;
- stream = undefined;
- }
- this.state = BOUNDARY_END;
- this.index = 0;
- } else {
- this.index++;
- }
- break;
-
- case BOUNDARY_END: // Matches the \r\n after the boundary
- if (c === 0x2d) { // -
- this.state = END;
- this.index = 0;
- continue;
- }
- if (c !== (this.index === 0 ? 0x0d : 0x0a)) {
- return this.error("Missing \\r\\n after boundary " + this.index);
- }
- if (this.index === 1) {
- this.state = HEADER_FIELD;
- this.index = 0;
- this.headers = {};
- start = i + 1;
- } else {
- this.index++;
- }
- break;
-
- case HEADER_FIELD:
- if (start === i && c === 0x0d) { // \r
- this.state = HEADERS_ALMOST_DONE;
- start = undefined;
- continue;
- }
- if (c !== 0x3a) continue; // Eat everything up to :
- var field = chunk.toString("ascii", start, i);
- if (leftover !== undefined) {
- field = leftover + field;
- leftover = undefined;
- }
- this.field = field;
- this.state = HEADER_VALUE;
- start = i + 1;
- break;
-
- case HEADER_VALUE:
-
- if (c === 0x20 && start === i && !leftover) {
- start = i + 1; // left trim
- }
- if (c !== 0x0d) continue; // Eat everything up to \r
-
- var value = chunk.toString("ascii", start, i);
- if (leftover !== undefined) {
- value = leftover + value;
- leftover = undefined;
- }
- this.headers[this.field.toLowerCase()] = value;
- this.field = undefined;
- start = undefined;
- this.state = HEADER_VALUE_END;
- break;
-
- case HEADER_VALUE_END:
- if (c !== 0x0a) {
- return this.error("Missing \\r\\n after header");
- }
- start = i + 1;
- this.state = HEADER_FIELD;
- break;
-
- case HEADERS_ALMOST_DONE:
- if (c !== 0x0a) {
- return this.error("Missing \\r\\n after headers");
- }
- stream = new PartStream(this.input, this.headers);
- this.stream = stream;
- this.headers = undefined;
- this.emit("part", stream);
-
- this.state = PART_DATA;
- partStart = i + 1;
- break;
-
- case PART_DATA:
- if (c !== 0x0d) continue; // \r
- // This might be the end of the data, we're not sure yet
- partEnd = i;
- // Start checking if this is the end of the body
- this.state = PART_END;
- break;
- case PART_END:
- if (c === 0x0a) {
- this.state = BOUNDARY_START;
- this.index = 0;
- } else {
- if (partEnd !== undefined) {
- partEnd = undefined;
- }
- if (this.chunks.length) {
- this.flush(); // Flush any pending chunks that we weren't sure about
- }
- this.state = PART_DATA;
- i--;
- }
- break;
- case END:
- if (c !== (this.index === 0 ? 0x2d : this.index === 1 ? 0x0d : 0x0a)) {
- return this.error("Missing --\r\n after closing boundary");
- }
- if (this.index === 2) {
- this.state = DONE;
- continue;
- }
- this.index++;
- break;
-
- case DONE:
- return this.error("Trailing data after end");
-
- default:
- this.error("Unknown parser state " + this.state);
- break;
- }
- }
-
- // At end of input chunk, we need to handle leftovers.
-
- // If we were parsing a body, just emit what we got.
- if (this.state === PART_DATA) {
- if (!partStart) { // The entire chunk was data
- stream.emit("data", chunk);
- } else if (partStart < chunk.length) { // The data started within this chunk
- stream.emit("data", chunk.slice(partStart));
- }
- } else {
- // We're still checking to see if chunk bytes are boundary or data
- if (partEnd !== undefined) {
- // Flush the part we're sure is body
- partStart = partStart || 0;
- if (partStart < partEnd) {
- stream.emit("data", chunk.slice(partStart, partEnd));
- }
- // Buffer the rest
- if (partEnd < chunk.length) {
- this.chunks.push(chunk.slice(partEnd));
- }
- } else if (this.chunks.length) {
- this.chunks.push(chunk);
- }
- }
-
- if (start !== undefined) {
- this.leftover = (leftover || "") + chunk.toString("ascii", start);
- } else if (leftover) {
- this.leftover = leftover;
- }
-};
-
-Parser.prototype.onEnd = function onEnd() {
- if (this.state !== DONE) {
- this.error("Unexpected EOF in input stream");
- }
- this.emit("end");
-};
View
24 http-adapter/package.json
@@ -1,24 +0,0 @@
-{
- "author": "Ajax.org B.V. <info@ajax.org>",
- "contributors": [
- { "name": "Tim Caswell", "email": "tim@c9.io>" }
- ],
- "name": "vfs-http-adapter",
- "description": "A http middleware to wrap vfs instances and expose them via a RESTful interface",
- "version": "0.2.2",
- "repository": {
- "type": "git",
- "url": "git://github.com/c9/vfs.git"
- },
- "main": "restful.js",
- "dependencies": {},
- "devDependencies": {},
- "optionalDependencies": {},
- "licenses" : [{
- "type" : "MIT",
- "url" : "http://github.com/c9/vfs/raw/master/http-adapter/LICENSE"
- }],
- "engines": {
- "node": "*"
- }
-}
View
280 http-adapter/restful.js
@@ -1,280 +0,0 @@
-var urlParse = require('url').parse;
-var multipart = require('./multipart');
-var Stream = require('stream').Stream;
-var pathJoin = require('path').join;
-
-module.exports = function setup(mount, vfs, mountOptions) {
-
- if (!mountOptions) mountOptions = {};
-
- // Returns a json stream that wraps input object stream
- function jsonEncoder(input, path) {
- var output = new Stream();
- output.readable = true;
- var first = true;
- input.on("data", function (entry) {
- if (path) {
- entry.href = path + entry.name;
- var mime = entry.linkStat ? entry.linkStat.mime : entry.mime;
- if (mime.match(/(directory|folder)$/)) {
- entry.href += "/";
- }
- }
- if (first) {
- output.emit("data", "[\n " + JSON.stringify(entry));
- first = false;
- } else {
- output.emit("data", ",\n " + JSON.stringify(entry));
- }
- });
- input.on("end", function () {
- if (first) output.emit("data", "[]");
- else output.emit("data", "\n]");
- output.emit("end");
- });
- if (input.pause) {
- output.pause = function () {
- input.pause();
- };
- }
- if (input.resume) {
- output.resume = function () {
- input.resume();
- };
- }
- return output;
- }
-
- return function (req, res, next) {
-
- if (mountOptions.readOnly && !(req.method === "GET" || req.method === "HEAD")) return next();
- if (!req.uri) { req.uri = urlParse(req.url); }
-
- if (mount[mount.length - 1] !== "/") mount += "/";
-
- var path = unescape(req.uri.pathname);
- // no need to sanitize the url (remove ../..) the vfs layer has this
- // responsibility since it can do it better with realpath.
- if (path.substr(0, mount.length) !== mount) { return next(); }
- path = path.substr(mount.length - 1);
-
- // Instead of using next for errors, we send a custom response here.
- function abort(err, code) {
- console.error(err.stack || err);
- if (code) res.statusCode = code;
- else if (err.code === "EBADREQUEST") res.statusCode = 400;
- else if (err.code === "EACCESS") res.statusCode = 403;
- else if (err.code === "ENOENT") res.statusCode = 404;
- else if (err.code === "ENOTREADY") res.statusCode = 503;
- else res.statusCode = 500;
- var message = (err.stack || err) + "\n";
- res.setHeader("Content-Type", "text/plain");
- res.setHeader("Content-Length", Buffer.byteLength(message));
- res.end(message);
- }
-
- var options = {};
- if (req.method === "HEAD") {
- options.head = true;
- req.method = "GET";
- }
-
- if (req.method === "GET") {
-
- if (req.headers.hasOwnProperty("if-none-match")) options.etag = req.headers["if-none-match"];
-
- if (req.headers.hasOwnProperty('range')) {
- var range = options.range = {};
- var p = req.headers.range.indexOf('=');
- var parts = req.headers.range.substr(p + 1).split('-');
- if (parts[0].length) {
- range.start = parseInt(parts[0], 10);
- }
- if (parts[1].length) {
- range.end = parseInt(parts[1], 10);
- }
- if (req.headers.hasOwnProperty('if-range')) range.etag = req.headers["if-range"];
- }
-
- var tryAgain;
-
- if (path[path.length - 1] === "/") {
- if (mountOptions.autoIndex) {
- tryAgain = true;
- vfs.readfile(path + mountOptions.autoIndex, options, onGet);
- }
- else {
- options.encoding = null;
- vfs.readdir(path, options, onGet);
- }
- } else {
- vfs.readfile(path, options, onGet);
- }
-
- function onGet(err, meta) {
- res.setHeader("Date", (new Date()).toUTCString());
- if (err) {
- if (tryAgain) {
- tryAgain = false;
- options.encoding = null;
- return vfs.readdir(path, options, onGet);
- }
- return abort(err);
- }
- if (meta.rangeNotSatisfiable) return abort(meta.rangeNotSatisfiable, 416);
-
- if (meta.hasOwnProperty('etag')) res.setHeader("ETag", meta.etag);
-
- if (meta.notModified) res.statusCode = 304;
- if (meta.partialContent) res.statusCode = 206;
-
- if (meta.hasOwnProperty('stream') || options.head) {
- if (meta.hasOwnProperty('mime')) res.setHeader("Content-Type", meta.mime);
- if (meta.hasOwnProperty("size")) {
- res.setHeader("Content-Length", meta.size);
- if (meta.hasOwnProperty("partialContent")) {
- res.setHeader("Content-Range", "bytes " + meta.partialContent.start + "-" + meta.partialContent.end + "/" + meta.partialContent.size);
- }
- }
- if (options.encoding === null) {
- res.setHeader("Content-Type", "application/json");
- }
- }
- if (meta.hasOwnProperty('stream')) {
- meta.stream.on("error", abort);
- if (options.encoding === null) {
- var base = (req.socket.encrypted ? "https://" : "http://") + req.headers.host + pathJoin(mount, path);
- jsonEncoder(meta.stream, base).pipe(res);
- } else {
- meta.stream.pipe(res);
- }
- req.on("close", function () {
- if (meta.stream.readable) {
- meta.stream.destroy();
- meta.stream.readable = false;
- }
- })
- } else {
- res.end();
- }
- }
-
- } // end GET request
-
- else if (req.method === "PUT") {
-
- if (path[path.length - 1] === "/") {
- vfs.mkdir(path, {}, function (err, meta) {
- if (err) return abort(err);
- res.end();
- });
- } else {
-
- vfs.mkfile(path, { stream: req }, function (err, meta) {
- if (err) return abort(err);
- res.end();
- });
- }
- } // end PUT request
-
- else if (req.method === "DELETE") {
- var command;
- if (path[path.length - 1] === "/") {
- command = vfs.rmdir;
- } else {
- command = vfs.rmfile;
- }
- command(path, {}, function (err, meta) {
- if (err) return abort(err);
- res.end();
- });
- } // end DELETE request
-
- else if (req.method === "POST") {
-
- if (path[path.length - 1] === "/") {
- var contentType = req.headers["content-type"];
- if (!contentType) {
- return abort(new Error("Missing Content-Type header"), 400);
- }
- if (!(/multipart/i).test(contentType)) {
- return abort(new Error("Content-Type should be multipart"), 400);
- }
- var match = contentType.match(/boundary=(?:"([^"]+)"|([^;]+))/i);
- if (!match) {
- return abort(new Error("Missing multipart boundary"), 400);
- }
- var boundary = match[1] || match[2];
-
- var parser = multipart(req, boundary);
-
- parser.on("part", function (stream) {
- var contentDisposition = stream.headers["content-disposition"];
- if (!contentDisposition) {
- return parser.error("Missing Content-Disposition header in part");
- }
- var match = contentDisposition.match(/filename="([^"]*)"/);
- if (!match) {
- return parser.error("Missing filename in Content-Disposition header in part");
- }
- var filename = match[1];
-
- vfs.mkfile(path + "/" + filename, {stream:stream}, function (err, meta) {
- if (err) return abort(err);
- });
- });
- parser.on("error", abort);
- parser.on("end", function () {
- res.end();
- });
- return;
- }
-
- var data = "";
- req.on("data", function (chunk) {
- data += chunk;
- });
- req.on("end", function () {
- var message;
- try {
- message = JSON.parse(data);
- } catch (err) {
- return abort(err);
- }
- var command, options = {};
- if (message.renameFrom) {
- command = vfs.rename;
- options.from = message.renameFrom;
- }
- else if (message.copyFrom) {
- command = vfs.copy;
- options.from = message.copyFrom;
- }
- else if (message.linkTo) {
- command = vfs.symlink;
- options.target = message.linkTo;
- }
- else {
- return abort(new Error("Invalid command in POST " + data));
- }
- command(path, options, function (err, meta) {
- if (err) return abort(err);
- res.end();
- });
- });
- } // end POST commands
- else if (req.method === "PROPFIND") {
- vfs.stat(path, {}, function (err, meta) {
- if (err) return abort(err);
- res.setHeader("Content-Type", "application/json");
- res.end(JSON.stringify(meta) + "\n");
- });
- }
- else {
- return abort("Unsupported HTTP method", 501);
- }
-
- };
-
-};
-
View
83 http-adapter/test-multipart.js
@@ -1,83 +0,0 @@
-var fs = require('fs');
-var assert = require('assert');
-
-function join(buffers) {
- var size = 0;
- buffers.forEach(function (buffer) {
- size += buffer.length;
- });
- var total = new Buffer(size);
- var offset = 0;
- buffers.forEach(function (buffer) {
- buffer.copy(total, offset);
- offset += buffer.length;
- });
- return total;
-}
-
-var multipart = require('./multipart');
-var boundary = "---------------------------1530233567340623049784027732";
-var body = new Buffer(256 * 2);
-for (var i = 0; i < 256; i++) {
- body[i] = i;
- body[i + 256] = i;
-}
-//var body = new Buffer('12345\r\n--67890\n');
-var headers = { 'content-disposition': 'form-data; name="module.js"; filename="module.js"', 'content-type': 'application/javascript' };
-var data = [new Buffer('--' + boundary + '\r\n'),
- new Buffer('Content-Disposition: ' + headers['content-disposition'] + '\r\n'),
- new Buffer('Content-Type: ' + headers['content-type'] + '\r\n'),
- new Buffer('\r\n'),
- body,
- new Buffer('\r\n'),
- new Buffer('--' + boundary + '--\r\n')];
-data = join(data);
-fs.writeFileSync("multipart2.log", data);
-var size = data.length;
-
-var left = size;
-var runs = [];
-var done;
-next(1);
-function next(bufferSize) {
- var files = [];
- var input = require('fs').createReadStream("multipart2.log", {bufferSize: bufferSize});
- var parser = multipart(input, boundary);
- parser.on("part", function (stream) {
- var data = [];
- assert.deepEqual(stream.headers, headers);
- stream.on("data", function (chunk) {
- data.push(chunk);
- console.log("data", chunk);
- if (!chunk.length) throw new Error("Empty buffer");
- });
- stream.on("end", function () {
- if (files.hasOwnProperty(bufferSize)) {
- throw new Error("Duplicate bufferSize " + bufferSize);
- }
- data = join(data);
- files.push(data);
- var actual = data.toString("hex");
- var expected = body.toString("hex");
- if (actual !== expected) {
- console.error("bufferSize " + bufferSize);
- console.error({a:data,e:body});
- assert.equal(actual, expected);
- }
- });
- });
- parser.on("end", function () {
- console.log("Successfully parsed using chunks of size " + bufferSize);
- if (bufferSize < size) {
- next(bufferSize + 1);
- } else {
- console.log("All tests passed!");
- done = true;
- }
- });
-}
-
-process.on("exit", function () {
- if (!done) throw new Error("Failed to finish all tests.");
-});
-
View
1 node_modules/vfs-http-adapter

0 comments on commit eed2440

Please sign in to comment.
Something went wrong with that request. Please try again.