Skip to content

Commit 23a0bd8

Browse files
committed
Merge branch 'master' of github.com:valyala/fasthttp into feature/support-flush-fasthttpadaptor
2 parents fc4abf4 + f9d84d7 commit 23a0bd8

14 files changed

+473
-398
lines changed

.github/workflows/lint.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@ jobs:
1717
lint:
1818
runs-on: ubuntu-latest
1919
steps:
20-
- uses: actions/checkout@v4
20+
- uses: actions/checkout@v5
2121
- uses: actions/setup-go@v5
2222
with:
2323
go-version: 1.24.x

.github/workflows/security.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ jobs:
1414
env:
1515
GO111MODULE: on
1616
steps:
17-
- uses: actions/checkout@v4
17+
- uses: actions/checkout@v5
1818
- name: Run Gosec Security Scanner
1919
uses: securego/[email protected]
2020
with:

.github/workflows/test.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ jobs:
1313
os: [ubuntu-latest, macos-latest, windows-latest, macos-14]
1414
runs-on: ${{ matrix.os }}
1515
steps:
16-
- uses: actions/checkout@v4
16+
- uses: actions/checkout@v5
1717
- uses: actions/setup-go@v5
1818
with:
1919
go-version: ${{ matrix.go-version }}

allocation_test.go

