File size: 2,573 Bytes
5ed446f
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
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
import app from "../app.js"

async function writeReadableStreamToWritable(stream, writable) {
    let reader = stream.getReader()

    async function read() {
        let { done, value } = await reader.read()

        if (done) {
            writable.end()
            return
        }

        writable.write(value)

        await read()
    }

    try {
        await read()
    } catch (error) {
        writable.destroy(error)
        throw error
    }
}

class NodeResponse extends Response {
    get headers() {
        return super.headers
    }

    clone() {
        return super.clone()
    }
}
const getRequestListener = (fetchCallback) => {
    return async (incoming, outgoing) => {
        const method = incoming.method || 'GET'
        const url = `http://${incoming.headers.host}${incoming.url}`

        const headerRecord = {}
        const len = incoming.rawHeaders.length
        for (let i = 0; i < len; i++) {
            if (i % 2 === 0) {
                const key = incoming.rawHeaders[i]
                headerRecord[key] = incoming.rawHeaders[i + 1]
            }
        }

        const init = {
            method: method,
            headers: headerRecord,
        }

        if (!(method === 'GET' || method === 'HEAD')) {
            const buffers = []
            for await (const chunk of incoming) {
                buffers.push(chunk)
            }
            const buffer = Buffer.concat(buffers)
            init['body'] = buffer
        }

        let res

        try {
            res = (await fetchCallback(new Request(url.toString(), init)))
        } catch {
            res = new NodeResponse(null, { status: 500 })
        }

        const contentType = res.headers.get('content-type') || ''
        const contentEncoding = res.headers.get('content-encoding')

        for (const [k, v] of res.headers) {
            if (k === 'set-cookie') {
                outgoing.setHeader(k, res.headers.getAll(k))
            } else {
                outgoing.setHeader(k, v)
            }
        }
        outgoing.statusCode = res.status

        if (res.body) {
            if (!contentEncoding && contentType.startsWith('text')) {
                outgoing.end(await res.text())
            } else if (!contentEncoding && contentType.startsWith('application/json')) {
                outgoing.end(await res.text())
            } else {
                await writeReadableStreamToWritable(res.body, outgoing)
            }
        } else {
            outgoing.end()
        }
    }
}

export default getRequestListener(app.fetch)