1
0
Эх сурвалжийг харах

实验无法满足 https://fetch.spec.whatwg.org/#cors-unsafe-request-header-byte

zjcqoo 6 жил өмнө
parent
commit
3391d1df8b

+ 6 - 3
api.conf

@@ -27,15 +27,18 @@ location = /preflight {
   more_set_headers
   more_set_headers
     'access-control-allow-origin: *'
     'access-control-allow-origin: *'
     'access-control-allow-methods: GET,POST,PUT,PATCH,TRACE,DELETE,HEAD,OPTIONS'
     'access-control-allow-methods: GET,POST,PUT,PATCH,TRACE,DELETE,HEAD,OPTIONS'
-    'access-control-allow-headers: --raw-info,--level,--url,--referer,--cookie,--origin,--ext,--aceh,--ver,--type,--mode,accept,accept-charset,accept-encoding,accept-language,accept-datetime,authorization,cache-control,content-length,content-type,date,if-match,if-modified-since,if-none-match,if-range,if-unmodified-since,max-forwards,pragma,range,te,upgrade,upgrade-insecure-requests,x-requested-with,chrome-proxy,purpose'
     'access-control-max-age: 1728000'
     'access-control-max-age: 1728000'
   ;
   ;
   return              204;
   return              204;
 }
 }
 
 
+# 该接口已作废
+location = /http {
+  rewrite             ^   /error?msg=API_OBSOLETED;
+}
 
 
 # HTTP(S) Proxy
 # HTTP(S) Proxy
