-
Notifications
You must be signed in to change notification settings - Fork 66
/
fetch-to-handler.js
119 lines (101 loc) · 2.74 KB
/
fetch-to-handler.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
import fs from 'fs-extra'
import { Readable } from 'stream'
/*
export const CORS_HEADERS = [
'Access-Control-Allow-Origin',
'Allow-CSP-From',
'Access-Control-Allow-Headers',
'Access-Control-Allow-Methods',
'Access-Control-Request-Headers'
]
*/
export default function fetchToHandler (getFetch, session) {
let hasFetch = null
let loadingFetch = null
async function load () {
try {
if (hasFetch) return hasFetch
if (loadingFetch) return loadingFetch
loadingFetch = Promise.resolve(getFetch()).then((fetch) => {
hasFetch = fetch
return fetch
})
return loadingFetch
} finally {
loadingFetch = null
}
}
async function * readBody (body) {
for (const chunk of body) {
if (chunk.bytes) {
yield await Promise.resolve(chunk.bytes)
} else if (chunk.blobUUID) {
yield await session.getBlobData(chunk.blobUUID)
} else if (chunk.file) {
yield * Readable.from(fs.createReadStream(chunk.file))
}
}
}
const close = async () => {
if (loadingFetch) {
await loadingFetch
await close()
} else if (hasFetch) {
if (hasFetch.close) await hasFetch.close()
else if (hasFetch.destroy) await hasFetch.destroy()
}
}
return { handler: protocolHandler, close }
async function protocolHandler (req, sendResponse) {
const headers = {
'Access-Control-Allow-Origin': '*',
'Allow-CSP-From': '*',
'Access-Control-Allow-Headers': '*',
'Access-Control-Allow-Methods': '*',
'Access-Control-Request-Headers': '*'
}
try {
// Lazy load fetch implementation
const fetch = await load()
const { url, headers: requestHeaders, method, uploadData } = req
const body = uploadData ? Readable.from(readBody(uploadData)) : null
const response = await fetch(url, {
method,
headers: requestHeaders,
body,
session,
duplex: 'half'
})
const { status: statusCode, body: responseBody, headers: responseHeaders } = response
for (const [key, value] of responseHeaders) {
if (Array.isArray(value)) {
headers[key] = value[0]
} else {
headers[key] = value
}
}
const isAsync = responseBody && responseBody[Symbol.asyncIterator]
const data = isAsync ? Readable.from(responseBody, { objectMode: false }) : responseBody
sendResponse({
statusCode,
headers,
data
})
} catch (e) {
console.log(e)
sendResponse({
statusCode: 500,
headers,
data: intoStream(e.stack)
})
}
}
}
function intoStream (data) {
return new Readable({
read () {
this.push(data)
this.push(null)
}
})
}