mirror of
https://github.com/Wei-Shaw/sub2api.git
synced 2026-11-02 08:31:35 +00:00
Merge pull request #6638 from feeeei/feat/images-url-to-b64json-backfill
feat(images): 账户开关将生图结果 url 下载回填为 b64_json
This commit is contained in:
16 files changed
+861
-23
No files matched your search
@@ -213,7 +213,7 @@ func (s *httpUpstreamService) Do(req *http.Request, proxyURL string, accountID i
|
||||
}
|
||||
|
||||
// 执行请求
|
||||
client := httpClientForUpstreamRequest(entry.client, req)
|
||||
client := s.httpClientForUpstreamRequest(entry.client, req)
|
||||
client = httpClientWithGrokAccessDeniedFallback(client)
|
||||
resp, err := servertiming.Do(client, req)
|
||||
if err != nil {
|
||||
@@ -277,7 +277,7 @@ func (s *httpUpstreamService) DoWithTLS(req *http.Request, proxyURL string, acco
|
||||
return nil, err
|
||||
}
|
||||
|
||||
client := httpClientForUpstreamRequest(entry.client, req)
|
||||
client := s.httpClientForUpstreamRequest(entry.client, req)
|
||||
client = httpClientWithGrokAccessDeniedFallback(client)
|
||||
resp, err := servertiming.Do(client, req)
|
||||
if err != nil {
|
||||
@@ -297,15 +297,27 @@ func (s *httpUpstreamService) DoWithTLS(req *http.Request, proxyURL string, acco
|
||||
return resp, nil
|
||||
}
|
||||
|
||||
func httpClientForUpstreamRequest(client *http.Client, req *http.Request) *http.Client {
|
||||
if client == nil || req == nil || !service.HTTPUpstreamRedirectsDisabled(req.Context()) {
|
||||
// httpClientForUpstreamRequest 按请求上下文的标记派生客户端:禁用重定向,或对重定向的每一跳做主机校验。
|
||||
// 派生的克隆与缓存客户端共享 Transport;未打标记时原样返回。
|
||||
func (s *httpUpstreamService) httpClientForUpstreamRequest(client *http.Client, req *http.Request) *http.Client {
|
||||
if client == nil || req == nil {
|
||||
return client
|
||||
}
|
||||
clone := *client
|
||||
clone.CheckRedirect = func(*http.Request, []*http.Request) error {
|
||||
return http.ErrUseLastResponse
|
||||
ctx := req.Context()
|
||||
switch {
|
||||
case service.HTTPUpstreamRedirectsDisabled(ctx):
|
||||
clone := *client
|
||||
clone.CheckRedirect = func(*http.Request, []*http.Request) error {
|
||||
return http.ErrUseLastResponse
|
||||
}
|
||||
return &clone
|
||||
case service.HTTPUpstreamPublicHostsOnly(ctx) && client.CheckRedirect == nil:
|
||||
clone := *client
|
||||
clone.CheckRedirect = s.redirectChecker
|
||||
return &clone
|
||||
default:
|
||||
return client
|
||||
}
|
||||
return &clone
|
||||
}
|
||||
|
||||
// grokAccessDeniedFallbackTransport preserves the subscription CLI proxy as
|
||||
@@ -587,8 +599,11 @@ func (s *httpUpstreamService) shouldValidateResolvedIP() bool {
|
||||
return !s.cfg.Security.URLAllowlist.AllowPrivateHosts
|
||||
}
|
||||
|
||||
// validateRequestHost 校验请求主机的解析结果不落在回环、私网、链路本地或未指定地址。
|
||||
// 是否全局启用由 security.url_allowlist 决定;带 WithHTTPUpstreamPublicHostsOnly 标记的请求无论配置如何都校验。
|
||||
func (s *httpUpstreamService) validateRequestHost(req *http.Request) error {
|
||||
if !s.shouldValidateResolvedIP() {
|
||||
publicHostsOnly := req != nil && service.HTTPUpstreamPublicHostsOnly(req.Context())
|
||||
if !s.shouldValidateResolvedIP() && !publicHostsOnly {
|
||||
return nil
|
||||
}
|
||||
if req == nil || req.URL == nil {
|
||||
|
||||
@@ -961,3 +961,63 @@ func hasEntry(svc *httpUpstreamService, target *upstreamClientEntry) bool {
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
func TestHTTPUpstreamDoPublicHostsOnlyRejectsPrivateDestinationBeforeConnecting(t *testing.T) {
|
||||
var calls atomic.Int64
|
||||
target := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, _ *http.Request) {
|
||||
calls.Add(1)
|
||||
w.WriteHeader(http.StatusOK)
|
||||
}))
|
||||
t.Cleanup(target.Close)
|
||||
|
||||
upstream := NewHTTPUpstream(nil)
|
||||
|
||||
plain, err := http.NewRequestWithContext(t.Context(), http.MethodGet, target.URL, nil)
|
||||
require.NoError(t, err)
|
||||
resp, err := upstream.Do(plain, "", 1, 1)
|
||||
require.NoError(t, err)
|
||||
require.NoError(t, resp.Body.Close())
|
||||
require.Equal(t, int64(1), calls.Load(), "loopback stays reachable for requests without the marker")
|
||||
|
||||
guarded, err := http.NewRequestWithContext(service.WithHTTPUpstreamPublicHostsOnly(t.Context()), http.MethodGet, target.URL, nil)
|
||||
require.NoError(t, err)
|
||||
resp, err = upstream.Do(guarded, "", 1, 1)
|
||||
require.Error(t, err)
|
||||
require.Nil(t, resp)
|
||||
require.Contains(t, err.Error(), "not allowed")
|
||||
require.Equal(t, int64(1), calls.Load(), "marked request must be rejected before any connection is made")
|
||||
}
|
||||
|
||||
func TestHTTPUpstreamPublicHostsOnlyValidatesEveryRedirectHop(t *testing.T) {
|
||||
upstream, ok := NewHTTPUpstream(nil).(*httpUpstreamService)
|
||||
require.True(t, ok)
|
||||
base := &http.Client{}
|
||||
|
||||
plain, err := http.NewRequestWithContext(t.Context(), http.MethodGet, "https://cdn.example.com/a.png", nil)
|
||||
require.NoError(t, err)
|
||||
require.Same(t, base, upstream.httpClientForUpstreamRequest(base, plain))
|
||||
|
||||
guarded, err := http.NewRequestWithContext(service.WithHTTPUpstreamPublicHostsOnly(t.Context()), http.MethodGet, "https://cdn.example.com/a.png", nil)
|
||||
require.NoError(t, err)
|
||||
client := upstream.httpClientForUpstreamRequest(base, guarded)
|
||||
require.NotSame(t, base, client)
|
||||
require.NotNil(t, client.CheckRedirect)
|
||||
require.Nil(t, base.CheckRedirect, "the cached client must stay untouched")
|
||||
|
||||
via := []*http.Request{guarded}
|
||||
for _, hop := range []string{
|
||||
"http://127.0.0.1:8080/a.png",
|
||||
"http://[::1]:8080/a.png",
|
||||
"http://10.0.0.8/a.png",
|
||||
"http://169.254.169.254/latest/meta-data/",
|
||||
"http://0.0.0.0/a.png",
|
||||
} {
|
||||
hopReq, err := http.NewRequestWithContext(guarded.Context(), http.MethodGet, hop, nil)
|
||||
require.NoError(t, err)
|
||||
require.Error(t, client.CheckRedirect(hopReq, via), "hop=%s", hop)
|
||||
}
|
||||
publicHop, err := http.NewRequestWithContext(guarded.Context(), http.MethodGet, "http://93.184.216.34/a.png", nil)
|
||||
require.NoError(t, err)
|
||||
require.NoError(t, client.CheckRedirect(publicHop, via))
|
||||
require.Error(t, client.CheckRedirect(publicHop, make([]*http.Request, 10)), "redirect chain stays capped")
|
||||
}
|
||||
Reference in new issue
Block a user