Skip to content

Commit 2c079cd

Browse files
authored
Fix the case of Transfer-Encoding: chunked (#368)
* Fix the case of Transfer-Encoding: chunked * Make the test code more robust * Fix typo
1 parent b42e3da commit 2c079cd

File tree

1 file changed

+36
-6
lines changed

1 file changed

+36
-6
lines changed

lessons/229/myapp/cmd/gnet/server.go

+36-6
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,14 @@
11
package main
22

33
import (
4+
"bufio"
45
"bytes"
56
"context"
67
"encoding/json"
78
"errors"
9+
"io"
810
"log/slog"
11+
"net/http"
912
"strconv"
1013
"sync"
1114
"time"
@@ -43,7 +46,10 @@ type httpCodec struct {
4346
m *mon.Metrics
4447
}
4548

46-
var CRLF = []byte("0\r\n")
49+
var (
50+
CRLF = []byte("\r\n\r\n")
51+
lastChunk = []byte("0\r\n\r\n")
52+
)
4753

4854
func (hc *httpCodec) parse(data []byte) (int, []byte, error) {
4955
bodyOffset, err := hc.parser.Parse(data)
@@ -53,11 +59,31 @@ func (hc *httpCodec) parse(data []byte) (int, []byte, error) {
5359

5460
contentLength := hc.getContentLength()
5561
if contentLength > -1 {
56-
return bodyOffset + contentLength, data[bodyOffset : bodyOffset+contentLength], nil
62+
bodyEnd := bodyOffset + contentLength
63+
var body []byte
64+
if len(data) >= bodyEnd {
65+
body = data[bodyOffset:bodyEnd]
66+
}
67+
return bodyEnd, body, nil
68+
}
69+
70+
// Transfer-Encoding: chunked
71+
if idx := bytes.Index(data[bodyOffset:], lastChunk); idx != -1 {
72+
bodyEnd := idx + 5
73+
var body []byte
74+
if len(data) >= bodyEnd {
75+
req, err := http.ReadRequest(bufio.NewReader(bytes.NewReader(data[:bodyEnd])))
76+
if err != nil {
77+
return bodyEnd, nil, err
78+
}
79+
body, _ = io.ReadAll(req.Body)
80+
}
81+
return bodyEnd, body, nil
5782
}
5883

84+
// Request without a body.
5985
if idx := bytes.Index(data, CRLF); idx != -1 {
60-
return idx + 3, nil, nil
86+
return idx + 4, nil, nil
6187
}
6288

6389
return 0, nil, errors.New("invalid http request")
@@ -200,15 +226,18 @@ func (hs *httpServer) OnOpen(c gnet.Conn) ([]byte, gnet.Action) {
200226

201227
func (hs *httpServer) OnTraffic(c gnet.Conn) gnet.Action {
202228
hc := c.Context().(*httpCodec)
203-
buf, _ := c.Next(-1)
229+
buf, _ := c.Peek(-1)
230+
n := len(buf)
204231

205232
pipeline:
206233
nextOffset, body, err := hc.parse(buf)
234+
hc.resetParser()
207235
if err != nil {
208236
goto response
209237
}
210-
211-
hc.resetParser()
238+
if len(buf) < nextOffset { // incomplete request
239+
goto response
240+
}
212241
writeResponse(c, body)
213242
buf = buf[nextOffset:]
214243
if len(buf) > 0 {
@@ -219,6 +248,7 @@ response:
219248
c.Write(hc.resp.Bytes())
220249
}
221250
hc.reset()
251+
c.Discard(n - len(buf))
222252
return gnet.None
223253
}
224254

0 commit comments

Comments
 (0)