-
Notifications
You must be signed in to change notification settings - Fork 549
/
index.js
118 lines (101 loc) · 2.89 KB
/
index.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
'use strict'
/** @type {RequestInit} */
const PREFLIGHT_INIT = {
status: 204,
headers: new Headers({
'access-control-allow-origin': '*',
'access-control-allow-methods': 'GET,POST,PUT,PATCH,TRACE,DELETE,HEAD,OPTIONS',
'access-control-max-age': '1728000',
}),
}
/**
* @param {any} body
* @param {number} status
* @param {Object<string, string>} headers
*/
function makeRes(body, status = 200, headers = {}) {
headers['access-control-allow-origin'] = '*'
return new Response(body, { status, headers })
}
/**
* @param {string} urlStr
*/
function newUrl(urlStr) {
try {
return new URL(urlStr)
} catch (err) {
return null
}
}
addEventListener('fetch', e => {
const ret = fetchHandler(e)
.catch(err => makeRes('cfworker error:\n' + err.stack, 502))
e.respondWith(ret)
})
/**
* @param {FetchEvent} e
*/
async function fetchHandler(e) {
const req = e.request
const urlStr = req.url
const urlObj = new URL(urlStr)
const path = urlObj.href.substr(urlObj.origin.length)
if (path.startsWith('/http/')) {
return await httpHandler(req, path.substr(6))
}
return makeRes('hello!')
}
/**
* @param {Request} req
* @param {string} pathname
*/
async function httpHandler(req, pathname) {
const reqHdrRaw = req.headers
if (reqHdrRaw.has('x-jsproxy')) {
return Response.error()
}
// preflight
if (req.method === 'OPTIONS' && reqHdrRaw.has('access-control-request-headers')) {
return new Response(null, PREFLIGHT_INIT)
}
const reqHdrNew = new Headers(reqHdrRaw)
reqHdrNew.set('x-jsproxy', '1')
if (!reqHdrRaw.has('user-agent')) {
reqHdrRaw.set('user-agent', 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/79.0.3945.130 Safari/537.36')
}
// cfworker 会把路径中的 `//` 合并成 `/`
const urlStr = pathname.replace(/^(https?):\/+/, '$1://')
const urlObj = newUrl(urlStr)
if (!urlObj) {
return makeRes('invalid proxy url: ' + urlStr, 403)
}
/** @type {RequestInit} */
const reqInit = {
method: req.method,
headers: reqHdrNew,
}
if (req.method === 'POST') {
reqInit.body = await req.arrayBuffer()
}
return await proxy(urlObj, reqInit)
}
/**
*
* @param {URL} urlObj
* @param {RequestInit} reqInit
*/
async function proxy(urlObj, reqInit) {
const res = await fetch(urlObj.href, reqInit)
const resHdrOld = res.headers
const resHdrNew = new Headers(resHdrOld)
let status = res.status
resHdrNew.set('access-control-expose-headers', '*')
resHdrNew.set('access-control-allow-origin', '*')
resHdrNew.delete('content-security-policy')
resHdrNew.delete('content-security-policy-report-only')
resHdrNew.delete('clear-site-data')
return new Response(res.body, {
status,
headers: resHdrNew,
})
}