@marcel91200 / caddy Mirror · read-only
Fork 0

Fast and extensible multi-platform HTTP/1-2-3 web server with automatic HTTPS

Mirrored from https://github.com/Slazee/caddy.git

Synced Nov 11, 02:15 UTC

master
go 89 lines 2.77 KB
Raw
1 package fastcgi
2
3 import (
4 "encoding/json"
5 "fmt"
6 "io"
7 "net"
8 "net/http"
9 "net/http/fcgi"
10 "strings"
11 "testing"
12 "time"
13
14 "github.com/caddyserver/caddy/v2"
15 )
16
17 func TestRequestTrailersFastCGI(t *testing.T) {
18 backend, err := net.Listen("tcp", "127.0.0.1:0")
19 if err != nil {
20 t.Fatal(err)
21 }
22 done := make(chan error, 1)
23 go func() {
24 done <- fcgi.Serve(backend, http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
25 body, err := io.ReadAll(r.Body)
26 if err != nil {
27 t.Error(err)
28 http.Error(w, err.Error(), 500)
29 return
30 }
31 // FastCGI carries a length and stdin bytes, not HTTP trailers.
32 if len(r.Trailer) != 0 || len(r.TransferEncoding) != 0 {
33 t.Errorf("unexpected HTTP framing: %v %v", r.Trailer, r.TransferEncoding)
34 }
35 w.Header().Set("X-Body-Length", fmt.Sprint(r.ContentLength))
36 _, _ = w.Write(body)
37 }))
38 }()
39 defer func() { backend.Close(); <-done }()
40 reserve, err := net.Listen("tcp", "127.0.0.1:0")
41 if err != nil {
42 t.Fatal(err)
43 }
44 addr := reserve.Addr().String()
45 reserve.Close()
46 config, err := json.Marshal(map[string]any{
47 "admin": map[string]any{"disabled": true},
48 "apps": map[string]any{"http": map[string]any{"servers": map[string]any{"test": map[string]any{
49 "listen": []string{addr}, "automatic_https": map[string]any{"disable": true},
50 "routes": []any{map[string]any{"handle": []any{map[string]any{
51 "handler": "reverse_proxy", "upstreams": []any{map[string]any{"dial": backend.Addr().String()}},
52 "transport": map[string]any{"protocol": "fastcgi", "root": "/", "split_path": []string{".php"}},
53 }}}},
54 }}}},
55 })
56 if err != nil {
57 t.Fatal(err)
58 }
59 // Omit request_buffers so provisioning applies FastCGI's default 4096-byte buffer.
60 if err := caddy.Load(config, true); err != nil {
61 t.Fatal(err)
62 }
63 defer caddy.Stop()
64 client := &http.Client{Transport: &http.Transport{}, Timeout: 5 * time.Second}
65 defer client.CloseIdleConnections()
66 for _, body := range []string{"", "hello", strings.Repeat("x", 4095)} {
67 for _, trailers := range []bool{false, true} {
68 t.Run(fmt.Sprintf("length=%d/trailers=%t", len(body), trailers), func(t *testing.T) {
69 req, err := http.NewRequest(http.MethodPost, "http://"+addr+"/index.php", io.NopCloser(strings.NewReader(body)))
70 if err != nil {
71 t.Fatal(err)
72 }
73 req.ContentLength = -1
74 if trailers {
75 req.Trailer = http.Header{"Content-Digest": {"digest"}}
76 }
77 res, err := client.Do(req)
78 if err != nil {
79 t.Fatal(err)
80 }
81 got, err := io.ReadAll(res.Body)
82 res.Body.Close()
83 if err != nil || res.StatusCode != 200 || string(got) != body || res.Header.Get("X-Body-Length") != fmt.Sprint(len(body)) {
84 t.Fatalf("status=%d length=%q body bytes=%d (want %d), error=%v", res.StatusCode, res.Header.Get("X-Body-Length"), len(got), len(body), err)
85 }
86 })
87 }
88 }
89 }