Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 6 additions & 6 deletions src/builders/base.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { assertArray, assertNotEmptyString, assertString } from '../assertions'
import { EOL, HttpContentApplicationType, HttpContentMultipartType, HttpHeader } from '../constants'
import { EOL, HttpContentTypeApplication, HttpContentTypeMultipart, HttpHeader } from '../constants'
import { HttpZBody, HttpZHeader, HttpZParam } from '../types'
import { isEmpty, prettifyHeaderName, getEmptyStringForUndefined, arrayToPairs } from '../utils'

Expand Down Expand Up @@ -42,12 +42,12 @@ export class HttpZBaseBuilder {
this._processTransferEncodingChunked()

switch (this.body!.contentType) {
case HttpContentMultipartType.formData:
case HttpContentMultipartType.alternative:
case HttpContentMultipartType.mixed:
case HttpContentMultipartType.related:
case HttpContentTypeMultipart.formData:
case HttpContentTypeMultipart.alternative:
case HttpContentTypeMultipart.mixed:
case HttpContentTypeMultipart.related:
return this._generateFormDataBody()
case HttpContentApplicationType.xWwwFormUrlencoded:
case HttpContentTypeApplication.xWwwFormUrlencoded:
return this._generateUrlencodedBody()
default:
return this._generateTextBody()
Expand Down
42 changes: 22 additions & 20 deletions src/constants.ts
Original file line number Diff line number Diff line change
@@ -1,25 +1,26 @@
export const EOL = '\r\n'
export const EOL2X = EOL + EOL

const BASIC_LATIN = '[\\u0009\\u0020-\\u007E]'
const PARAM_NAME = '[A-Za-z0-9_.\\[\\]-]' // TODO: extend
const HTTP_METHODS = '(CONNECT|OPTIONS|TRACE|GET|HEAD|POST|PUT|PATCH|DELETE)'
const HTTP_PROTOCOL_VERSIONS = '(HTTP)\\/(1\\.0|1\\.1|2(\\.0){0,1})'
const HTTP_PROTOCOL_VERSIONS = '(HTTP)\\/(1\\.0|1\\.1|2(\\.0){0,1}|3(\\.0){0,1})'

export const regexps = {
quote: /"/g,
startNl: new RegExp(`^${EOL}`),
endNl: new RegExp(`${EOL}$`),
requestStartRow: new RegExp(`^${HTTP_METHODS} \\S* ${HTTP_PROTOCOL_VERSIONS}$`),
responseStartRow: new RegExp(`^${HTTP_PROTOCOL_VERSIONS} \\d{3} ${BASIC_LATIN}*$`),
nlStart: new RegExp(`^${EOL}`),
nlEnd: new RegExp(`${EOL}$`),
requestStartRow: new RegExp(`^${HTTP_METHODS}\\s\\S*\\s${HTTP_PROTOCOL_VERSIONS}$`),
responseStartRow: new RegExp(`^${HTTP_PROTOCOL_VERSIONS}\\s\\d{3}\\s[^\r\n]*$`),
// eslint-disable-next-line no-control-regex
quotedHeaderValue: new RegExp('^"[\\u0009\\u0020\\u0021\\u0023-\\u007E]+"$'),
boundary: /(?<=boundary=)"{0,1}[A-Za-z0-9'()+_,.:=?-]+"{0,1}/,
contentDisposition: new RegExp(`^Content-Disposition: *(form-data|inline|attachment)${BASIC_LATIN}*${EOL}`, 'i'),
boundary: new RegExp(`(?<=boundary=)"{0,1}[A-Za-z0-9'()+_,.:=?-]+"{0,1}`),
contentDisposition: new RegExp(
`^Content-Disposition:\\s*(form-data|inline|attachment)(?:\\s*;\\s*(name|filename)\\s*=\\s*(?:"([^"]+)"|([^;\\s]+)))*${EOL}`,
'i',
),
contentType: new RegExp(`^Content-Type:[\\S ]*${EOL}`, 'i'),
contentDispositionType: /(?<=Content-Disposition:) *(form-data|inline|attachment)/,
dispositionName: new RegExp(`(?<=name=)"${PARAM_NAME}+"`, 'i'),
dispositionFileName: new RegExp(`(?<=filename=)"${PARAM_NAME}+"`, 'i'),
contentDispositionType: new RegExp(`(?<=Content-Disposition:)\\s*(form-data|inline|attachment)`),
dispositionName: new RegExp(`(?<=name=)(?:"([^"]+)"|([^;\\s]+))+`, 'i'),
dispositionFileName: new RegExp(`(?<=filename=)(?:"([^"]+)"|([^;\\s]+))+`, 'i'),
chunkRow: new RegExp(`^[0-9a-fA-F]+${EOL}`),
}

Expand All @@ -31,7 +32,8 @@ export enum HttpProtocol {
export enum HttpProtocolVersion {
http10 = 'HTTP/1.0',
http11 = 'HTTP/1.1',
http20 = 'HTTP/2.0',
http2 = 'HTTP/2',
http3 = 'HTTP/3',
}

export enum HttpMethod {
Expand All @@ -57,7 +59,7 @@ export enum HttpHeader {
transferEncoding = 'Transfer-Encoding',
}

export enum HttpContentTextType {
export enum HttpContentTypeText {
any = 'text/',
css = 'text/css',
csv = 'text/csv',
Expand All @@ -67,7 +69,7 @@ export enum HttpContentTextType {
xml = 'text/xml',
}

export enum HttpContentApplicationType {
export enum HttpContentTypeApplication {
any = 'application/',
javascript = 'application/javascript',
json = 'application/json',
Expand All @@ -81,15 +83,15 @@ export enum HttpContentApplicationType {
zip = 'application/zip',
}

export enum HttpContentMultipartType {
export enum HttpContentTypeMultipart {
any = 'multipart/',
alternative = 'multipart/alternative',
formData = 'multipart/form-data',
mixed = 'multipart/mixed',
related = 'multipart/related',
}

export enum HttpContentImageType {
export enum HttpContentTypeImage {
any = 'image/',
gif = 'image/gif',
jpeg = 'image/jpeg',
Expand All @@ -98,14 +100,14 @@ export enum HttpContentImageType {
icon = 'image/x-icon',
}

export enum HttpContentAudioType {
export enum HttpContentTypeAudio {
any = 'audio/',
}

export enum HttpContentVideoType {
export enum HttpContentTypeVideo {
any = 'video/',
}

export enum HttpContentFonType {
export enum HttpContentTypeFont {
any = 'font/',
}
12 changes: 6 additions & 6 deletions src/parsers/base.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { EOL, EOL2X, HttpContentApplicationType, HttpContentMultipartType, HttpHeader, regexps } from '../constants'
import { EOL, EOL2X, HttpContentTypeApplication, HttpContentTypeMultipart, HttpHeader, regexps } from '../constants'
import { HttpZError } from '../error'
import { HttpZBody, HttpZHeader } from '../types'
import { splitBy, prettifyHeaderName, head, tail, isNil, trim } from '../utils'
Expand Down Expand Up @@ -67,13 +67,13 @@ export class HttpZBaseParser {
this.body.contentType = contentTypeHeader.toLowerCase().split(';')[0]
}
switch (this.body.contentType) {
case HttpContentMultipartType.formData:
case HttpContentMultipartType.alternative:
case HttpContentMultipartType.mixed:
case HttpContentMultipartType.related:
case HttpContentTypeMultipart.formData:
case HttpContentTypeMultipart.alternative:
case HttpContentTypeMultipart.mixed:
case HttpContentTypeMultipart.related:
this._parseFormDataBody()
break
case HttpContentApplicationType.xWwwFormUrlencoded:
case HttpContentTypeApplication.xWwwFormUrlencoded:
this._parseUrlencodedBody()
break
default:
Expand Down
6 changes: 3 additions & 3 deletions src/parsers/form-data-param-parser.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ export class FormDataParamParser {

// TODO: test it
parse(): HttpZBodyParam {
this.paramGroup = this.paramGroup.replace(regexps.startNl, '').replace(regexps.endNl, '')
this.paramGroup = this.paramGroup.replace(regexps.nlStart, '').replace(regexps.nlEnd, '')

const contentDispositionHeader = this._getContentDisposition()
const contentType = this._getContentType()
Expand Down Expand Up @@ -89,8 +89,8 @@ export class FormDataParamParser {

// TODO: test it
private _getParamValue(): string | never {
if (this.paramGroup.match(regexps.startNl)) {
return this.paramGroup.replace(regexps.startNl, '')
if (this.paramGroup.match(regexps.nlStart)) {
return this.paramGroup.replace(regexps.nlStart, '')
}
throw HttpZError.get('Incorrect form-data parameter', this.paramGroup)
}
Expand Down
29 changes: 19 additions & 10 deletions test/parsers/request.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -212,10 +212,19 @@ describe('parsers / request', () => {
test(startRow, expected)
})

it('should parse valid startRow when HTTP protocol is v2.0', () => {
const startRow = 'GET /features HTTP/2.0'
it('should parse valid startRow when HTTP protocol is v2', () => {
const startRow = 'GET /features HTTP/2'
const expected = getExpected({
protocolVersion: HttpProtocolVersion.http20,
protocolVersion: HttpProtocolVersion.http2,
})

test(startRow, expected)
})

it('should parse valid startRow when HTTP protocol is v3', () => {
const startRow = 'GET /features HTTP/3'
const expected = getExpected({
protocolVersion: HttpProtocolVersion.http3,
})

test(startRow, expected)
Expand Down Expand Up @@ -703,7 +712,7 @@ describe('parsers / request', () => {
'',
'John',
'--111362:53119209',
'Content-Disposition: form-data; name="photo"; filename="photo1.jpg"',
'Content-Disposition: form-data; name="photo-㡣"; filename="photo-㡣1.jpg"',
'Content-Type: application/octet-stream',
'',
'<binary-data>',
Expand Down Expand Up @@ -765,8 +774,8 @@ describe('parsers / request', () => {
{ name: 'user.data[firstName]', value: 'John' },
{
contentType: 'application/octet-stream',
name: 'photo',
fileName: 'photo1.jpg',
name: 'photo-㡣',
fileName: 'photo-㡣1.jpg',
value: '<binary-data>',
},
{
Expand All @@ -777,7 +786,7 @@ describe('parsers / request', () => {
],
},
headersSize: 284,
bodySize: 367,
bodySize: 371,
}

const parser = getParserInstance(rawRequest)
Expand Down Expand Up @@ -877,7 +886,7 @@ describe('parsers / request', () => {
'Content-Length: 301',
'',
'--11136253119209',
'Content-Disposition: attachment; filename="photo1.jpg"',
'Content-Disposition: attachment; filename="photo-㡣1.jpg"',
'Content-Type: application/octet-stream',
'',
'<binary-data>',
Expand Down Expand Up @@ -932,13 +941,13 @@ describe('parsers / request', () => {
{
type: 'attachment',
contentType: 'application/octet-stream',
fileName: 'photo1.jpg',
fileName: 'photo-㡣1.jpg',
value: '<binary-data>',
},
],
},
headersSize: 279,
bodySize: 149,
bodySize: 151,
}

const parser = getParserInstance(rawRequest)
Expand Down
8 changes: 4 additions & 4 deletions test/parsers/response.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -124,12 +124,12 @@ describe('parsers / response', () => {

it('should set instance fields when startRow has valid format (reason is not empty)', () => {
const parser = getParserInstance()
parser['startRow'] = 'HTTP/1.1 201 Created'
parser['startRow'] = 'HTTP/3 500 Server Error'

parser['_parseStartRow']()
expect(parser['protocolVersion']).toEqual('HTTP/1.1')
expect(parser['statusCode']).toEqual(201)
expect(parser['statusMessage']).toEqual('Created')
expect(parser['protocolVersion']).toEqual('HTTP/3')
expect(parser['statusCode']).toEqual(500)
expect(parser['statusMessage']).toEqual('Server Error')
})
})

Expand Down