Lines changed: 28 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,9 @@ import (
1010
func TestAllocationServeConn(t *testing.T) {
1111
s := &Server{
1212
Handler: func(ctx *RequestCtx) {
13+
ctx.SetStatusCode(StatusOK)
14+
ctx.SetBodyString("Hello, World!")
15+
ctx.Response.Header.Set("Content-Type", "text/plain; charset=utf-8")
1316
},
1417
}
1518

@@ -43,6 +46,9 @@ func TestAllocationClient(t *testing.T) {
4346

4447
s := &Server{
4548
Handler: func(ctx *RequestCtx) {
49+
ctx.SetStatusCode(StatusOK)
50+
ctx.SetBodyString("Hello, World!")
51+
ctx.Response.Header.Set("Content-Type", "text/plain; charset=utf-8")
4652
},
4753
}
4854
go s.Serve(ln) //nolint:errcheck
@@ -55,6 +61,7 @@ func TestAllocationClient(t *testing.T) {
5561
res := AcquireResponse()
5662

5763
req.SetRequestURI(url)
64+
req.Header.Add("Foo", "bar")
5865
if err := c.Do(req, res); err != nil {
5966
t.Fatal(err)
6067
}
@@ -105,7 +112,27 @@ func TestAllocationFS(t *testing.T) {
105112

106113
t.Logf("FS operations allocate %f times per request", n)
107114

108-
if n > 0 {
115+
if n != 0 {
116+
t.Fatalf("expected 0 allocations, got %f", n)
117+
}
118+
}
119+
120+
func TestAllocationsHeaderScanner(t *testing.T) {
121+
body := []byte("Host: a.com\r\nCookie: foo=bar\r\nWithTabs: \t v1 \t\r\nWithTabs-Start: \t \t v1 \r\nWithTabs-End: v1 \t \t\t\t\r\nWithTabs-Multi-Line: \t v1 \t;\r\n \t v2 \t;\r\n\t v3\r\n\r\n")
122+
123+
n := testing.AllocsPerRun(100, func() {
124+
var s headerScanner
125+
s.b = body
126+
127+
for s.next() {
128+
}
129+
130+
if s.err != nil {
131+
t.Fatal(s.err)
132+
}
133+
})
134+
135+
if n != 0 {
109136
t.Fatalf("expected 0 allocations, got %f", n)
110137
}
111138
}

fuzz_test.go

Lines changed: 93 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,10 @@ import (
55
"bytes"
66
"encoding/base64"
77
"encoding/binary"
8+
"fmt"
9+
"net/textproto"
810
"net/url"
11+
"reflect"
912
"strings"
1013
"testing"
1114
)
@@ -139,3 +142,93 @@ func FuzzURIParse(f *testing.F) {
139142
}
140143
})
141144
}
145+
146+
func FuzzTestHeaderScanner(f *testing.F) {
147+
f.Add([]byte("Host: example.com\r\nUser-Agent: Go-http-client/1.1\r\nAccept-Encoding: gzip, deflate\r\n\r\n"))
148+
f.Add([]byte("Content-Type: application/x-www-form-urlencoded\r\nContent-Length: 27\r\n\r\nname=John+Doe&age=30"))
149+
150+
f.Fuzz(func(t *testing.T, data []byte) {
151+
if !bytes.Contains(data, []byte("\r\n\r\n")) {
152+
return
153+
}
154+
155+
t.Logf("%q", data)
156+
157+
tmp, herr := textproto.NewReader(bufio.NewReader(bytes.NewReader(data))).ReadMIMEHeader()
158+
h := map[string][]string(tmp)
159+
160+
var s headerScanner
161+
s.b = data
162+
f := make(map[string][]string)
163+
for s.next() {
164+
// ReadMIMEHeader normalizes header keys, headerScanner doesn't by default.
165+
normalizeHeaderKey(s.key, false)
166+
167+
// textproto.ReadMIMEHeader will validate the header value, since we compare
168+
// errors we should do this as well.
169+
for _, c := range s.value {
170+
if !validHeaderValueByte(c) {
171+
s.err = fmt.Errorf("malformed MIME header: invalid byte %q in value %q for key %q", c, s.value, s.key)
172+
}
173+
}
174+
if s.err != nil {
175+
break
176+
}
177+
178+
key := string(s.key)
179+
value := string(s.value)
180+
181+
if _, ok := f[key]; !ok {
182+
f[key] = []string{}
183+
}
184+
f[key] = append(f[key], value)
185+
}
186+
187+
if s.err != nil && herr == nil {
188+
t.Errorf("unexpected error from headerScanner: %v: %v", s.err, h)
189+
} else if s.err == nil && herr != nil {
190+
t.Errorf("unexpected error from textproto.NewReader: %v: %v", herr, f)
191+
}
192+
193+
if !reflect.DeepEqual(h, f) {
194+
t.Errorf("headers mismatch:\ntextproto: %v\nfasthttp: %v", h, f)
195+
}
196+
})
197+
}
198+
199+
func FuzzRequestReadLimitBodyAllocations(f *testing.F) {
200+
f.Add([]byte("POST /a HTTP/1.1\r\nHost: a.com\r\nTransfer-Encoding: chunked\r\nContent-Type: aa\r\n\r\n6\r\nfoobar\r\n3\r\nbaz\r\n0\r\nfoobar\r\n\r\n"), 1024)
201+
f.Add([]byte("POST /a HTTP/1.1\r\nHost: a.com\r\nWithTabs: \t v1 \t\r\nWithTabs-Start: \t \t v1 \r\nWithTabs-End: v1 \t \t\t\t\r\nWithTabs-Multi-Line: \t v1 \t;\r\n \t v2 \t;\r\n\t v3\r\n\r\n"), 1024)
202+
203+
f.Fuzz(func(t *testing.T, body []byte, maxBodySize int) {
204+
if len(body) > 1024*1024 || maxBodySize > 1024*1024 {
205+
return
206+
}
207+
// Only test with a max for the body, otherwise a very large Content-Length will just OOM.
208+
if maxBodySize <= 0 {
209+
return
210+
}
211+
212+
t.Logf("%d %q", maxBodySize, body)
213+
214+
req := Request{}
215+
a := bytes.NewReader(body)
216+
b := bufio.NewReader(a)
217+
218+
if err := req.ReadLimitBody(b, maxBodySize); err != nil {
219+
return
220+
}
221+
222+
n := testing.AllocsPerRun(200, func() {
223+
req.Reset()
224+
a.Reset(body)
225+
b.Reset(a)
226+
227+
_ = req.ReadLimitBody(b, maxBodySize)
228+
})
229+
230+
if n != 0 {
231+
t.Fatalf("expected 0 allocations, got %f", n)
232+
}
233+
})
234+
}

0 commit comments

Comments
 (0)