Create gh-proxy
This commit is contained in:
parent
d6b54061b6
commit
5eb506adbd
|
@ -0,0 +1,42 @@
|
|||
name: "gh-proxy docker build"
|
||||
|
||||
env:
|
||||
PROJECT: gh-proxy
|
||||
|
||||
on:
|
||||
workflow_dispatch:
|
||||
|
||||
jobs:
|
||||
build:
|
||||
runs-on: ubuntu-latest
|
||||
env:
|
||||
ACTIONS_ALLOW_UNSECURE_COMMANDS: true
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v2
|
||||
- name: Set tag
|
||||
id: tag
|
||||
run: |
|
||||
TAG=$(cat ${{ env.PROJECT }}/Dockerfile | awk 'NR==4 {print $3}')
|
||||
echo "::set-env name=TAG::$TAG"
|
||||
- name: Docker Hub login
|
||||
env:
|
||||
DOCKER_USERNAME: ${{ secrets.DOCKER_USERNAME }}
|
||||
DOCKER_PASSWORD: ${{ secrets.DOCKER_PASSWORD }}
|
||||
run: |
|
||||
echo "${DOCKER_PASSWORD}" | docker login --username ${DOCKER_USERNAME} --password-stdin
|
||||
- name: Set up Docker Buildx
|
||||
id: buildx
|
||||
uses: crazy-max/ghaction-docker-buildx@v1
|
||||
with:
|
||||
buildx-version: latest
|
||||
- name: Build Dockerfile
|
||||
env:
|
||||
DOCKER_USERNAME: ${{ secrets.DOCKER_USERNAME }}
|
||||
run: |
|
||||
docker buildx build \
|
||||
--platform=linux/amd64,linux/arm64 \
|
||||
--output "type=image,push=true" \
|
||||
--file ${{ env.PROJECT }}/Dockerfile ./${{ env.PROJECT }} \
|
||||
--tag $(echo "${DOCKER_USERNAME}" | tr '[:upper:]' '[:lower:]')/${{ env.PROJECT }}:latest \
|
||||
--tag $(echo "${DOCKER_USERNAME}" | tr '[:upper:]' '[:lower:]')/${{ env.PROJECT }}:${TAG}
|
|
@ -0,0 +1,28 @@
|
|||
FROM stilleshan/uwsgi-nginx:python3.7
|
||||
LABEL maintainer="Sebastian Ramirez <tiangolo@gmail.com>"
|
||||
|
||||
ENV VERSION 2.1
|
||||
|
||||
RUN pip install flask requests
|
||||
|
||||
COPY ./app /app
|
||||
WORKDIR /app
|
||||
|
||||
# Make /app/* available to be imported by Python globally to better support several use cases like Alembic migrations.
|
||||
ENV PYTHONPATH=/app
|
||||
|
||||
# Move the base entrypoint to reuse it
|
||||
RUN mv /entrypoint.sh /uwsgi-nginx-entrypoint.sh
|
||||
# Copy the entrypoint that will generate Nginx additional configs
|
||||
COPY entrypoint.sh /entrypoint.sh
|
||||
RUN chmod +x /entrypoint.sh
|
||||
|
||||
ENTRYPOINT ["/entrypoint.sh"]
|
||||
|
||||
# Run the start script provided by the parent image tiangolo/uwsgi-nginx.
|
||||
# It will check for an /app/prestart.sh script (e.g. for migrations)
|
||||
# And then will start Supervisor, which in turn will start Nginx and uWSGI
|
||||
|
||||
EXPOSE 80
|
||||
|
||||
CMD ["/start.sh"]
|
|
@ -0,0 +1,21 @@
|
|||
MIT License
|
||||
|
||||
Copyright (c) 2020 hunshcn
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
|
@ -0,0 +1,110 @@
|
|||
# gh-proxy
|
||||
|
||||
## 简介
|
||||
|
||||
github release、archive以及项目文件的加速项目,支持clone,有Cloudflare Workers无服务器版本以及Python版本
|
||||
|
||||
## 演示
|
||||
|
||||
[https://gh.api.99988866.xyz/](https://gh.api.99988866.xyz/)
|
||||
|
||||
演示站为公共服务,如有大规模使用需求请自行部署,演示站有点不堪重负
|
||||
|
||||
![imagea272c95887343279.png](https://img.maocdn.cn/img/2021/04/24/imagea272c95887343279.png)
|
||||
|
||||
当然也欢迎[捐赠](#捐赠)以支持作者
|
||||
|
||||
## python版本和cf worker版本差异
|
||||
|
||||
- python版本支持进行文件大小限制,超过设定返回原地址 [issue #8](https://github.com/hunshcn/gh-proxy/issues/8)
|
||||
|
||||
## 使用
|
||||
|
||||
直接在copy出来的url前加`https://gh.api.99988866.xyz/`即可
|
||||
|
||||
也可以直接访问,在input输入
|
||||
|
||||
***大量使用请自行部署,以上域名仅为演示使用。***
|
||||
|
||||
以下都是合法输入(仅示例,文件不存在):
|
||||
|
||||
- 分支源码:https://github.com/hunshcn/project/archive/master.zip
|
||||
|
||||
- release源码:https://github.com/hunshcn/project/archive/v0.1.0.tar.gz
|
||||
|
||||
- release文件:https://github.com/hunshcn/project/releases/download/v0.1.0/example.zip
|
||||
|
||||
- 分支文件:https://github.com/hunshcn/project/blob/master/filename
|
||||
|
||||
- commit文件:https://github.com/hunshcn/project/blob/1111111111111111111111111111/filename
|
||||
|
||||
- gist:https://gist.githubusercontent.com/cielpy/351557e6e465c12986419ac5a4dd2568/raw/cmd.py
|
||||
|
||||
## cf worker版本部署
|
||||
|
||||
首页:https://workers.cloudflare.com
|
||||
|
||||
注册,登陆,`Start building`,取一个子域名,`Create a Worker`。
|
||||
|
||||
复制 [index.js](https://cdn.jsdelivr.net/hunshcn/gh-proxy@master/index.js) 到左侧代码框,`Save and deploy`。如果正常,右侧应显示首页。
|
||||
|
||||
`index.js`默认配置下clone走github.com.cnpmjs.org,项目文件会走jsDeliver,如需走worker,修改Config变量即可
|
||||
|
||||
`ASSET_URL`是静态资源的url(实际上就是现在显示出来的那个输入框单页面)
|
||||
|
||||
`PREFIX`是前缀,默认(根路径情况为"/"),如果自定义路由为example.com/gh/*,请将PREFIX改为 '/gh/',注意,少一个杠都会错!
|
||||
|
||||
## Python版本部署
|
||||
|
||||
### Docker部署
|
||||
|
||||
```
|
||||
docker run -d --name="gh-proxy-py" \
|
||||
-p 0.0.0.0:80:80 \
|
||||
--restart=always \
|
||||
hunsh/gh-proxy-py:latest
|
||||
```
|
||||
|
||||
第一个80是你要暴露出去的端口
|
||||
|
||||
### 直接部署
|
||||
|
||||
安装依赖(请使用python3)
|
||||
|
||||
```pip install flask requests```
|
||||
|
||||
按需求修改`app/main.py`的前几项配置
|
||||
|
||||
### 注意
|
||||
|
||||
python版本的机器如果无法正常访问github.io会启动报错,请自行修改静态文件url
|
||||
|
||||
workers版本默认配置下clone走github.com.cnpmjs.org,项目文件会走jsDeliver,如需走服务器,修改配置即可
|
||||
|
||||
python版本默认走服务器(2021.3.27更新)
|
||||
|
||||
## Cloudflare Workers计费
|
||||
|
||||
到 `overview` 页面可参看使用情况。免费版每天有 10 万次免费请求,并且有每分钟1000次请求的限制。
|
||||
|
||||
如果不够用,可升级到 $5 的高级版本,每月可用 1000 万次请求(超出部分 $0.5/百万次请求)。
|
||||
|
||||
## Changelog
|
||||
|
||||
* 2020.04.10 增加对`raw.githubusercontent.com`文件的支持
|
||||
* 2020.04.09 增加Python版本(使用Flask)
|
||||
* 2020.03.23 新增了clone的支持
|
||||
* 2020.03.22 初始版本
|
||||
|
||||
## 链接
|
||||
|
||||
[我的博客](https://hunsh.net)
|
||||
|
||||
## 参考
|
||||
|
||||
[jsproxy](https://github.com/EtherDream/jsproxy/)
|
||||
|
||||
## 捐赠
|
||||
|
||||
![wx.png](https://img.maocdn.cn/img/2021/04/24/image.md.png)
|
||||
![ali.png](https://www.helloimg.com/images/2021/04/24/BK9vmb.md.png)
|
|
@ -0,0 +1,137 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
import re
|
||||
|
||||
import requests
|
||||
from flask import Flask, Response, redirect, request
|
||||
from requests.exceptions import (
|
||||
ChunkedEncodingError,
|
||||
ContentDecodingError, ConnectionError, StreamConsumedError)
|
||||
from requests.utils import (
|
||||
stream_decode_response_unicode, iter_slices, CaseInsensitiveDict)
|
||||
from urllib3.exceptions import (
|
||||
DecodeError, ReadTimeoutError, ProtocolError)
|
||||
|
||||
# config
|
||||
# git使用cnpmjs镜像、分支文件使用jsDelivr镜像的开关,0为关闭,默认关闭
|
||||
jsdelivr = 0
|
||||
cnpmjs = 0
|
||||
size_limit = 1024 * 1024 * 1024 * 999 # 允许的文件大小,默认999GB,相当于无限制了 https://github.com/hunshcn/gh-proxy/issues/8
|
||||
HOST = '127.0.0.1' # 监听地址,建议监听本地然后由web服务器反代
|
||||
PORT = 80 # 监听端口
|
||||
ASSET_URL = 'https://hunshcn.github.io/gh-proxy' # 主页
|
||||
|
||||
app = Flask(__name__)
|
||||
CHUNK_SIZE = 1024 * 10
|
||||
index_html = requests.get(ASSET_URL, timeout=10).text
|
||||
icon_r = requests.get(ASSET_URL + '/favicon.ico', timeout=10).content
|
||||
exp1 = re.compile(r'^(?:https?://)?github\.com/.+?/.+?/(?:releases|archive)/.*$')
|
||||
exp2 = re.compile(r'^(?:https?://)?github\.com/.+?/.+?/(?:blob)/.*$')
|
||||
exp3 = re.compile(r'^(?:https?://)?github\.com/.+?/.+?/(?:info|git-).*$')
|
||||
exp4 = re.compile(r'^(?:https?://)?raw\.githubusercontent\.com/.+?/.+?/.+?/.+$')
|
||||
exp5 = re.compile(r'^(?:https?://)?gist\.(?:githubusercontent|github)\.com/.+?/.+?/.+$')
|
||||
|
||||
requests.sessions.default_headers = lambda: CaseInsensitiveDict()
|
||||
|
||||
|
||||
@app.route('/')
|
||||
def index():
|
||||
if 'q' in request.args:
|
||||
return redirect('/' + request.args.get('q'))
|
||||
return index_html
|
||||
|
||||
|
||||
@app.route('/favicon.ico')
|
||||
def icon():
|
||||
return Response(icon_r, content_type='image/vnd.microsoft.icon')
|
||||
|
||||
|
||||
def iter_content(self, chunk_size=1, decode_unicode=False):
|
||||
"""rewrite requests function, set decode_content with False"""
|
||||
|
||||
def generate():
|
||||
# Special case for urllib3.
|
||||
if hasattr(self.raw, 'stream'):
|
||||
try:
|
||||
for chunk in self.raw.stream(chunk_size, decode_content=False):
|
||||
yield chunk
|
||||
except ProtocolError as e:
|
||||
raise ChunkedEncodingError(e)
|
||||
except DecodeError as e:
|
||||
raise ContentDecodingError(e)
|
||||
except ReadTimeoutError as e:
|
||||
raise ConnectionError(e)
|
||||
else:
|
||||
# Standard file-like object.
|
||||
while True:
|
||||
chunk = self.raw.read(chunk_size)
|
||||
if not chunk:
|
||||
break
|
||||
yield chunk
|
||||
|
||||
self._content_consumed = True
|
||||
|
||||
if self._content_consumed and isinstance(self._content, bool):
|
||||
raise StreamConsumedError()
|
||||
elif chunk_size is not None and not isinstance(chunk_size, int):
|
||||
raise TypeError("chunk_size must be an int, it is instead a %s." % type(chunk_size))
|
||||
# simulate reading small chunks of the content
|
||||
reused_chunks = iter_slices(self._content, chunk_size)
|
||||
|
||||
stream_chunks = generate()
|
||||
|
||||
chunks = reused_chunks if self._content_consumed else stream_chunks
|
||||
|
||||
if decode_unicode:
|
||||
chunks = stream_decode_response_unicode(chunks, self)
|
||||
|
||||
return chunks
|
||||
|
||||
|
||||
@app.route('/<path:u>', methods=['GET', 'POST'])
|
||||
def proxy(u):
|
||||
u = u if u.startswith('http') else 'https://' + u
|
||||
if u.rfind('://', 3, 9) == -1:
|
||||
u = u.replace('s:/', 's://', 1) # uwsgi会将//传递为/
|
||||
if not any([i.match(u) for i in [exp1, exp2, exp3, exp4, exp5]]):
|
||||
return Response('Invalid input.', status=403)
|
||||
if jsdelivr and exp2.match(u):
|
||||
u = u.replace('/blob/', '@', 1).replace('github.com', 'cdn.jsdelivr.net/gh', 1)
|
||||
return redirect(u)
|
||||
elif cnpmjs and exp3.match(u):
|
||||
u = u.replace('github.com', 'github.com.cnpmjs.org', 1) + request.url.replace(request.base_url, '', 1)
|
||||
return redirect(u)
|
||||
elif jsdelivr and exp4.match(u):
|
||||
u = re.sub(r'(\.com/.*?/.+?)/(.+?/)', r'\1@\2', u, 1)
|
||||
u = u.replace('raw.githubusercontent.com', 'cdn.jsdelivr.net/gh', 1)
|
||||
return redirect(u)
|
||||
else:
|
||||
if exp2.match(u):
|
||||
u = u.replace('/blob/', '/raw/', 1)
|
||||
headers = {}
|
||||
r_headers = dict(request.headers)
|
||||
if 'Host' in r_headers:
|
||||
r_headers.pop('Host')
|
||||
try:
|
||||
url = u + request.url.replace(request.base_url, '', 1)
|
||||
if url.startswith('https:/') and not url.startswith('https://'):
|
||||
url = 'https://' + url[7:]
|
||||
r = requests.request(method=request.method, url=url, data=request.data, headers=r_headers, stream=True)
|
||||
headers = dict(r.headers)
|
||||
|
||||
if 'Content-length' in r.headers and int(r.headers['Content-length']) > size_limit:
|
||||
return redirect(u + request.url.replace(request.base_url, '', 1))
|
||||
|
||||
def generate():
|
||||
for chunk in iter_content(r, chunk_size=CHUNK_SIZE):
|
||||
yield chunk
|
||||
|
||||
return Response(generate(), headers=headers, status=r.status_code)
|
||||
except Exception as e:
|
||||
headers['content-type'] = 'text/html; charset=UTF-8'
|
||||
return Response('server error ' + str(e), status=500, headers=headers)
|
||||
# else:
|
||||
# return Response('Illegal input', status=403, mimetype='text/html; charset=UTF-8')
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
app.run(host=HOST, port=PORT)
|
|
@ -0,0 +1,3 @@
|
|||
[uwsgi]
|
||||
module = main
|
||||
callable = app
|
|
@ -0,0 +1,26 @@
|
|||
#! /usr/bin/env bash
|
||||
set -e
|
||||
|
||||
/uwsgi-nginx-entrypoint.sh
|
||||
|
||||
# Get the listen port for Nginx, default to 80
|
||||
USE_LISTEN_PORT=${LISTEN_PORT:-80}
|
||||
|
||||
if [ -f /app/nginx.conf ]; then
|
||||
cp /app/nginx.conf /etc/nginx/nginx.conf
|
||||
else
|
||||
content_server='server {\n'
|
||||
content_server=$content_server" listen ${USE_LISTEN_PORT};\n"
|
||||
content_server=$content_server' location / {\n'
|
||||
content_server=$content_server' try_files $uri @app;\n'
|
||||
content_server=$content_server' }\n'
|
||||
content_server=$content_server' location @app {\n'
|
||||
content_server=$content_server' include uwsgi_params;\n'
|
||||
content_server=$content_server' uwsgi_pass unix:///tmp/uwsgi.sock;\n'
|
||||
content_server=$content_server' }\n'
|
||||
content_server=$content_server'}\n'
|
||||
# Save generated server /etc/nginx/conf.d/nginx.conf
|
||||
printf "$content_server" > /etc/nginx/conf.d/nginx.conf
|
||||
fi
|
||||
|
||||
exec "$@"
|
|
@ -0,0 +1,165 @@
|
|||
'use strict'
|
||||
|
||||
/**
|
||||
* static files (404.html, sw.js, conf.js)
|
||||
*/
|
||||
const ASSET_URL = 'https://hunshcn.github.io/gh-proxy/'
|
||||
// 前缀,如果自定义路由为example.com/gh/*,将PREFIX改为 '/gh/',注意,少一个杠都会错!
|
||||
const PREFIX = '/'
|
||||
// git使用cnpmjs镜像、分支文件使用jsDelivr镜像的开关,0为关闭,默认开启
|
||||
const Config = {
|
||||
jsdelivr: 1,
|
||||
cnpmjs: 1
|
||||
}
|
||||
|
||||
/** @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 + PREFIX + path, 301)
|
||||
}
|
||||
// cfworker 会把路径中的 `//` 合并成 `/`
|
||||
path = urlObj.href.substr(urlObj.origin.length + PREFIX.length).replace(/^https?:\/+/, 'https://')
|
||||
const exp1 = /^(?:https?:\/\/)?github\.com\/.+?\/.+?\/(?:releases|archive)\/.*$/i
|
||||
const exp2 = /^(?:https?:\/\/)?github\.com\/.+?\/.+?\/(?:blob)\/.*$/i
|
||||
const exp3 = /^(?:https?:\/\/)?github\.com\/.+?\/.+?\/(?:info|git-).*$/i
|
||||
const exp4 = /^(?:https?:\/\/)?raw\.githubusercontent\.com\/.+?\/.+?\/.+?\/.+$/i
|
||||
const exp5 = /^(?:https?:\/\/)?gist\.(?:githubusercontent|github)\.com\/.+?\/.+?\/.+$/i
|
||||
if (path.search(exp1) === 0 || path.search(exp5) === 0 || !Config.cnpmjs && (path.search(exp3) === 0 || path.search(exp4) === 0)) {
|
||||
return httpHandler(req, path)
|
||||
} else if (path.search(exp2) === 0) {
|
||||
if (Config.jsdelivr){
|
||||
const newUrl = path.replace('/blob/', '@').replace(/^(?:https?:\/\/)?github\.com/, 'https://cdn.jsdelivr.net/gh')
|
||||
return Response.redirect(newUrl, 302)
|
||||
}else{
|
||||
path = path.replace('/blob/', '/raw/')
|
||||
return httpHandler(req, path)
|
||||
}
|
||||
} else if (path.search(exp3) === 0) {
|
||||
const newUrl = path.replace(/^(?:https?:\/\/)?github\.com/, 'https://github.com.cnpmjs.org')
|
||||
return Response.redirect(newUrl, 302)
|
||||
} else if (path.search(exp4) === 0) {
|
||||
const newUrl = path.replace(/(?<=com\/.+?\/.+?)\/(.+?\/)/, '@$1').replace(/^(?:https?:\/\/)?raw\.githubusercontent\.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)
|
||||
|
||||
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