33
44import * as types from '@azure/functions' ;
55import { HttpRequestParams , HttpRequestUser } from '@azure/functions' ;
6- import { RpcHttpData } from '@azure/functions-core' ;
6+ import { RpcHttpData , RpcTypedData } from '@azure/functions-core' ;
77import { Blob } from 'buffer' ;
88import { IncomingMessage } from 'http' ;
99import * as stream from 'stream' ;
1010import { ReadableStream } from 'stream/web' ;
11- import { FormData , Headers , Request as uRequest } from 'undici' ;
11+ import { FormData , Headers , HeadersInit , Request as uRequest } from 'undici' ;
1212import { URLSearchParams } from 'url' ;
1313import { fromNullableMapping } from '../converters/fromRpcNullable' ;
14+ import { fromRpcTypedData } from '../converters/fromRpcTypedData' ;
1415import { AzFuncSystemError } from '../errors' ;
15- import { nonNullProp } from '../utils/nonNull' ;
16+ import { isDefined , nonNullProp } from '../utils/nonNull' ;
1617import { extractHttpUserFromHeaders } from './extractHttpUserFromHeaders' ;
1718
1819interface InternalHttpRequestInit extends RpcHttpData {
1920 undiciRequest ?: uRequest ;
20- proxyRequest ?: IncomingMessage ;
2121}
2222
23- type RequestInitResult = [ uRequest , URLSearchParams , HttpRequestParams ] ;
24-
2523export class HttpRequest implements types . HttpRequest {
2624 readonly query : URLSearchParams ;
2725 readonly params : HttpRequestParams ;
@@ -33,14 +31,6 @@ export class HttpRequest implements types.HttpRequest {
3331 constructor ( init : InternalHttpRequestInit ) {
3432 this . #init = init ;
3533
36- if ( init . proxyRequest ) {
37- [ this . #uReq, this . query , this . params ] = this . #initStreamRequest( init ) ;
38- } else {
39- [ this . #uReq, this . query , this . params ] = this . #initInMemoryRequest( init ) ;
40- }
41- }
42-
43- #initInMemoryRequest( init : InternalHttpRequestInit ) : RequestInitResult {
4434 let uReq = init . undiciRequest ;
4535 if ( ! uReq ) {
4636 const url = nonNullProp ( init , 'url' ) ;
@@ -58,45 +48,15 @@ export class HttpRequest implements types.HttpRequest {
5848 headers : fromNullableMapping ( init . nullableHeaders , init . headers ) ,
5949 } ) ;
6050 }
51+ this . #uReq = uReq ;
6152
62- const query = new URLSearchParams ( fromNullableMapping ( init . nullableQuery , init . query ) ) ;
63- const params = fromNullableMapping ( init . nullableParams , init . params ) ;
64-
65- return [ uReq , query , params ] ;
66- }
67-
68- #initStreamRequest( init : InternalHttpRequestInit ) : RequestInitResult {
69- const proxyReq = nonNullProp ( init , 'proxyRequest' ) ;
70-
71- const hostHeaderName = 'x-forwarded-host' ;
72- const protoHeaderName = 'x-forwarded-proto' ;
73- const host = proxyReq . headers [ hostHeaderName ] ;
74- const proto = proxyReq . headers [ protoHeaderName ] ;
75- if ( typeof host !== 'string' || typeof proto !== 'string' ) {
76- throw new AzFuncSystemError ( `Expected headers "${ hostHeaderName } " and "${ protoHeaderName } " to be set.` ) ;
77- }
78- const url = `${ proto } ://${ host } ${ nonNullProp ( proxyReq , 'url' ) } ` ;
79-
80- let uReq = init . undiciRequest ;
81- if ( ! uReq ) {
82- let body : stream . Readable | undefined ;
83- const lowerMethod = proxyReq . method ?. toLowerCase ( ) ;
84- if ( lowerMethod !== 'get' && lowerMethod !== 'head' ) {
85- body = proxyReq ;
86- }
87-
88- uReq = new uRequest ( url , {
89- body : body ,
90- duplex : 'half' ,
91- method : nonNullProp ( proxyReq , 'method' ) ,
92- headers : < Record < string , string | ReadonlyArray < string > > > proxyReq . headers ,
93- } ) ;
53+ if ( init . nullableQuery || init . query ) {
54+ this . query = new URLSearchParams ( fromNullableMapping ( init . nullableQuery , init . query ) ) ;
55+ } else {
56+ this . query = new URL ( this . #uReq. url ) . searchParams ;
9457 }
9558
96- const query = new URL ( url ) . searchParams ;
97- const params = fromNullableMapping ( init . nullableParams , init . params ) ;
98-
99- return [ uReq , query , params ] ;
59+ this . params = fromNullableMapping ( init . nullableParams , init . params ) ;
10060 }
10161
10262 get url ( ) : string {
@@ -153,3 +113,54 @@ export class HttpRequest implements types.HttpRequest {
153113 return new HttpRequest ( newInit ) ;
154114 }
155115}
116+
117+ export function createStreamRequest (
118+ proxyReq : IncomingMessage ,
119+ triggerMetadata : Record < string , RpcTypedData >
120+ ) : HttpRequest {
121+ const hostHeaderName = 'x-forwarded-host' ;
122+ const protoHeaderName = 'x-forwarded-proto' ;
123+ const host = proxyReq . headers [ hostHeaderName ] ;
124+ const proto = proxyReq . headers [ protoHeaderName ] ;
125+ if ( typeof host !== 'string' || typeof proto !== 'string' ) {
126+ throw new AzFuncSystemError ( `Expected headers "${ hostHeaderName } " and "${ protoHeaderName } " to be set.` ) ;
127+ }
128+ const url = `${ proto } ://${ host } ${ nonNullProp ( proxyReq , 'url' ) } ` ;
129+
130+ let body : stream . Readable | undefined ;
131+ const lowerMethod = proxyReq . method ?. toLowerCase ( ) ;
132+ if ( lowerMethod !== 'get' && lowerMethod !== 'head' ) {
133+ body = proxyReq ;
134+ }
135+
136+ // Get headers and params from trigger metadata
137+ // See here for more info: https://github.com/Azure/azure-functions-host/issues/9840
138+ // NOTE: We ignore query info because it has this bug: https://github.com/Azure/azure-functions-nodejs-library/issues/168
139+ const { Query : rpcQueryIgnored , Headers : rpcHeaders , ...rpcParams } = triggerMetadata ;
140+
141+ let headers : HeadersInit | undefined ;
142+ const headersData = fromRpcTypedData ( rpcHeaders ) ;
143+ if ( typeof headersData === 'object' && isDefined ( headersData ) ) {
144+ headers = < HeadersInit > headersData ;
145+ }
146+
147+ const uReq = new uRequest ( url , {
148+ body,
149+ duplex : 'half' ,
150+ method : nonNullProp ( proxyReq , 'method' ) ,
151+ headers,
152+ } ) ;
153+
154+ const params : Record < string , string > = { } ;
155+ for ( const [ key , rpcValue ] of Object . entries ( rpcParams ) ) {
156+ const value = fromRpcTypedData ( rpcValue ) ;
157+ if ( typeof value === 'string' ) {
158+ params [ key ] = value ;
159+ }
160+ }
161+
162+ return new HttpRequest ( {
163+ undiciRequest : uReq ,
164+ params,
165+ } ) ;
166+ }
0 commit comments