Skip to content

Commit

Permalink
In the trenches
Browse files Browse the repository at this point in the history
  • Loading branch information
felixge committed May 3, 2010
0 parents commit 3270eb4
Show file tree
Hide file tree
Showing 15 changed files with 799 additions and 0 deletions.
4 changes: 4 additions & 0 deletions Makefile
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
test:
@find test/simple/test-*.js | xargs -n 1 -t node

.PHONY: test
23 changes: 23 additions & 0 deletions ideas/api.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
var formidable = require('formidable');

(new formidable.ServerRequest(req))
.addListener('end', function(fields, files) {
// handle files / files hashes
});

// OR

(new formidable.ServerRequest)
.fromNodeRequest(req)
.addListener('file', function(file) {

})
.addListener('field', function(field) {

})
.addListener('error', function() {

})
.addListener('end', function() {

});
8 changes: 8 additions & 0 deletions ideas/test.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
var http = require('http')
, sys = require('sys');

http.createServer(function(req, res) {
req.addListener('data', function(buffer) {
sys.p(Object.keys(buffer.constructor.prototype));
});
}).listen(8001);
1 change: 1 addition & 0 deletions lib/formidable/formidable.js
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
exports.ServerRequest = require('./server_request').ServerRequest;
1 change: 1 addition & 0 deletions lib/formidable/index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
module.exports = require('./formidable');
229 changes: 229 additions & 0 deletions lib/formidable/multipart_parser.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,229 @@
var sys = require('sys')
, Buffer = require('buffer').Buffer

, s = 0
, S =
{ PARSER_UNINITIALIZED: s++
, START_MESSAGE: s++
, PART_BEGIN: s++
// , PART_BEGIN_HYPEN: s++
// , PART_BEGIN_BOUNDARY: s++
, HEADER_FIELD_START: s++
, HEADER_FIELD: s++
, HEADER_VALUE_START: s++
, HEADER_VALUE: s++
, HEADER_VALUE_ALMOST_DONE: s++
, HEADERS_ALMOST_DONE: s++
, PART_DATA_START: s++
, PART_DATA: s++
, PART_END: s++
}

, f = 1
, F =
{ PART_DATA: f
}

, LF = 10
, CR = 13
, SPACE = 32
, HYPHEN = 45
, COLON = 58
, SEMICOLON = 59
, EQUALSIGN = 61
, A = 97
, Z = 122

, lower = function(c) {
return c | 0x20;
};

for (var s in S) {
exports[s] = S[s];
}

var MultipartParser = exports.MultipartParser = function() {
this.boundary = null;
this.state = S.PARSER_UNINITIALIZED;

this.index = null;
this.mark = null;
this.flags = 0;
};

MultipartParser.prototype.initWithBoundary = function(str) {
this.boundary = new Buffer(Buffer.byteLength(str, 'ascii'));
this.boundary.write(str, 'ascii', 0);
this.state = S.STREAM_BEGIN;
};

