调整语法, 兼容bun

v2
yutent 2023-10-25 18:45:16 +08:00
parent 148684bf35
commit 6b3a44d387
8 changed files with 913 additions and 912 deletions

View File

@ -14,11 +14,11 @@ import PATH from 'path'
const DEFAULT_FORM_TYPE = 'application/x-www-form-urlencoded' const DEFAULT_FORM_TYPE = 'application/x-www-form-urlencoded'
var __dirname = PATH.dirname(URL.fileURLToPath(import.meta.url)) const __dirname = PATH.dirname(URL.fileURLToPath(import.meta.url))
var tmpdir = PATH.resolve(__dirname, '.tmp/') const tmpdir = PATH.resolve(__dirname, '.tmp/')
var encode = encodeURIComponent const encode = encodeURIComponent
var decode = decodeURIComponent const decode = decodeURIComponent
if (fs.isdir(tmpdir)) { if (fs.isdir(tmpdir)) {
fs.rm(tmpdir, true) fs.rm(tmpdir, true)
@ -44,7 +44,6 @@ export default class Request {
hideProperty(this, '__GET__', null) hideProperty(this, '__GET__', null)
hideProperty(this, '__POST__', null) hideProperty(this, '__POST__', null)
hideProperty(this, '__COOKIE__', parseCookie(this.header('cookie') || '')) hideProperty(this, '__COOKIE__', parseCookie(this.header('cookie') || ''))
this.__fixUrl() this.__fixUrl()
} }

View File

@ -4,16 +4,16 @@
*/ */
// var KEY_REGEXP = /^[\u0009\u0020-\u007e\u0080-\u00ff]+$/ // var KEY_REGEXP = /^[\u0009\u0020-\u007e\u0080-\u00ff]+$/
var SPLIT_REGEXP = /; */ const SPLIT_REGEXP = /; */
// var encode = encodeURIComponent // var encode = encodeURIComponent
var decode = decodeURIComponent const decode = decodeURIComponent
/** /**
* [parse 格式化字符串] * [parse 格式化字符串]
*/ */
export function parseCookie(str) { export function parseCookie(str) {
var obj = {} let obj = {}
var pairs let pairs
if (typeof str !== 'string') { if (typeof str !== 'string') {
return {} return {}
@ -27,8 +27,8 @@ export function parseCookie(str) {
continue continue
} }
var key = item[0].trim() let key = item[0].trim()
var val = item[1].trim() let val = item[1].trim()
obj[key] = decode(val) obj[key] = decode(val)
} }

View File

@ -1,38 +1,30 @@
import util from 'util' import { WriteStream } from 'node:fs'
import { WriteStream } from 'fs' import { EventEmitter } from 'node:events'
import { EventEmitter } from 'events'
import crypto from 'crypto'
export default function File(properties) {
EventEmitter.call(this)
this.size = 0 export default class File extends EventEmitter {
this.path = null
this.name = null
this.type = null
this.hash = null
this.lastModifiedDate = null
this._writeStream = null #stream = null
for (var key in properties) { size = 0
this[key] = properties[key] path = null
name = null
type = null
lastModifiedDate = null
constructor(props = {}){
super()
for (var key in props) {
this[key] = props[key]
}
} }
if (typeof this.hash === 'string') { open() {
this.hash = crypto.createHash(properties.hash) this.#stream = new WriteStream(this.path)
} else {
this.hash = null
} }
}
util.inherits(File, EventEmitter) toJSON() {
File.prototype.open = function() {
this._writeStream = new WriteStream(this.path)
}
File.prototype.toJSON = function() {
return { return {
size: this.size, size: this.size,
path: this.path, path: this.path,
@ -43,28 +35,27 @@ File.prototype.toJSON = function() {
filename: this.filename, filename: this.filename,
mime: this.mime mime: this.mime
} }
}
File.prototype.write = function(buffer, cb) {
var self = this
if (self.hash) {
self.hash.update(buffer)
} }
this._writeStream.write(buffer, function() {
self.lastModifiedDate = new Date() write(buffer, cb) {
self.size += buffer.length
self.emit('progress', self.size)
this.#stream.write(buffer, _ =>{
this.lastModifiedDate = new Date()
this.size += buffer.length
this.emit('progress', this.size)
cb() cb()
}) })
}
File.prototype.end = function(cb) {
var self = this
if (self.hash) {
self.hash = self.hash.digest('hex')
} }
this._writeStream.end(function() {
self.emit('end') end(cb) {
this.#stream.end(() => {
this.emit('end')
cb() cb()
}) })
}
} }

