Name: js-handler/node_modules/restify/node_modules/formidable/lib/multipart_parser.js
| 1: | var Buffer = require('buffer').Buffer, |
| 2: | s = 0, |
| 3: | S = |
| 4: | { PARSER_UNINITIALIZED: s++, |
| 5: | START: s++, |
| 6: | START_BOUNDARY: s++, |
| 7: | HEADER_FIELD_START: s++, |
| 8: | HEADER_FIELD: s++, |
| 9: | HEADER_VALUE_START: s++, |
| 10: | HEADER_VALUE: s++, |
| 11: | HEADER_VALUE_ALMOST_DONE: s++, |
| 12: | HEADERS_ALMOST_DONE: s++, |
| 13: | PART_DATA_START: s++, |
| 14: | PART_DATA: s++, |
| 15: | PART_END: s++, |
| 16: | END: s++ |
| 17: | }, |
| 18: | |
| 19: | f = 1, |
| 20: | F = |
| 21: | { PART_BOUNDARY: f, |
| 22: | LAST_BOUNDARY: f *= 2 |
| 23: | }, |
| 24: | |
| 25: | LF = 10, |
| 26: | CR = 13, |
| 27: | SPACE = 32, |
| 28: | HYPHEN = 45, |
| 29: | COLON = 58, |
| 30: | A = 97, |
| 31: | Z = 122, |
| 32: | |
| 33: | lower = function(c) { |
| 34: | return c | 0x20; |
| 35: | }; |
| 36: | |
| 37: | for (s in S) { |
| 38: | exports[s] = S[s]; |
| 39: | } |
| 40: | |
| 41: | function MultipartParser() { |
| 42: | this.boundary = null; |
| 43: | this.boundaryChars = null; |
| 44: | this.lookbehind = null; |
| 45: | this.state = S.PARSER_UNINITIALIZED; |
| 46: | |
| 47: | this.index = null; |
| 48: | this.flags = 0; |
| 49: | }; |
| 50: | exports.MultipartParser = MultipartParser; |
| 51: | |
| 52: | MultipartParser.stateToString = function(stateNumber) { |
| 53: | for (var state in S) { |
| 54: | var number = S[state]; |
| 55: | if (number === stateNumber) return state; |
| 56: | } |
| 57: | }; |
| 58: | |
| 59: | MultipartParser.prototype.initWithBoundary = function(str) { |
| 60: | this.boundary = new Buffer(str.length+4); |
| 61: | this.boundary.write('\r\n--', 'ascii', 0); |
| 62: | this.boundary.write(str, 'ascii', 4); |
| 63: | this.lookbehind = new Buffer(this.boundary.length+8); |
| 64: | this.state = S.START; |
| 65: | |
| 66: | this.boundaryChars = {}; |
| 67: | for (var i = 0; i < this.boundary.length; i++) { |
| 68: | this.boundaryChars[this.boundary[i]] = true; |
| 69: | } |
| 70: | }; |
| 71: | |
| 72: | MultipartParser.prototype.write = function(buffer) { |
| 73: | var self = this, |
| 74: | i = 0, |
| 75: | len = buffer.length, |
| 76: | prevIndex = this.index, |
| 77: | index = this.index, |
| 78: | state = this.state, |
| 79: | flags = this.flags, |
| 80: | lookbehind = this.lookbehind, |
| 81: | boundary = this.boundary, |
| 82: | boundaryChars = this.boundaryChars, |
| 83: | boundaryLength = this.boundary.length, |
| 84: | boundaryEnd = boundaryLength - 1, |
| 85: | bufferLength = buffer.length, |
| 86: | c, |
| 87: | cl, |
| 88: | |
| 89: | mark = function(name) { |
| 90: | self[name+'Mark'] = i; |
| 91: | }, |
| 92: | clear = function(name) { |
| 93: | delete self[name+'Mark']; |
| 94: | }, |
| 95: | callback = function(name, buffer, start, end) { |
| 96: | if (start !== undefined && start === end) { |
| 97: | return; |
| 98: | } |
| 99: | |
| 100: | var callbackSymbol = 'on'+name.substr(0, 1).toUpperCase()+name.substr(1); |
| 101: | if (callbackSymbol in self) { |
| 102: | self[callbackSymbol](buffer, start, end); |
| 103: | } |
| 104: | }, |
| 105: | dataCallback = function(name, clear) { |
| 106: | var markSymbol = name+'Mark'; |
| 107: | if (!(markSymbol in self)) { |
| 108: | return; |
| 109: | } |
| 110: | |
| 111: | if (!clear) { |
| 112: | callback(name, buffer, self[markSymbol], buffer.length); |
| 113: | self[markSymbol] = 0; |
| 114: | } else { |
| 115: | callback(name, buffer, self[markSymbol], i); |
| 116: | delete self[markSymbol]; |
| 117: | } |
| 118: | }; |
| 119: | |
| 120: | for (i = 0; i < len; i++) { |
| 121: | c = buffer[i]; |
| 122: | switch (state) { |
| 123: | case S.PARSER_UNINITIALIZED: |
| 124: | return i; |
| 125: | case S.START: |
| 126: | index = 0; |
| 127: | state = S.START_BOUNDARY; |
| 128: | case S.START_BOUNDARY: |
| 129: | if (index == boundary.length - 2) { |
| 130: | if (c != CR) { |
| 131: | return i; |
| 132: | } |
| 133: | index++; |
| 134: | break; |
| 135: | } else if (index - 1 == boundary.length - 2) { |
| 136: | if (c != LF) { |
| 137: | return i; |
| 138: | } |
| 139: | index = 0; |
| 140: | callback('partBegin'); |
| 141: | state = S.HEADER_FIELD_START; |
| 142: | break; |
| 143: | } |
| 144: | |
| 145: | if (c != boundary[index+2]) { |
| 146: | index = -2; |
| 147: | } |
| 148: | if (c == boundary[index+2]) { |
| 149: | index++; |
| 150: | } |
| 151: | break; |
| 152: | case S.HEADER_FIELD_START: |
| 153: | state = S.HEADER_FIELD; |
| 154: | mark('headerField'); |
| 155: | index = 0; |
| 156: | case S.HEADER_FIELD: |
| 157: | if (c == CR) { |
| 158: | clear('headerField'); |
| 159: | state = S.HEADERS_ALMOST_DONE; |
| 160: | break; |
| 161: | } |
| 162: | |
| 163: | index++; |
| 164: | if (c == HYPHEN) { |
| 165: | break; |
| 166: | } |
| 167: | |
| 168: | if (c == COLON) { |
| 169: | if (index == 1) { |
| 170: | // empty header field |
| 171: | return i; |
| 172: | } |
| 173: | dataCallback('headerField', true); |
| 174: | state = S.HEADER_VALUE_START; |
| 175: | break; |
| 176: | } |
| 177: | |
| 178: | cl = lower(c); |
| 179: | if (cl < A || cl > Z) { |
| 180: | return i; |
| 181: | } |
| 182: | break; |
| 183: | case S.HEADER_VALUE_START: |
| 184: | if (c == SPACE) { |
| 185: | break; |
| 186: | } |
| 187: | |
| 188: | mark('headerValue'); |
| 189: | state = S.HEADER_VALUE; |
| 190: | case S.HEADER_VALUE: |
| 191: | if (c == CR) { |
| 192: | dataCallback('headerValue', true); |
| 193: | callback('headerEnd'); |
| 194: | state = S.HEADER_VALUE_ALMOST_DONE; |
| 195: | } |
| 196: | break; |
| 197: | case S.HEADER_VALUE_ALMOST_DONE: |
| 198: | if (c != LF) { |
| 199: | return i; |
| 200: | } |
| 201: | state = S.HEADER_FIELD_START; |
| 202: | break; |
| 203: | case S.HEADERS_ALMOST_DONE: |
| 204: | if (c != LF) { |
| 205: | return i; |
| 206: | } |
| 207: | |
| 208: | callback('headersEnd'); |
| 209: | state = S.PART_DATA_START; |
| 210: | break; |
| 211: | case S.PART_DATA_START: |
| 212: | state = S.PART_DATA; |
| 213: | mark('partData'); |
| 214: | case S.PART_DATA: |
| 215: | prevIndex = index; |
| 216: | |
| 217: | if (index == 0) { |
| 218: | // boyer-moore derrived algorithm to safely skip non-boundary data |
| 219: | i += boundaryEnd; |
| 220: | while (i < bufferLength && !(buffer[i] in boundaryChars)) { |
| 221: | i += boundaryLength; |
| 222: | } |
| 223: | i -= boundaryEnd; |
| 224: | c = buffer[i]; |
| 225: | } |
| 226: | |
| 227: | if (index < boundary.length) { |
| 228: | if (boundary[index] == c) { |
| 229: | if (index == 0) { |
| 230: | dataCallback('partData', true); |
| 231: | } |
| 232: | index++; |
| 233: | } else { |
| 234: | index = 0; |
| 235: | } |
| 236: | } else if (index == boundary.length) { |
| 237: | index++; |
| 238: | if (c == CR) { |
| 239: | // CR = part boundary |
| 240: | flags |= F.PART_BOUNDARY; |
| 241: | } else if (c == HYPHEN) { |
| 242: | // HYPHEN = end boundary |
| 243: | flags |= F.LAST_BOUNDARY; |
| 244: | } else { |
| 245: | index = 0; |
| 246: | } |
| 247: | } else if (index - 1 == boundary.length) { |
| 248: | if (flags & F.PART_BOUNDARY) { |
| 249: | index = 0; |
| 250: | if (c == LF) { |
| 251: | // unset the PART_BOUNDARY flag |
| 252: | flags &= ~F.PART_BOUNDARY; |
| 253: | callback('partEnd'); |
| 254: | callback('partBegin'); |
| 255: | state = S.HEADER_FIELD_START; |
| 256: | break; |
| 257: | } |
| 258: | } else if (flags & F.LAST_BOUNDARY) { |
| 259: | if (c == HYPHEN) { |
| 260: | callback('partEnd'); |
| 261: | callback('end'); |
| 262: | state = S.END; |
| 263: | } else { |
| 264: | index = 0; |
| 265: | } |
| 266: | } else { |
| 267: | index = 0; |
| 268: | } |
| 269: | } |
| 270: | |
| 271: | if (index > 0) { |
| 272: | // when matching a possible boundary, keep a lookbehind reference |
| 273: | // in case it turns out to be a false lead |
| 274: | lookbehind[index-1] = c; |
| 275: | } else if (prevIndex > 0) { |
| 276: | // if our boundary turned out to be rubbish, the captured lookbehind |
| 277: | // belongs to partData |
| 278: | callback('partData', lookbehind, 0, prevIndex); |
| 279: | prevIndex = 0; |
| 280: | mark('partData'); |
| 281: | |
| 282: | // reconsider the current character even so it interrupted the sequence |
| 283: | // it could be the beginning of a new sequence |
| 284: | i--; |
| 285: | } |
| 286: | |
| 287: | break; |
| 288: | case S.END: |
| 289: | break; |
| 290: | default: |
| 291: | return i; |
| 292: | } |
| 293: | } |
| 294: | |
| 295: | dataCallback('headerField'); |
| 296: | dataCallback('headerValue'); |
| 297: | dataCallback('partData'); |
| 298: | |
| 299: | this.index = index; |
| 300: | this.state = state; |
| 301: | this.flags = flags; |
| 302: | |
| 303: | return len; |
| 304: | }; |
| 305: | |
| 306: | MultipartParser.prototype.end = function() { |
| 307: | var callback = function(self, name) { |
| 308: | var callbackSymbol = 'on'+name.substr(0, 1).toUpperCase()+name.substr(1); |
| 309: | if (callbackSymbol in self) { |
| 310: | self[callbackSymbol](); |
| 311: | } |
| 312: | }; |
| 313: | if ((this.state == S.HEADER_FIELD_START && this.index == 0) || |
| 314: | (this.state == S.PART_DATA && this.index == this.boundary.length)) { |
| 315: | callback(this, 'partEnd'); |
| 316: | callback(this, 'end'); |
| 317: | } else if (this.state != S.END) { |
| 318: | return new Error('MultipartParser.end(): stream ended unexpectedly: ' + this.explain()); |
| 319: | } |
| 320: | }; |
| 321: | |
| 322: | MultipartParser.prototype.explain = function() { |
| 323: | return 'state = ' + MultipartParser.stateToString(this.state); |
| 324: | }; |
