mirror of https://github.com/hunshcn/gh-proxy
hunshnet
5 years ago
2 changed files with 6 additions and 148 deletions
@ -1,147 +0,0 @@
|
||||
'use strict' |
||||
|
||||
/** |
||||
* static files (404.html, sw.js, conf.js) |
||||
*/ |
||||
const ASSET_URL = 'https://hunshcn.github.io/gh-proxy' |
||||
|
||||
/** @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) |
||||
let path = urlObj.searchParams.get('q') |
||||
if(path) |
||||
{ |
||||
return Response.redirect('https://' + urlObj.host + '/' + path, 301) |
||||
} |
||||
// cfworker 会把路径中的 `//` 合并成 `/`
|
||||
path = urlObj.href.substr(urlObj.origin.length + 1).replace(/^https?:\/+/, 'https://') |
||||
const exp = /^(?:https?:\/\/)?github\.com\/.+?\/.+?\/(?:releases|archive|info|git-upload-pack).*$/ |
||||
const exp2 = /^(?:https?:\/\/)?github\.com\/.+?\/.+?\/(?:blob)\/.*$/ |
||||
if (path.search(exp)===0) { |
||||
return httpHandler(req, path) |
||||
}else if(path.search(exp2)===0){ |
||||
const newUrl = path.replace('/blob/', '@').replace(/^(?:https?:\/\/)?github\.com/, 'https://cdn.jsdelivr.net/gh') |
||||
return Response.redirect(newUrl, 302) |
||||
} else { |
||||
return fetch(ASSET_URL + path) |
||||
} |
||||
} |
||||
|
||||
|
||||
/** |
||||
* @param {Request} req |
||||
* @param {string} pathname |
||||
*/ |
||||
function httpHandler(req, pathname) { |
||||
const reqHdrRaw = req.headers |
||||
|
||||
// preflight
|
||||
if (req.method === 'OPTIONS' && |
||||
reqHdrRaw.has('access-control-request-headers') |
||||
) { |
||||
return new Response(null, PREFLIGHT_INIT) |
||||
} |
||||
|
||||
let rawLen = '' |
||||
|
||||
const reqHdrNew = new Headers(reqHdrRaw) |
||||
|
||||
const refer = reqHdrNew.get('referer') |
||||
|
||||
let urlStr = pathname |
||||
if (urlStr.startsWith('github')) { |
||||
urlStr = 'https://' + urlStr |
||||
} |
||||
const urlObj = newUrl(urlStr) |
||||
|
||||
/** @type {RequestInit} */ |
||||
const reqInit = { |
||||
method: req.method, |
||||
headers: reqHdrNew, |
||||
redirect: 'follow', |
||||
body: req.body |
||||
} |
||||
return proxy(urlObj, reqInit, rawLen, 0) |
||||
} |
||||
|
||||
|
||||
/** |
||||
* |
||||
* @param {URL} urlObj |
||||
* @param {RequestInit} reqInit |
||||
*/ |
||||
async function proxy(urlObj, reqInit, rawLen) { |
||||
const res = await fetch(urlObj.href, reqInit) |
||||
const resHdrOld = res.headers |
||||
const resHdrNew = new Headers(resHdrOld) |
||||
|
||||
// verify
|
||||
if (rawLen) { |
||||
const newLen = resHdrOld.get('content-length') || '' |
||||
const badLen = (rawLen !== newLen) |
||||
|
||||
if (badLen) { |
||||
return makeRes(res.body, 400, { |
||||
'--error': `bad len: ${newLen}, except: ${rawLen}`, |
||||
'access-control-expose-headers': '--error', |
||||
}) |
||||
} |
||||
} |
||||
const 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, |
||||
}) |
||||
} |
||||
|
Loading…
Reference in new issue