View File

@ -1,21 +1,31 @@
import crypto from 'crypto' import crypto from 'node:crypto'
import fs from 'fs' import fs from 'node:fs'
import util from 'util' import util from 'node:util'
import path from 'path' import path from 'node:path'
import File from './file.js' import File from './file.js'
import { EventEmitter } from 'events' import { EventEmitter } from 'node:events'
import { Stream } from 'stream' import { Stream } from 'node:stream'
import { StringDecoder } from 'string_decoder' import { StringDecoder } from 'node:string_decoder'
import { MultipartParser } from './multipart_parser.js' import { MultipartParser } from './multipart_parser.js'
import { QuerystringParser } from './querystring_parser.js' import { QuerystringParser } from './querystring_parser.js'
import { OctetParser } from './octet_parser.js' import { OctetParser } from './octet_parser.js'
import { JSONParser } from './json_parser.js' import { JSONParser } from './json_parser.js'
export default function IncomingForm(opts) {
EventEmitter.call(this)
opts = opts || {} function dummyParser(self) {
return {
end: function() {
self.ended = true
self._maybeEnd()
return null
}
}
}
export default class IncomingForm{
constructor(opts = {}) {
this.error = null this.error = null
this.ended = false this.ended = false
@ -37,11 +47,13 @@ export default function IncomingForm(opts) {
this._flushing = 0 this._flushing = 0
this._fieldsSize = 0 this._fieldsSize = 0
this.openedFiles = [] this.openedFiles = []
}
util.inherits(IncomingForm, EventEmitter) }
IncomingForm.prototype.parse = function(req, cb) {
parse(req, cb) {
this.pause = function() { this.pause = function() {
try { try {
req.pause() req.pause()
@ -129,15 +141,15 @@ IncomingForm.prototype.parse = function(req, cb) {
}) })
return this return this
} }
IncomingForm.prototype.writeHeaders = function(headers) { writeHeaders(headers) {
this.headers = headers this.headers = headers
this._parseContentLength() this._parseContentLength()
this._parseContentType() this._parseContentType()
} }
IncomingForm.prototype.write = function(buffer) { write(buffer) {
if (this.error) { if (this.error) {
return return
} }
@ -163,24 +175,24 @@ IncomingForm.prototype.write = function(buffer) {
} }
return bytesParsed return bytesParsed
} }
IncomingForm.prototype.pause = function() { pause() {
// this does nothing, unless overwritten in IncomingForm.parse // this does nothing, unless overwritten in IncomingForm.parse
return false return false
} }
IncomingForm.prototype.resume = function() { resume() {
// this does nothing, unless overwritten in IncomingForm.parse // this does nothing, unless overwritten in IncomingForm.parse
return false return false
} }
IncomingForm.prototype.onPart = function(part) { onPart(part) {
// this method can be overwritten by the user // this method can be overwritten by the user
this.handlePart(part) this.handlePart(part)
} }
IncomingForm.prototype.handlePart = function(part) { handlePart(part) {
var self = this var self = this
if (part.filename === undefined) { if (part.filename === undefined) {
@ -239,19 +251,10 @@ IncomingForm.prototype.handlePart = function(part) {
self._maybeEnd() self._maybeEnd()
}) })
}) })
}
function dummyParser(self) {
return {
end: function() {
self.ended = true
self._maybeEnd()
return null
} }
}
}
IncomingForm.prototype._parseContentType = function() {
_parseContentType() {
if (this.bytesExpected === 0) { if (this.bytesExpected === 0) {
this._parser = dummyParser(this) this._parser = dummyParser(this)
return return
@ -295,9 +298,9 @@ IncomingForm.prototype._parseContentType = function() {
this.headers['content-type'] this.headers['content-type']
) )
) )
} }
IncomingForm.prototype._error = function(err) { _error(err) {
if (this.error || this.ended) { if (this.error || this.ended) {
return return
} }
@ -311,9 +314,9 @@ IncomingForm.prototype._error = function(err) {
setTimeout(fs.unlink, 0, file.path, function(error) {}) setTimeout(fs.unlink, 0, file.path, function(error) {})
}) })
} }
} }
IncomingForm.prototype._parseContentLength = function() { _parseContentLength() {
this.bytesReceived = 0 this.bytesReceived = 0
if (this.headers['content-length']) { if (this.headers['content-length']) {
this.bytesExpected = parseInt(this.headers['content-length'], 10) this.bytesExpected = parseInt(this.headers['content-length'], 10)
@ -324,13 +327,13 @@ IncomingForm.prototype._parseContentLength = function() {
if (this.bytesExpected !== null) { if (this.bytesExpected !== null) {
this.emit('progress', this.bytesReceived, this.bytesExpected) this.emit('progress', this.bytesReceived, this.bytesExpected)
} }
} }
IncomingForm.prototype._newParser = function() { _newParser() {
return new MultipartParser() return new MultipartParser()
} }
IncomingForm.prototype._initMultipart = function(boundary) { _initMultipart(boundary) {
this.type = 'multipart' this.type = 'multipart'
var parser = new MultipartParser(), var parser = new MultipartParser(),
@ -436,9 +439,9 @@ IncomingForm.prototype._initMultipart = function(boundary) {
} }
this._parser = parser this._parser = parser
} }
IncomingForm.prototype._fileName = function(headerValue) { _fileName(headerValue) {
var m = headerValue.match(/\bfilename="(.*?)"($|; )/i) var m = headerValue.match(/\bfilename="(.*?)"($|; )/i)
if (!m) return if (!m) return
@ -448,9 +451,9 @@ IncomingForm.prototype._fileName = function(headerValue) {
return String.fromCharCode(code) return String.fromCharCode(code)
}) })
return filename return filename
} }
IncomingForm.prototype._initUrlencoded = function() { _initUrlencoded() {
this.type = 'urlencoded' this.type = 'urlencoded'
var parser = new QuerystringParser(this.maxFields) var parser = new QuerystringParser(this.maxFields)
@ -465,9 +468,9 @@ IncomingForm.prototype._initUrlencoded = function() {
} }
this._parser = parser this._parser = parser
} }
IncomingForm.prototype._initOctetStream = function() { _initOctetStream() {
this.type = 'octet-stream' this.type = 'octet-stream'
var filename = this.headers['x-file-name'] var filename = this.headers['x-file-name']
var mime = this.headers['content-type'] var mime = this.headers['content-type']
@ -521,9 +524,9 @@ IncomingForm.prototype._initOctetStream = function() {
self._parser.once('doneWritingFile', done) self._parser.once('doneWritingFile', done)
} }
}) })
} }
IncomingForm.prototype._initJSONencoded = function() { _initJSONencoded() {
this.type = 'json' this.type = 'json'
var parser = new JSONParser(), var parser = new JSONParser(),
@ -543,9 +546,9 @@ IncomingForm.prototype._initJSONencoded = function() {
} }
this._parser = parser this._parser = parser
} }
IncomingForm.prototype._uploadPath = function(filename) { _uploadPath(filename) {
var name = 'upload_' var name = 'upload_'
var buf = crypto.randomBytes(16) var buf = crypto.randomBytes(16)
for (var i = 0; i < buf.length; ++i) { for (var i = 0; i < buf.length; ++i) {
@ -560,12 +563,15 @@ IncomingForm.prototype._uploadPath = function(filename) {
} }
return path.join(this.uploadDir, name) return path.join(this.uploadDir, name)
} }
IncomingForm.prototype._maybeEnd = function() { _maybeEnd() {
if (!this.ended || this._flushing || this.error) { if (!this.ended || this._flushing || this.error) {
return return
} }
this.emit('end') this.emit('end')
}
} }

