1
1
package main
2
2
3
3
import (
4
+ "bufio"
4
5
"bytes"
5
6
"context"
6
7
"encoding/json"
7
8
"errors"
9
+ "io"
8
10
"log/slog"
11
+ "net/http"
9
12
"strconv"
10
13
"sync"
11
14
"time"
@@ -43,7 +46,10 @@ type httpCodec struct {
43
46
m * mon.Metrics
44
47
}
45
48
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
+ )
47
53
48
54
func (hc * httpCodec ) parse (data []byte ) (int , []byte , error ) {
49
55
bodyOffset , err := hc .parser .Parse (data )
@@ -53,11 +59,31 @@ func (hc *httpCodec) parse(data []byte) (int, []byte, error) {
53
59
54
60
contentLength := hc .getContentLength ()
55
61
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
57
82
}
58
83
84
+ // Request without a body.
59
85
if idx := bytes .Index (data , CRLF ); idx != - 1 {
60
- return idx + 3 , nil , nil
86
+ return idx + 4 , nil , nil
61
87
}
62
88
63
89
return 0 , nil , errors .New ("invalid http request" )
@@ -200,15 +226,18 @@ func (hs *httpServer) OnOpen(c gnet.Conn) ([]byte, gnet.Action) {
200
226
201
227
func (hs * httpServer ) OnTraffic (c gnet.Conn ) gnet.Action {
202
228
hc := c .Context ().(* httpCodec )
203
- buf , _ := c .Next (- 1 )
229
+ buf , _ := c .Peek (- 1 )
230
+ n := len (buf )
204
231
205
232
pipeline:
206
233
nextOffset , body , err := hc .parse (buf )
234
+ hc .resetParser ()
207
235
if err != nil {
208
236
goto response
209
237
}
210
-
211
- hc .resetParser ()
238
+ if len (buf ) < nextOffset { // incomplete request
239
+ goto response
240
+ }
212
241
writeResponse (c , body )
213
242
buf = buf [nextOffset :]
214
243
if len (buf ) > 0 {
@@ -219,6 +248,7 @@ response:
219
248
c .Write (hc .resp .Bytes ())
220
249
}
221
250
hc .reset ()
251
+ c .Discard (n - len (buf ))
222
252
return gnet .None
223
253
}
224
254
0 commit comments