-location = /http {
+location /http/ {
   # see ./allowed-sites.conf
   # see ./allowed-sites.conf
   if ($_origin_id = '') {
   if ($_origin_id = '') {
     rewrite             ^   /error?msg=ORIGIN_NOT_ALLOWED;
     rewrite             ^   /error?msg=ORIGIN_NOT_ALLOWED;
@@ -47,7 +50,7 @@ location = /http {
   proxy_set_header      Connection  $http_connection;
   proxy_set_header      Connection  $http_connection;
   
   
 
 
-  if ($http_access_control_request_headers) {
+  if ($http_access_control_request_methods) {
     rewrite             ^   /preflight;
     rewrite             ^   /preflight;
   }
   }
 
 

+ 3 - 0
cert/cert.conf

@@ -0,0 +1,3 @@
+listen                8443 ssl http2;
+ssl_certificate       cert/etherdream.com/ecc.cer;
+ssl_certificate_key   cert/etherdream.com/ecc.key;

+ 0 - 17
cf-worker/README.md

@@ -23,29 +23,12 @@
 
 
 如果不够用,可注册多个 Worker,在 `conf.js` 中配置多线路负载均衡。或者升级到 $5 的高级版本,每月可用 1000 万次请求(超出部分 $0.5/百万次请求)。
 如果不够用,可注册多个 Worker,在 `conf.js` 中配置多线路负载均衡。或者升级到 $5 的高级版本,每月可用 1000 万次请求(超出部分 $0.5/百万次请求)。
 
 
-如果远不够用,建议和服务器组合使用。因为 cfworker 是按请求次数计费的,所以小文件更适合通过服务器代理,大文件走 cfworker 才合算。可参考下面的 `加速功能`。
-
 
 
 # 修改配置
 # 修改配置
 
 
 默认情况下,静态资源从 `https://zjcqoo.github.io` 反向代理,可通过代码中 `ASSET_URL` 配置,从而可使用自定义的 `conf.js` 配置。
 默认情况下,静态资源从 `https://zjcqoo.github.io` 反向代理,可通过代码中 `ASSET_URL` 配置,从而可使用自定义的 `conf.js` 配置。
 
 
 
 
-# 加速功能
-
-如果你已有服务器,也可通过 CloudFlare Worker 分担大文件的代理。
-
-前端修改:`conf.js` 的 `cfworker` 节点 `lines` 配置。
-
-后端修改:`lua/http-enc-res-hdr.lua` 的 [114-116 行](https://github.com/EtherDream/jsproxy/blob/master/lua/http-enc-res-hdr.lua#L114-L116) 注释打开,重启服务生效。
-
-可在 [84行](https://github.com/EtherDream/jsproxy/blob/master/lua/http-enc-res-hdr.lua#L84) 处修改大于多少字节的静态资源走加速。
-
-该功能目前还在实验中,有问题或者更好的思路可交流。
-
-(推荐下行流量免费且不限速的服务器,可节省大量费用)
-
-
 # 存在问题
 # 存在问题
 
 
 * WebSocket 代理尚未实现
 * WebSocket 代理尚未实现

+ 30 - 41
cf-worker/index.js

@@ -25,8 +25,6 @@ const PREFLIGHT_INIT = {
  * @param {Object<string, string>} headers
  * @param {Object<string, string>} headers
  */
  */
 function makeRes(body, status = 200, headers = {}) {
 function makeRes(body, status = 200, headers = {}) {
-  headers['cache-control'] = 'no-cache'
-  headers['vary'] = '--url'
   headers['--ver'] = JS_VER
   headers['--ver'] = JS_VER
   headers['access-control-allow-origin'] = '*'
   headers['access-control-allow-origin'] = '*'
   return new Response(body, {status, headers})
   return new Response(body, {status, headers})
@@ -47,6 +45,7 @@ async function fetchHandler(e) {
   const req = e.request
   const req = e.request
   const urlStr = req.url
   const urlStr = req.url
   const urlObj = new URL(urlStr)
   const urlObj = new URL(urlStr)
+  const {pathname} = urlObj
 
 
   if (urlObj.protocol === 'http:') {
   if (urlObj.protocol === 'http:') {
     urlObj.protocol = 'https:'
     urlObj.protocol = 'https:'
@@ -56,16 +55,18 @@ async function fetchHandler(e) {
     })
     })
   }
   }
 
 
-  switch (urlObj.pathname) {
-  case '/http':
+  if (pathname.startsWith('/http')) {
     return httpHandler(req)
     return httpHandler(req)
+  }
+
+  switch (pathname) {
   case '/ws':
   case '/ws':
     return makeRes('not support', 400)
     return makeRes('not support', 400)
   case '/works':
   case '/works':
     return makeRes('it works')
     return makeRes('it works')
   default:
   default:
     // static files
     // static files
-    return fetch(ASSET_URL + urlObj.pathname)
+    return fetch(ASSET_URL + pathname)
   }
   }
 }
 }
 
 
@@ -86,8 +87,13 @@ function httpHandler(req) {
     return new Response(null, PREFLIGHT_INIT)
     return new Response(null, PREFLIGHT_INIT)
   }
   }
 
 
-  let urlObj = null
-  let extHdrs = null
+  const urlStr = req.url.substr(6)
+  try {
+    var urlObj = new URL(urlStr)
+  } catch (err) {
+    return makeRes('invalid url: ' + urlStr, 403)
+  }
+
   let acehOld = false
   let acehOld = false
   let rawSvr = ''
   let rawSvr = ''
   let rawLen = ''
   let rawLen = ''
@@ -96,46 +102,34 @@ function httpHandler(req) {
   const reqHdrNew = new Headers(reqHdrRaw)
   const reqHdrNew = new Headers(reqHdrRaw)
   reqHdrNew.set('x-jsproxy', '1')
   reqHdrNew.set('x-jsproxy', '1')
 
 
-  for (const [k, v] of reqHdrRaw.entries()) {
-    if (!k.startsWith('--')) {
-      continue
-    }
-    reqHdrNew.delete(k)
+  // 此处逻辑和 http-dec-req-hdr.lua 大致相同
+  // https://github.com/EtherDream/jsproxy/blob/master/lua/http-dec-req-hdr.lua
+  const {sys, ext} = JSON.parse(reqHdrNew.get('accept'))
 
 
-    const k2 = k.substr(2)
-    switch (k2) {
-    case 'url':
-      urlObj = new URL(v)
-      break
+  // 系统信息
+  for (const [k, v] of Object.entries(sys)) {
+    switch (k) {
     case 'aceh':
     case 'aceh':
       acehOld = true
       acehOld = true
       break
       break
     case 'raw-info':
     case 'raw-info':
       [rawSvr, rawLen, rawEtag] = v.split('|')
       [rawSvr, rawLen, rawEtag] = v.split('|')
       break
       break
-    case 'level':
-    case 'mode':
-    case 'type':
-      break
-    case 'ext':
-      extHdrs = JSON.parse(v)
-      break
-    default:
-      if (v) {
-        reqHdrNew.set(k2, v)
-      } else {
-        reqHdrNew.delete(k2)
-      }
-      break
     }
     }
   }
   }
-  if (extHdrs) {
-    for (const [k, v] of Object.entries(extHdrs)) {
-      reqHdrNew.set(k, v)
+
+  // 原始 HTTP 字段
+  let hasRawAccept = false
+
+  for (const [k, v] of Object.entries(ext)) {
+    if (k === 'accept') {
+      hasRawAccept = true
     }
     }
+    reqHdrNew.set(k, v)
   }
   }
-  if (!urlObj) {
-    return makeRes('missing url param', 403)
+
+  if (!hasRawAccept) {
+    reqHdrNew.delete('accept')
   }
   }
 
 
   /** @type {RequestInit} */
   /** @type {RequestInit} */
@@ -163,7 +157,6 @@ async function proxy(urlObj, reqInit, acehOld, rawLen, retryTimes) {
   const resHdrNew = new Headers(resHdrOld)
   const resHdrNew = new Headers(resHdrOld)
 
 
   let expose = '*'
   let expose = '*'
-  let vary = '--url'
   
   
   for (const [k, v] of resHdrOld.entries()) {
   for (const [k, v] of resHdrOld.entries()) {
     if (k === 'access-control-allow-origin' ||
     if (k === 'access-control-allow-origin' ||
@@ -178,9 +171,6 @@ async function proxy(urlObj, reqInit, acehOld, rawLen, retryTimes) {
       }
       }
       resHdrNew.delete(k)
       resHdrNew.delete(k)
     }
     }
-    else if (k === 'vary') {
-      vary = vary + ',' + v
-    }
     else if (acehOld &&
     else if (acehOld &&
       k !== 'cache-control' &&
       k !== 'cache-control' &&
       k !== 'content-language' &&
       k !== 'content-language' &&
@@ -225,7 +215,6 @@ async function proxy(urlObj, reqInit, acehOld, rawLen, retryTimes) {
 
 
   resHdrNew.set('access-control-expose-headers', expose)
   resHdrNew.set('access-control-expose-headers', expose)
   resHdrNew.set('access-control-allow-origin', '*')
   resHdrNew.set('access-control-allow-origin', '*')
-  resHdrNew.set('vary', vary)
   resHdrNew.set('--s', status)
   resHdrNew.set('--s', status)
   resHdrNew.set('--ver', JS_VER)
   resHdrNew.set('--ver', JS_VER)
 
 

+ 29 - 26
lua/http-dec-req-hdr.lua

@@ -1,20 +1,18 @@
--- 功能:还原 HTTP 请求头
--- 阶段:access_by_lua
+-- 还原 HTTP 请求头
+-- 前端只保留简单字段(防止出现 preflight),
+-- 其余字段及系统信息,存储在 Accept 字段里(JSON 格式)。
 
 
+local cjson = require('cjson')
 local hdrs, err = ngx.req.get_headers()
 local hdrs, err = ngx.req.get_headers()
-local extHdrs
+ngx.log(ngx.ALERT, 'accept:' .. hdrs['accept'])
+local info = ngx.unescape_uri(hdrs['accept'])
+local json = cjson.decode(info)
 
 
-for k, v in pairs(hdrs) do
-  if k:sub(1, 2) ~= '--' then
-    goto continue
-  end
-
-  ngx.req.clear_header(k)
-  k = k:sub(3)
+-- 系统信息
+local sys = json['sys']
 
 
-  if k == 'url' then
-    ngx.var._url = v
-  elseif k == 'ver' then
+for k, v in pairs(sys) do
+  if k == 'ver' then
     ngx.var._ver = v
     ngx.var._ver = v
   elseif k == 'type' then
   elseif k == 'type' then
     ngx.var._type = v
     ngx.var._type = v
@@ -25,20 +23,25 @@ for k, v in pairs(hdrs) do
   elseif k == 'level' then
   elseif k == 'level' then
     ngx.var._level = v
     ngx.var._level = v
     ngx.ctx._level = tonumber(v)
     ngx.ctx._level = tonumber(v)
-  elseif k == 'ext' then
-    extHdrs = require('cjson').decode(v)
-  else
-    if k == 'referer' then
-      ngx.var._ref = v
-    end
-    ngx.req.set_header(k, v)
   end
   end
-
-  ::continue::
 end
 end
 
 
-if extHdrs then
-  for k, v in pairs(extHdrs) do
-    ngx.req.set_header(k, v)
+-- 原始 HTTP 字段
+local ext = json['ext']
+local hasRawAccept = false
+
+for k, v in pairs(ext) do
+  if k == 'accept' then
+    hasRawAccept = true
+  elseif k == 'referer' then
+    ngx.var._ref = v
   end
   end
-end
+  ngx.req.set_header(k, v)
+end
+
+if not hasRawAccept then
+  ngx.req.clear_header('accept')
+end
+
+-- 删除 URL 的 '/http/' 前缀
+ngx.var._url = ngx.var.request_uri:sub(7)

+ 6 - 18
lua/http-enc-res-hdr.lua

@@ -9,9 +9,6 @@ local expose = '*'
 -- 该值为 true 表示浏览器不支持 aceh: *,需返回详细的头部列表
 -- 该值为 true 表示浏览器不支持 aceh: *,需返回详细的头部列表
 local detail = ngx.ctx._acehOld
 local detail = ngx.ctx._acehOld
 
 
--- 由于接口路径固定,为避免被缓存,以请求头的 --url 值区分缓存
-local vary = '--url'
-
 
 
 local function addHdr(k, v)
 local function addHdr(k, v)
   ngx.header[k] = v
   ngx.header[k] = v
@@ -32,7 +29,6 @@ local function flushHdr()
 
 
   ngx.header['access-control-expose-headers'] = expose
   ngx.header['access-control-expose-headers'] = expose
   ngx.header['access-control-allow-origin'] = '*'
   ngx.header['access-control-allow-origin'] = '*'
-  ngx.header['vary'] = vary
 
 
   local status = ngx.status
   local status = ngx.status
 
 
@@ -57,15 +53,6 @@ local function flushHdr()
 end
 end
 
 
 
 
-local function addVary(v)
-  if type(v) == 'table' then
-    vary = vary .. ',' .. table.concat(v, ',')
-  else
-    vary = vary .. ',' .. v
-  end
-end
-
-
 local function nodeSwitched()
 local function nodeSwitched()
   local status = ngx.status
   local status = ngx.status
   if status ~= 200 and status ~= 206 then
   if status ~= 200 and status ~= 206 then
@@ -113,7 +100,6 @@ local function nodeSwitched()
   addHdr('--switched', '1')
   addHdr('--switched', '1')
 
 
   ngx.header['cache-control'] = 'no-cache'
   ngx.header['cache-control'] = 'no-cache'
-  ngx.header['vary'] = '--url'
   ngx.var._switched = resLenStr
   ngx.var._switched = resLenStr
   ngx.ctx._switched = true
   ngx.ctx._switched = true
 
 
@@ -147,9 +133,6 @@ for k, v in pairs(h) do
     end
     end
     ngx.header[k] = nil
     ngx.header[k] = nil
 
 
-  elseif k == 'vary' then
-    addVary(v)
-
   elseif detail and
   elseif detail and
     -- 非简单头无法被 fetch 读取,需添加到 aceh 列表 --
     -- 非简单头无法被 fetch 读取,需添加到 aceh 列表 --
     -- https://developer.mozilla.org/en-US/docs/Glossary/Simple_response_header
     -- https://developer.mozilla.org/en-US/docs/Glossary/Simple_response_header
@@ -164,4 +147,9 @@ for k, v in pairs(h) do
   end
   end
 end
 end
 
 
-flushHdr()
+-- 不缓存非 GET 请求
+if ngx.req.get_method() ~= 'GET' then
+  ngx.header['cache-control'] = 'no-cache'
+end
+
+flushHdr()