View File

@ -1,13 +1,13 @@
export function JSONParser() { export class JSONParser {
this.data = Buffer.from('')
this.bytesWritten = 0
}
JSONParser.prototype.initWithLength = function(length) { data = Buffer.from('')
bytesWritten = 0
initWithLength(length) {
this.data = Buffer.alloc(length) this.data = Buffer.alloc(length)
} }
JSONParser.prototype.write = function(buffer) { write(buffer) {
if (this.data.length >= this.bytesWritten + buffer.length) { if (this.data.length >= this.bytesWritten + buffer.length) {
buffer.copy(this.data, this.bytesWritten) buffer.copy(this.data, this.bytesWritten)
} else { } else {
@ -15,9 +15,9 @@ JSONParser.prototype.write = function(buffer) {
} }
this.bytesWritten += buffer.length this.bytesWritten += buffer.length
return buffer.length return buffer.length
} }
JSONParser.prototype.end = function() { end() {
var data = this.data.toString('utf8') var data = this.data.toString('utf8')
var fields var fields
try { try {
@ -30,4 +30,7 @@ JSONParser.prototype.end = function() {
this.data = null this.data = null
this.onEnd() this.onEnd()
}
} }

View File

@ -30,24 +30,25 @@ var s = 0,
return c | 0x20 return c | 0x20
} }
export function MultipartParser() { export class MultipartParser {
this.boundary = null boundary = null
this.boundaryChars = null boundaryChars = null
this.lookbehind = null lookbehind = null
this.state = S.PARSER_UNINITIALIZED state = S.PARSER_UNINITIALIZED
this.index = null index = null
this.flags = 0 flags = 0
}
MultipartParser.stateToString = function(stateNumber) {
static stateToString(stateNumber) {
for (var state in S) { for (var state in S) {
var number = S[state] var number = S[state]
if (number === stateNumber) return state if (number === stateNumber) return state
} }
} }
MultipartParser.prototype.initWithBoundary = function(str) {
initWithBoundary(str) {
this.boundary = Buffer.alloc(str.length + 4) this.boundary = Buffer.alloc(str.length + 4)
this.boundary.write('\r\n--', 0) this.boundary.write('\r\n--', 0)
this.boundary.write(str, 4) this.boundary.write(str, 4)
@ -58,9 +59,9 @@ MultipartParser.prototype.initWithBoundary = function(str) {
for (var i = 0; i < this.boundary.length; i++) { for (var i = 0; i < this.boundary.length; i++) {
this.boundaryChars[this.boundary[i]] = true this.boundaryChars[this.boundary[i]] = true
} }
} }
MultipartParser.prototype.write = function(buffer) { write(buffer) {
var self = this, var self = this,
i = 0, i = 0,
len = buffer.length, len = buffer.length,
@ -300,9 +301,9 @@ MultipartParser.prototype.write = function(buffer) {
this.flags = flags this.flags = flags
return len return len
} }
MultipartParser.prototype.end = function() { end() {
var callback = function(self, name) { var callback = function(self, name) {
var callbackSymbol = 'on' + name.substr(0, 1).toUpperCase() + name.substr(1) var callbackSymbol = 'on' + name.substr(0, 1).toUpperCase() + name.substr(1)
if (callbackSymbol in self) { if (callbackSymbol in self) {
@ -320,8 +321,11 @@ MultipartParser.prototype.end = function() {
'MultipartParser.end(): stream ended unexpectedly: ' + this.explain() 'MultipartParser.end(): stream ended unexpectedly: ' + this.explain()
) )
} }
}
explain() {
return 'state = ' + MultipartParser.stateToString(this.state)
}
} }
MultipartParser.prototype.explain = function() {
return 'state = ' + MultipartParser.stateToString(this.state)
}

View File

@ -1,17 +1,15 @@
import { EventEmitter } from 'events' import { EventEmitter } from 'events'
import util from 'util'
export function OctetParser() {
EventEmitter.call(this)
}
util.inherits(OctetParser, EventEmitter) export class OctetParser extends EventEmitter {
write(buffer) {
OctetParser.prototype.write = function(buffer) {
this.emit('data', buffer) this.emit('data', buffer)
return buffer.length return buffer.length
} }
OctetParser.prototype.end = function() { end () {
this.emit('end') this.emit('end')
} }
}

View File

@ -1,6 +1,6 @@
// This is a buffering parser, not quite as nice as the multipart one. // This is a buffering parser, not quite as nice as the multipart one.
// If I find time I'll rewrite this to be fully streaming as well // If I find time I'll rewrite this to be fully streaming as well
import querystring from 'querystring' import {parse} from 'node:querystring'
export class QuerystringParser { export class QuerystringParser {
constructor(maxKeys) { constructor(maxKeys) {
@ -14,7 +14,7 @@ export class QuerystringParser {
} }
end() { end() {
var fields = querystring.parse(this.buffer, '&', '=', { var fields = parse(this.buffer, '&', '=', {
maxKeys: this.maxKeys maxKeys: this.maxKeys
}) })
for (var field in fields) { for (var field in fields) {