Skip to content

Commit

Permalink
update undici core request patching (#363)
Browse files Browse the repository at this point in the history
* update undici-core-request

* changeset
  • Loading branch information
Schniz authored May 29, 2023
1 parent 1c2d99c commit 8b1dee4
Show file tree
Hide file tree
Showing 2 changed files with 68 additions and 16 deletions.
5 changes: 5 additions & 0 deletions .changeset/fair-birds-call.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
'@edge-runtime/primitives': patch
---

update patching of undici request
79 changes: 63 additions & 16 deletions packages/primitives/src/patches/undici-core-request.js
Original file line number Diff line number Diff line change
@@ -1,25 +1,39 @@
// Copied from https://github.com/nodejs/undici/blob/v5.10.0/lib/core/request.js
// Copied from https://github.com/nodejs/undici/blob/v5.22.1/lib/core/request.js
// modified to allow any headers

'use strict'

const {
InvalidArgumentError,
NotSupportedError,
} = require('undici/lib/core/errors')
const { InvalidArgumentError } = require('undici/lib/core/errors')
const assert = require('assert')
const util = require('undici/lib/core/util')

// tokenRegExp and headerCharRegex have been lifted from
// https://github.com/nodejs/node/blob/main/lib/_http_common.js

/**
* Verifies that the given val is a valid HTTP token
* per the rules defined in RFC 7230
* See https://tools.ietf.org/html/rfc7230#section-3.2.6
*/
const tokenRegExp = /^[\^_`a-zA-Z\-0-9!#$%&'*+.|~]+$/

/**
* Matches if val contains an invalid field-vchar
* field-value = *( field-content / obs-fold )
* field-content = field-vchar [ 1*( SP / HTAB ) field-vchar ]
* field-vchar = VCHAR / obs-text
*/
const headerCharRegex = /[^\t\x20-\x7e\x80-\xff]/

// Verifies that a given path is valid does not contain control chars \x00 to \x20
const invalidPathRegex = /[^\u0021-\u00ff]/

const kHandler = Symbol('handler')

const channels = {}

let extractBody

const nodeVersion = process.versions.node.split('.')
const nodeMajor = Number(nodeVersion[0])
const nodeMinor = Number(nodeVersion[1])

try {
const diagnosticsChannel = require('diagnostics_channel')
channels.create = diagnosticsChannel.channel('undici:request:create')
Expand Down Expand Up @@ -49,6 +63,7 @@ class Request {
upgrade,
headersTimeout,
bodyTimeout,
reset,
throwOnError,
},
handler
Expand All @@ -63,10 +78,14 @@ class Request {
throw new InvalidArgumentError(
'path must be an absolute URL or start with a slash'
)
} else if (invalidPathRegex.exec(path) !== null) {
throw new InvalidArgumentError('invalid request path')
}

if (typeof method !== 'string') {
throw new InvalidArgumentError('method must be a string')
} else if (tokenRegExp.exec(method) === null) {
throw new InvalidArgumentError('invalid request method')
}

if (upgrade && typeof upgrade !== 'string') {
Expand All @@ -87,6 +106,10 @@ class Request {
throw new InvalidArgumentError('invalid bodyTimeout')
}

if (reset != null && typeof reset !== 'boolean') {
throw new InvalidArgumentError('invalid reset')
}

this.headersTimeout = headersTimeout

this.bodyTimeout = bodyTimeout
Expand Down Expand Up @@ -136,6 +159,8 @@ class Request {

this.blocking = blocking == null ? false : blocking

this.reset = reset == null ? null : reset

this.host = null

this.contentLength = null
Expand All @@ -162,9 +187,12 @@ class Request {
}

if (util.isFormDataLike(this.body)) {
if (nodeMajor < 16 || (nodeMajor === 16 && nodeMinor < 5)) {
if (
util.nodeMajor < 16 ||
(util.nodeMajor === 16 && util.nodeMinor < 8)
) {
throw new InvalidArgumentError(
'Form-Data bodies are only supported in node v16.5 and newer.'
'Form-Data bodies are only supported in node v16.8 and newer.'
)
}

Expand All @@ -178,6 +206,7 @@ class Request {
this.headers += `content-type: ${contentType}\r\n`
}
this.body = bodyStream.stream
this.contentLength = bodyStream.length
} else if (util.isBlobLike(body) && this.contentType == null && body.type) {
this.contentType = body.type
this.headers += `content-type: ${body.type}\r\n`
Expand Down Expand Up @@ -273,9 +302,23 @@ class Request {
}
}

function processHeader(request, key, val) {
function processHeaderValue(key, val) {
if (val && typeof val === 'object') {
throw new InvalidArgumentError(`invalid ${key} header`)
}

val = val != null ? `${val}` : ''

if (headerCharRegex.exec(val) !== null) {
throw new InvalidArgumentError(`invalid ${key} header`)
}

return `${key}: ${val}\r\n`
}

function processHeader(request, key, val) {
if (val && typeof val === 'object' && !Array.isArray(val)) {
throw new InvalidArgumentError(`invalid ${key} header`)
} else if (val === undefined) {
return
}
Expand All @@ -302,11 +345,15 @@ function processHeader(request, key, val) {
key.toLowerCase() === 'content-type'
) {
request.contentType = val
request.headers += `${key}: ${val}\r\n`
} else if (key.length === 6 && key.toLowerCase() === 'expect') {
throw new NotSupportedError('expect header not supported')
request.headers += processHeaderValue(key, val)
} else {
request.headers += `${key}: ${val}\r\n`
if (Array.isArray(val)) {
for (let i = 0; i < val.length; i++) {
request.headers += processHeaderValue(key, val[i])
}
} else {
request.headers += processHeaderValue(key, val)
}
}
}

Expand Down

1 comment on commit 8b1dee4

@vercel
Copy link

@vercel vercel bot commented on 8b1dee4 May 29, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Successfully deployed to the following URLs:

edge-runtime – ./

edge-runtime-git-main.vercel.sh
edge-runtime.vercel.app
edge-runtime.vercel.sh

Please sign in to comment.