Skip to content

Commit

Permalink
Fix form-data encode
Browse files Browse the repository at this point in the history
  • Loading branch information
adaex committed May 13, 2021
1 parent 739159e commit 2fb6b1a
Show file tree
Hide file tree
Showing 4 changed files with 48 additions and 29 deletions.
23 changes: 23 additions & 0 deletions example/gateway/debug/test.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
import { mkdirSync, writeFileSync } from 'fs'
import { http } from '..'
import _ = require('lodash')

http.router.register('调试', {

Expand All @@ -21,5 +23,26 @@ http.router.register('调试', {
const request = ctx.request
return { request }
}
},

'/debug/test/upload': {
options: {
method: 'POST',
name: '测试文件上传'
},
async handler (ctx) {
const files = [] as string[]
const dir = 'dist/temp/upload/'

mkdirSync(dir, { recursive: true })

_.forEach(ctx.request.file, (item) => {
const file = 'file' + Date.now().toString() + _.toString(item.filename)
writeFileSync(dir + file, item.data)
files.push(file)
})

return { files, rawBody: ctx.request.rawBody.toString(), file: ctx.request.file }
}
}
})
4 changes: 1 addition & 3 deletions example/gateway/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,4 @@ import { CoaContext, CoaHttp } from '../../lib'

export const http = new CoaHttp(CoaContext, new CoaEnv('1.0.0'), { baseUrl: '/api/' })

http.start().then(() => {

}, () => { })
http.start().then(() => {}, () => {})
41 changes: 20 additions & 21 deletions lib/base/CoaRequestBody.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,14 +5,13 @@ import * as querystring from 'querystring'

const DefaultMaxBodySize = 10 * 1024 * 1024

interface RequestBodyParams {
rawBody: string
export interface CoaRequestBodyParams {
rawBody: Buffer
body: { [key: string]: any}
files: RequestBodyFile[]
file: { [key: string]: CoaRequestBodyFile }
}
interface RequestBodyFile {
data: any
key: string
interface CoaRequestBodyFile {
data: Buffer
filename: string
type: string
}
Expand All @@ -27,7 +26,7 @@ export class CoaRequestBody {
}

async get () {
const params: RequestBodyParams = { rawBody: '', body: {}, files: [] }
const params: CoaRequestBodyParams = { rawBody: Buffer.from([]), body: {}, file: {} }

const contentLength = parseInt(this.req.headers['content-length'] || '') || 0

Expand All @@ -52,7 +51,7 @@ export class CoaRequestBody {
// 处理 json
if (contentType.includes('application/json')) {
try {
params.body = JSON.parse(params.rawBody)
params.body = JSON.parse(params.rawBody.toString())
} catch (e) {
throw new CoaError('Gateway.BodyDataParseError', '网关数据解析JSON失败')
}
Expand All @@ -61,7 +60,7 @@ export class CoaRequestBody {
// 处理 x-www-form-urlencoded
else if (contentType.includes('application/x-www-form-urlencoded')) {
try {
params.body = querystring.parse(params.rawBody)
params.body = querystring.parse(params.rawBody.toString())
} catch (e) {
throw new CoaError('Gateway.BodyDataParseError', '网关数据解析form-urlencoded参数失败')
}
Expand All @@ -76,17 +75,17 @@ export class CoaRequestBody {
throw new CoaError('Gateway.BodyDataParseError', '网关数据解析form-data参数boundary失败')
}
// 分割每个参数
const rawDataArray = params.rawBody.split(boundary)
const rawDataArray = params.rawBody.toString('binary').split(boundary)
for (const item of rawDataArray) {
// 匹配结果
const name = this.matching(item, /(?:name=")(.+?)(?:")/, true)
const value = this.matching(item, /(?:\r\n\r\n)([\S\s]*)(?:\r\n--$)/)
const name = this.matching(item, /(?:name=")(.*?)(?:")/, 'utf-8')
const value = this.matching(item, /(?:\r\n\r\n)([\S\s]*)(?:\r\n--$)/, 'binary')
if (!name || !value) continue
// 尝试获取文件名
const filename = this.matching(item, /(?:filename=")(.*?)(?:")/, true)
const filename = this.matching(item, /(?:filename=")(.*?)(?:")/, 'utf-8')
if (filename) {
const type = this.matching(item, /(?:Content-Type:)(.*?)(?:\r\n)/, true)
params.files.push({ data: value, key: name, filename, type })
const type = this.matching(item, /(?:Content-Type:)(.*?)(?:\r\n)/, 'utf-8')
params.file[name] = { data: Buffer.from(value, 'binary'), filename, type }
} else {
params.body[name] = value
}
Expand All @@ -100,8 +99,8 @@ export class CoaRequestBody {
}

protected async getRawBody (contentLength: number) {
return await new Promise<string>((resolve, reject) => {
let raw = [] as Buffer[]
return await new Promise<Buffer>((resolve, reject) => {
let raw = Buffer.from([])
let received = 0
let destroy = false

Expand Down Expand Up @@ -129,7 +128,7 @@ export class CoaRequestBody {
return
}

raw.push(data)
raw = Buffer.concat([raw, data])
}

const onEnd = () => {
Expand All @@ -138,7 +137,7 @@ export class CoaRequestBody {
reject(new CoaError('Gateway.BodyDataContentError', '网关数据大小不符'))
return
}
resolve(raw.toString())
resolve(raw)
}

const onClose = () => {
Expand All @@ -159,10 +158,10 @@ export class CoaRequestBody {
})
}

private matching (string: string, regex: RegExp, trim = false) {
private matching (string: string, regex: RegExp, encode: BufferEncoding) {
const matches = string.match(regex)
if (!matches || matches.length < 2) { return '' }
const value = matches[1]
return trim ? value.trim() : value
return encode === 'binary' ? value : Buffer.from(value, 'binary').toString(encode).trim()
}
}
9 changes: 4 additions & 5 deletions lib/service/CoaContext.ts
Original file line number Diff line number Diff line change
@@ -1,13 +1,12 @@
import { IncomingMessage, ServerResponse } from 'http'
import { CoaRequestBodyParams } from '../base/CoaRequestBody'
import { CoaSession } from '../base/CoaSession'

export type CoaContextConstructor<T> = new (req: IncomingMessage, res: ServerResponse) => T

interface ConaContextRequest{
rawBody: string
query: { [key: string]: string }
body: { [key: string]: any }
interface CoaContextRequest extends CoaRequestBodyParams{
path: string[]
query: { [key: string]: string }
}

export class CoaContext {
Expand All @@ -32,7 +31,7 @@ export class CoaContext {
}

// 请求的参数等信息
public readonly request: ConaContextRequest = { rawBody: '', query: {}, body: {}, path: [] }
public readonly request: CoaContextRequest = { rawBody: Buffer.from([]), path: [], query: {}, body: {}, file: {} }

// 缓存的session信息
private cacheSessions: { [name: string]: CoaSession } = {}
Expand Down

0 comments on commit 2fb6b1a

Please sign in to comment.