3
3
4
4
import * as types from '@azure/functions' ;
5
5
import { HttpRequestParams , HttpRequestUser } from '@azure/functions' ;
6
- import { RpcHttpData } from '@azure/functions-core' ;
6
+ import { RpcHttpData , RpcTypedData } from '@azure/functions-core' ;
7
7
import { Blob } from 'buffer' ;
8
8
import { IncomingMessage } from 'http' ;
9
9
import * as stream from 'stream' ;
10
10
import { ReadableStream } from 'stream/web' ;
11
- import { FormData , Headers , Request as uRequest } from 'undici' ;
11
+ import { FormData , Headers , HeadersInit , Request as uRequest } from 'undici' ;
12
12
import { URLSearchParams } from 'url' ;
13
13
import { fromNullableMapping } from '../converters/fromRpcNullable' ;
14
+ import { fromRpcTypedData } from '../converters/fromRpcTypedData' ;
14
15
import { AzFuncSystemError } from '../errors' ;
15
- import { nonNullProp } from '../utils/nonNull' ;
16
+ import { isDefined , nonNullProp } from '../utils/nonNull' ;
16
17
import { extractHttpUserFromHeaders } from './extractHttpUserFromHeaders' ;
17
18
18
19
interface InternalHttpRequestInit extends RpcHttpData {
19
20
undiciRequest ?: uRequest ;
20
- proxyRequest ?: IncomingMessage ;
21
21
}
22
22
23
- type RequestInitResult = [ uRequest , URLSearchParams , HttpRequestParams ] ;
24
-
25
23
export class HttpRequest implements types . HttpRequest {
26
24
readonly query : URLSearchParams ;
27
25
readonly params : HttpRequestParams ;
@@ -33,14 +31,6 @@ export class HttpRequest implements types.HttpRequest {
33
31
constructor ( init : InternalHttpRequestInit ) {
34
32
this . #init = init ;
35
33
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 {
44
34
let uReq = init . undiciRequest ;
45
35
if ( ! uReq ) {
46
36
const url = nonNullProp ( init , 'url' ) ;
@@ -58,45 +48,15 @@ export class HttpRequest implements types.HttpRequest {
58
48
headers : fromNullableMapping ( init . nullableHeaders , init . headers ) ,
59
49
} ) ;
60
50
}
51
+ this . #uReq = uReq ;
61
52
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 ;
94
57
}
95
58
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 ) ;
100
60
}
101
61
102
62
get url ( ) : string {
@@ -153,3 +113,54 @@ export class HttpRequest implements types.HttpRequest {
153
113
return new HttpRequest ( newInit ) ;
154
114
}
155
115
}
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