mirror of
https://github.com/Rain-kl/OpenFlare.git
synced 2026-10-04 07:06:36 +08:00
fix(pages): 收紧部署包与 Agent 同步边界
完成 V2 Phase 0 安全与一致性前置:统一真实归档限额、流式拉取、候选裁剪、保留上传删除语义及 Pages 路由引用锁。
This commit is contained in:
@@ -0,0 +1,109 @@
|
||||
// Copyright 2026 Arctel.net
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
package httpclient
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"context"
|
||||
"io"
|
||||
"net/http"
|
||||
"net/http/httptest"
|
||||
"strings"
|
||||
"testing"
|
||||
"time"
|
||||
)
|
||||
|
||||
func TestDownloadPagesProjectLatestPackageRejectsChunkedBodyOverLimit(t *testing.T) {
|
||||
server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, _ *http.Request) {
|
||||
w.WriteHeader(http.StatusOK)
|
||||
if flusher, ok := w.(http.Flusher); ok {
|
||||
flusher.Flush()
|
||||
}
|
||||
_, _ = io.WriteString(w, "123456")
|
||||
}))
|
||||
defer server.Close()
|
||||
|
||||
client := New(server.URL, "test-token", time.Second)
|
||||
var dst bytes.Buffer
|
||||
written, err := client.DownloadPagesProjectLatestPackage(
|
||||
context.Background(),
|
||||
7,
|
||||
&dst,
|
||||
4,
|
||||
)
|
||||
if err == nil || !strings.Contains(err.Error(), "body exceeds limit") {
|
||||
t.Fatalf("DownloadPagesProjectLatestPackage(chunked, limit=4) error = %v, want body limit error", err)
|
||||
}
|
||||
if written != 5 {
|
||||
t.Errorf("DownloadPagesProjectLatestPackage(chunked, limit=4) written = %d, want 5", written)
|
||||
}
|
||||
}
|
||||
|
||||
func TestCopyPagesPackageResponseRejectsAdvertisedContentLengthBeforeWrite(t *testing.T) {
|
||||
response := &http.Response{
|
||||
Body: io.NopCloser(strings.NewReader("123456")),
|
||||
ContentLength: 6,
|
||||
}
|
||||
var dst bytes.Buffer
|
||||
written, err := copyPagesPackageResponse(&dst, response, 4)
|
||||
if err == nil || !strings.Contains(err.Error(), "Content-Length") {
|
||||
t.Fatalf("copyPagesPackageResponse(Content-Length=6, limit=4) error = %v, want Content-Length limit error", err)
|
||||
}
|
||||
if written != 0 || dst.Len() != 0 {
|
||||
t.Errorf("copyPagesPackageResponse(Content-Length=6, limit=4) wrote (%d, %d buffered), want no writes", written, dst.Len())
|
||||
}
|
||||
}
|
||||
|
||||
func TestCopyPagesPackageResponseRejectsForgedSmallContentLength(t *testing.T) {
|
||||
response := &http.Response{
|
||||
Body: io.NopCloser(strings.NewReader("123456")),
|
||||
ContentLength: 2,
|
||||
}
|
||||
var dst bytes.Buffer
|
||||
written, err := copyPagesPackageResponse(&dst, response, 4)
|
||||
if err == nil || !strings.Contains(err.Error(), "body exceeds limit") {
|
||||
t.Fatalf("copyPagesPackageResponse(forged Content-Length=2, limit=4) error = %v, want body limit error", err)
|
||||
}
|
||||
if written != 5 {
|
||||
t.Errorf("copyPagesPackageResponse(forged Content-Length=2, limit=4) written = %d, want 5", written)
|
||||
}
|
||||
}
|
||||
|
||||
func TestDownloadPagesProjectLatestPackageBoundsChunkedErrorResponse(t *testing.T) {
|
||||
server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, _ *http.Request) {
|
||||
w.WriteHeader(http.StatusBadRequest)
|
||||
if flusher, ok := w.(http.Flusher); ok {
|
||||
flusher.Flush()
|
||||
}
|
||||
_, _ = io.WriteString(w, strings.Repeat("x", int(pagesControlResponseMaxBytes+1)))
|
||||
}))
|
||||
defer server.Close()
|
||||
|
||||
client := New(server.URL, "test-token", time.Second)
|
||||
var dst bytes.Buffer
|
||||
_, err := client.DownloadPagesProjectLatestPackage(context.Background(), 7, &dst, 1024)
|
||||
if err == nil || !strings.Contains(err.Error(), "control response body exceeds limit") {
|
||||
t.Fatalf("DownloadPagesProjectLatestPackage(large chunked 400) error = %v, want bounded response error", err)
|
||||
}
|
||||
if dst.Len() != 0 {
|
||||
t.Errorf("DownloadPagesProjectLatestPackage(large chunked 400) wrote %d package bytes, want 0", dst.Len())
|
||||
}
|
||||
}
|
||||
|
||||
func TestGetPagesProjectLatestHashBoundsChunkedMetadataResponse(t *testing.T) {
|
||||
server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, _ *http.Request) {
|
||||
w.WriteHeader(http.StatusOK)
|
||||
if flusher, ok := w.(http.Flusher); ok {
|
||||
flusher.Flush()
|
||||
}
|
||||
_, _ = io.WriteString(w, strings.Repeat("x", int(pagesControlResponseMaxBytes+1)))
|
||||
}))
|
||||
defer server.Close()
|
||||
|
||||
client := New(server.URL, "test-token", time.Second)
|
||||
_, err := client.GetPagesProjectLatestHash(context.Background(), 7)
|
||||
if err == nil || !strings.Contains(err.Error(), "control response body exceeds limit") {
|
||||
t.Fatalf("GetPagesProjectLatestHash(large chunked metadata) error = %v, want bounded response error", err)
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user