Limit release asset redirects
This commit is contained in:
@@ -4,15 +4,104 @@ import (
|
||||
"context"
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"fmt"
|
||||
"io"
|
||||
"net/http"
|
||||
"net/http/httptest"
|
||||
"strconv"
|
||||
"strings"
|
||||
"sync/atomic"
|
||||
"testing"
|
||||
|
||||
"go.maximumdirect.net/releasekit/internal/forge"
|
||||
)
|
||||
|
||||
func TestBackendOpenAssetBoundsRedirects(t *testing.T) {
|
||||
for _, hops := range []int{0, 10, 11} {
|
||||
t.Run(strconv.Itoa(hops), func(t *testing.T) {
|
||||
var requests atomic.Int32
|
||||
server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||
requests.Add(1)
|
||||
if got := r.Header.Get("Authorization"); got != "token fixture-secret-token" {
|
||||
t.Errorf("authorization = %q", got)
|
||||
}
|
||||
step, err := strconv.Atoi(strings.TrimPrefix(r.URL.Path, "/"))
|
||||
if err != nil {
|
||||
t.Errorf("invalid path %q", r.URL.Path)
|
||||
return
|
||||
}
|
||||
if step < hops {
|
||||
http.Redirect(w, r, fmt.Sprintf("/%d", step+1), http.StatusFound)
|
||||
return
|
||||
}
|
||||
_, _ = io.WriteString(w, "asset")
|
||||
}))
|
||||
defer server.Close()
|
||||
backend := NewBackend(testDestination(server.URL), server.Client())
|
||||
stream, err := backend.OpenAsset(t.Context(), assetHandle{downloadURL: "/0"})
|
||||
if hops <= 10 {
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
body, readErr := io.ReadAll(stream)
|
||||
closeErr := stream.Close()
|
||||
if readErr != nil || closeErr != nil || string(body) != "asset" || requests.Load() != int32(hops+1) {
|
||||
t.Fatalf("body = %q, read = %v, close = %v, requests = %d", body, readErr, closeErr, requests.Load())
|
||||
}
|
||||
return
|
||||
}
|
||||
var failure *forge.Failure
|
||||
if !errors.As(err, &failure) || failure.Kind != forge.FailureUnverifiable || !strings.Contains(err.Error(), "redirect limit") || requests.Load() != 11 || stream != nil {
|
||||
t.Fatalf("stream = %v, error = %v, requests = %d", stream, err, requests.Load())
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestBackendOpenAssetRedirectReturnsToOrigin(t *testing.T) {
|
||||
var origin *httptest.Server
|
||||
external := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||
if got := r.Header.Get("Authorization"); got != "" {
|
||||
t.Errorf("cross-origin authorization = %q", got)
|
||||
}
|
||||
http.Redirect(w, r, origin.URL+"/final", http.StatusFound)
|
||||
}))
|
||||
defer external.Close()
|
||||
origin = httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||
if got := r.Header.Get("Authorization"); got != "token fixture-secret-token" {
|
||||
t.Errorf("origin authorization = %q", got)
|
||||
}
|
||||
if r.URL.Path == "/start" {
|
||||
http.Redirect(w, r, external.URL+"/away", http.StatusFound)
|
||||
return
|
||||
}
|
||||
_, _ = io.WriteString(w, "asset")
|
||||
}))
|
||||
defer origin.Close()
|
||||
stream, err := NewBackend(testDestination(origin.URL), origin.Client()).OpenAsset(t.Context(), assetHandle{downloadURL: "/start"})
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
defer stream.Close()
|
||||
if body, err := io.ReadAll(stream); err != nil || string(body) != "asset" {
|
||||
t.Fatalf("body = %q, error = %v", body, err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestBackendOpenAssetRejectsRedirectCycle(t *testing.T) {
|
||||
var requests atomic.Int32
|
||||
server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||
requests.Add(1)
|
||||
http.Redirect(w, r, "/loop#different-fragment", http.StatusFound)
|
||||
}))
|
||||
defer server.Close()
|
||||
stream, err := NewBackend(testDestination(server.URL), server.Client()).OpenAsset(t.Context(), assetHandle{downloadURL: "/loop"})
|
||||
var failure *forge.Failure
|
||||
if !errors.As(err, &failure) || failure.Kind != forge.FailureUnverifiable || !strings.Contains(err.Error(), "loop") || requests.Load() != 1 || stream != nil {
|
||||
t.Fatalf("stream = %v, error = %v, requests = %d", stream, err, requests.Load())
|
||||
}
|
||||
}
|
||||
|
||||
func TestBackendListAssetsRejectsMalformedAttachmentList(t *testing.T) {
|
||||
server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||
if r.Method != http.MethodGet || r.URL.Path != "/api/v1/repos/owner/project/releases/10/assets" {
|
||||
|
||||
Reference in New Issue
Block a user