MultipartParser.prototype.write = function(buffer) {
var self = this
, i = 0
, len = buffer.length
, index = this.index
, state = this.state
, flags = this.flags
, c
, cl

, mark = function(name) {
self[name+'Mark'] = i;
}
, callback = function(name, buffer, start, end) {
var callbackSymbol = 'on'+name.substr(0, 1).toUpperCase()+name.substr(1);
if (callbackSymbol in self) {
self[callbackSymbol](buffer, start, end);
}
}
, dataCallback = function(name, clear) {
var markSymbol = name+'Mark';
if (!(markSymbol in self)) {
return;
}

if (!clear) {
callback(name, buffer, self[markSymbol], buffer.length);
self[markSymbol] = 0;
} else {
callback(name, buffer, self[markSymbol], i);
delete self[markSymbol];
}
};

for (i = 0; i < len; i++) {
c = buffer[i];
switch (state) {
case S.PARSER_UNINITIALIZED:
return 0;
case S.MESSAGE_BEGIN:
if (c != HYPHEN) {
return 0;
}
state = S.PART_BEGIN;
index = 1;
break;
case S.PART_BEGIN:
index++;
if (index <= 2) {
if (c != HYPHEN) {
return 0;
}
break;
}

if (index - 2 <= this.boundary.length) {
if (this.boundary[index-3] != c) {
return 0;
}
break;
}

switch (index - this.boundary.length - 2) {
case 1:
if (c != CR) {
return 0;
}
break;
case 2:
if (c != LF) {
return 0;
}

index = 0;
callback('partBegin');
state = S.HEADER_FIELD_START;
break;
}
break;
case S.HEADER_FIELD_START:
state = S.HEADER_FIELD;
mark('headerField');
case S.HEADER_FIELD:
if (c == HYPHEN) {
break;
}

if (c == COLON) {
dataCallback('headerField', true);
state = S.HEADER_VALUE_START;
break;
}

cl = lower(c);
if (cl < A || cl > Z) {
return 0;
}
break;
case S.HEADER_VALUE_START:
if (c == SPACE) {
break;
}

if (c == CR) {
state = S.HEADERS_ALMOST_DONE;
break;
}

mark('headerValue');
state = S.HEADER_VALUE;
case S.HEADER_VALUE:
if (c == CR) {
dataCallback('headerValue', true);
state = S.HEADER_VALUE_ALMOST_DONE;
}
break;
case S.HEADER_VALUE_ALMOST_DONE:
if (c != LF) {
return 0;
}
state = S.HEADER_VALUE_START;
break;
case S.HEADERS_ALMOST_DONE:
if (c != LF) {
return 0;
}

state = S.PART_DATA_START;
break;
case S.PART_DATA_START:
flags |= F.PART_DATA;
state = S.PART_DATA
mark('partData');
case S.PART_DATA:
switch (index) {
case 0:
if (c == CR) {
index++;
}
break;
case 1:
index = 0;
if (c == LF) {
// i = i - 2;
p(i);
dataCallback('partData');
i = i + 2;
state = S.PART_BEGIN;
}
break;
}

// state = S.PART_BEGIN;

break;
default:
return 0;
}
}

dataCallback('headerField');
dataCallback('headerValue');
dataCallback('partData');

this.index = index;
this.state = state;
this.flags = flags;

return len;
};
74 changes: 74 additions & 0 deletions lib/formidable/server_request.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,74 @@
var sys = require('sys')
, events = require('events');

var ServerRequest = exports.ServerRequest = function() {
this.tmpDir = '/tmp';
this.httpRequest = null;
this.headers = null;
this.bytesTotal = null;
this.type = null;
this.multipartBoundary = null;
// this.buffer = null;
};
sys.inherits(ServerRequest, events.EventEmitter);

ServerRequest.prototype.fromNodeRequest = function(req) {
this.httpRequest = req;

var self = this;
this.writeHeaders(req.headers);
this.httpRequest
.addListener('data', function(buffer) {
self.write(buffer);
})
.addListener('end', function() {
self.end();
});
};

ServerRequest.prototype.writeHeaders = function(headers) {
this.headers = headers;
this.parseContentLength();
this.parseContentType();
}

ServerRequest.prototype.parseContentLength = function() {
if (this.headers['content-length']) {
this.bytesTotal = parseInt(this.headers['content-length'], 10);
}
};

ServerRequest.prototype.parseContentType = function() {
if (!this.headers['content-type']) {
return;
}

if (this.headers['content-type'].match(/urlencoded/i)) {
this.type = 'urlencoded';
return;
}

if (this.headers['content-type'].match(/multipart/i)) {
this.type = 'multipart';

var m;
if (m = this.headers['content-type'].match(/boundary=([^;]+)/i)) {
this.boundary = m[1];
} else {
this.boundary = null;
this.emit('error', new Error('malformed request, no multipart boundary'));
this.pause();
}
return;
}
};

ServerRequest.prototype.write = function(buffer) {
this.expected = [0, 33, 255, 42, 23];
this.expectedBytes = 0;

// this.buffer = this.buffer.concat(buffer);
// while (this.buffer.indexOf('--AADNSJKAS') == -1) {
//
// }
}
Loading

0 comments on commit 3270eb4

Please sign in to comment.