diff options
author | Alexander Sulfrian <alexander@sulfrian.net> | 2012-04-25 00:13:37 +0200 |
---|---|---|
committer | Alexander Sulfrian <alexander@sulfrian.net> | 2012-04-25 00:23:26 +0200 |
commit | fdc1028cfd9e6563dbbe950cdd539559ce8d6353 (patch) | |
tree | 4b0ae3791baf59e94767dca01c71fd9828a69798 /emacs.d/lisp/jshint-mode/node_modules/formidable/lib/multipart_parser.js | |
parent | 452a858fe4d70ec3521687dcbd1a8270f51b6f37 (diff) | |
download | dotfiles-fdc1028cfd9e6563dbbe950cdd539559ce8d6353.tar.gz dotfiles-fdc1028cfd9e6563dbbe950cdd539559ce8d6353.tar.xz dotfiles-fdc1028cfd9e6563dbbe950cdd539559ce8d6353.zip |
emacs: added some additional modes
Diffstat (limited to 'emacs.d/lisp/jshint-mode/node_modules/formidable/lib/multipart_parser.js')
-rw-r--r-- | emacs.d/lisp/jshint-mode/node_modules/formidable/lib/multipart_parser.js | 303 |
1 files changed, 303 insertions, 0 deletions
diff --git a/emacs.d/lisp/jshint-mode/node_modules/formidable/lib/multipart_parser.js b/emacs.d/lisp/jshint-mode/node_modules/formidable/lib/multipart_parser.js new file mode 100644 index 0000000..f553819 --- /dev/null +++ b/emacs.d/lisp/jshint-mode/node_modules/formidable/lib/multipart_parser.js @@ -0,0 +1,303 @@ +var Buffer = require('buffer').Buffer, + s = 0, + S = + { PARSER_UNINITIALIZED: s++, + START: s++, + START_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++, + END: s++, + }, + + f = 1, + F = + { PART_BOUNDARY: f, + LAST_BOUNDARY: f *= 2, + }, + + LF = 10, + CR = 13, + SPACE = 32, + HYPHEN = 45, + COLON = 58, + A = 97, + Z = 122, + + lower = function(c) { + return c | 0x20; + }; + +for (var s in S) { + exports[s] = S[s]; +} + +function MultipartParser() { + this.boundary = null; + this.boundaryChars = null; + this.lookbehind = null; + this.state = S.PARSER_UNINITIALIZED; + + this.index = null; + this.flags = 0; +}; +exports.MultipartParser = MultipartParser; + +MultipartParser.prototype.initWithBoundary = function(str) { + this.boundary = new Buffer(str.length+4); + this.boundary.write('\r\n--', 'ascii', 0); + this.boundary.write(str, 'ascii', 4); + this.lookbehind = new Buffer(this.boundary.length+8); + this.state = S.START; + + this.boundaryChars = {}; + for (var i = 0; i < this.boundary.length; i++) { + this.boundaryChars[this.boundary[i]] = true; + } +}; + +MultipartParser.prototype.write = function(buffer) { + var self = this, + i = 0, + len = buffer.length, + prevIndex = this.index, + index = this.index, + state = this.state, + flags = this.flags, + lookbehind = this.lookbehind, + boundary = this.boundary, + boundaryChars = this.boundaryChars, + boundaryLength = this.boundary.length, + boundaryEnd = boundaryLength - 1, + bufferLength = buffer.length, + c, + cl, + + mark = function(name) { + self[name+'Mark'] = i; + }, + clear = function(name) { + delete self[name+'Mark']; + }, + callback = function(name, buffer, start, end) { + if (start !== undefined && start === end) { + return; + } + + 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 i; + case S.START: + index = 0; + state = S.START_BOUNDARY; + case S.START_BOUNDARY: + if (index == boundary.length - 2) { + if (c != CR) { + return i; + } + index++; + break; + } else if (index - 1 == boundary.length - 2) { + if (c != LF) { + return i; + } + index = 0; + callback('partBegin'); + state = S.HEADER_FIELD_START; + break; + } + + if (c != boundary[index+2]) { + return i; + } + index++; + break; + case S.HEADER_FIELD_START: + state = S.HEADER_FIELD; + mark('headerField'); + index = 0; + case S.HEADER_FIELD: + if (c == CR) { + clear('headerField'); + state = S.HEADERS_ALMOST_DONE; + break; + } + + index++; + if (c == HYPHEN) { + break; + } + + if (c == COLON) { + if (index == 1) { + // empty header field + return i; + } + dataCallback('headerField', true); + state = S.HEADER_VALUE_START; + break; + } + + cl = lower(c); + if (cl < A || cl > Z) { + return i; + } + break; + case S.HEADER_VALUE_START: + if (c == SPACE) { + break; + } + + mark('headerValue'); + state = S.HEADER_VALUE; + case S.HEADER_VALUE: + if (c == CR) { + dataCallback('headerValue', true); + callback('headerEnd'); + state = S.HEADER_VALUE_ALMOST_DONE; + } + break; + case S.HEADER_VALUE_ALMOST_DONE: + if (c != LF) { + return i; + } + state = S.HEADER_FIELD_START; + break; + case S.HEADERS_ALMOST_DONE: + if (c != LF) { + return i; + } + + callback('headersEnd'); + state = S.PART_DATA_START; + break; + case S.PART_DATA_START: + state = S.PART_DATA + mark('partData'); + case S.PART_DATA: + prevIndex = index; + + if (index == 0) { + // boyer-moore derrived algorithm to safely skip non-boundary data + while (i + boundaryLength <= bufferLength) { + if (buffer[i + boundaryEnd] in boundaryChars) { + break; + } + + i += boundaryLength; + } + c = buffer[i]; + } + + if (index < boundary.length) { + if (boundary[index] == c) { + if (index == 0) { + dataCallback('partData', true); + } + index++; + } else { + index = 0; + } + } else if (index == boundary.length) { + index++; + if (c == CR) { + // CR = part boundary + flags |= F.PART_BOUNDARY; + } else if (c == HYPHEN) { + // HYPHEN = end boundary + flags |= F.LAST_BOUNDARY; + } else { + index = 0; + } + } else if (index - 1 == boundary.length) { + if (flags & F.PART_BOUNDARY) { + index = 0; + if (c == LF) { + // unset the PART_BOUNDARY flag + flags &= ~F.PART_BOUNDARY; + callback('partEnd'); + callback('partBegin'); + state = S.HEADER_FIELD_START; + break; + } + } else if (flags & F.LAST_BOUNDARY) { + if (c == HYPHEN) { + callback('partEnd'); + callback('end'); + state = S.END; + } else { + index = 0; + } + } else { + index = 0; + } + } + + if (index > 0) { + // when matching a possible boundary, keep a lookbehind reference + // in case it turns out to be a false lead + lookbehind[index-1] = c; + } else if (prevIndex > 0) { + // if our boundary turned out to be rubbish, the captured lookbehind + // belongs to partData + callback('partData', lookbehind, 0, prevIndex); + prevIndex = 0; + mark('partData'); + + // reconsider the current character even so it interrupted the sequence + // it could be the beginning of a new sequence + i--; + } + + break; + case S.END: + break; + default: + return i; + } + } + + dataCallback('headerField'); + dataCallback('headerValue'); + dataCallback('partData'); + + this.index = index; + this.state = state; + this.flags = flags; + + return len; +}; + +MultipartParser.prototype.end = function() { + if (this.state != S.END) { + return new Error('MultipartParser.end(): stream ended unexpectedly'); + } +}; |