55 "errors"
66 "fmt"
77 "io"
8+ "strconv"
89 "strings"
910)
1011
@@ -15,13 +16,15 @@ type RequestState int
1516
1617const (
1718 RequestStateInitialized RequestState = iota
18- RequestStateDone
1919 RequestStateParsingHeaders
20+ RequestParsingBody
21+ RequestStateDone
2022)
2123
2224type Request struct {
2325 RequestLine RequestLine
2426 Headers headers.Headers
27+ Body []byte
2528 State RequestState
2629}
2730
@@ -83,39 +86,6 @@ func RequestFromReader(reader io.Reader) (*Request, error) {
8386 return req , nil
8487}
8588
86- func parseRequestLine (data string ) (* RequestLine , int , error ) {
87- // Look for the CRLF that marks the end of the request line
88- endIdx := strings .Index (data , crlf )
89- if endIdx == - 1 {
90- // Not enough data yet; no CRLF found
91- return nil , 0 , nil
92- }
93-
94- // Extract the request line (without the trailing CRLF)
95- reqLine := data [:endIdx ]
96-
97- parts := strings .Split (reqLine , " " )
98- if len (parts ) != 3 {
99- return nil , endIdx + 2 , errors .New ("invalid number of parts in request line" )
100- }
101- // "method" part only contains capital alphabetic characters.
102- if strings .ToUpper (parts [0 ]) != parts [0 ] {
103- return nil , endIdx + 2 , errors .New ("http method is not capitalized" )
104- }
105-
106- httpVersion := strings .Replace (parts [2 ], "HTTP/" , "" , 1 )
107-
108- if httpVersion != "1.1" {
109- return nil , endIdx + 2 , errors .New ("http/1.1 only supported" )
110- }
111-
112- return & RequestLine {
113- Method : parts [0 ],
114- HttpVersion : httpVersion ,
115- RequestTarget : parts [1 ],
116- }, endIdx + 2 , nil
117- }
118-
11989func (r * Request ) parse (data []byte ) (int , error ) {
12090 totalBytesParsed := 0
12191 for r .State != RequestStateDone {
@@ -156,10 +126,65 @@ func (r *Request) parseSingle(data []byte) (int, error) {
156126 return 0 , err
157127 }
158128 if done {
159- r .State = RequestStateDone
129+ r .State = RequestParsingBody
160130 }
161131 return numberOfBytes , nil
162132 }
163133
134+ if r .State == RequestParsingBody {
135+ contentLen := r .Headers .GET ("Content-Length" )
136+ // content-length not present in headers no body
137+ if len (contentLen ) == 0 {
138+ r .State = RequestStateDone
139+ return 0 , nil
140+ }
141+ contentLenInt , err := strconv .Atoi (contentLen )
142+ if err != nil {
143+ return 0 , errors .New ("content-length doesn't convert to int" )
144+ }
145+ if len (data ) > contentLenInt {
146+ return 0 , errors .New ("body is larger than the content-length" )
147+ }
148+ if len (data ) == contentLenInt {
149+ r .Body = append (r .Body , data ... )
150+ r .State = RequestStateDone
151+ return len (data ), nil
152+ }
153+ return 0 , nil
154+ }
155+
164156 return 0 , errors .New ("unknown request status" )
165157}
158+
159+ func parseRequestLine (data string ) (* RequestLine , int , error ) {
160+ // Look for the CRLF that marks the end of the request line
161+ endIdx := strings .Index (data , crlf )
162+ if endIdx == - 1 {
163+ // Not enough data yet; no CRLF found
164+ return nil , 0 , nil
165+ }
166+
167+ // Extract the request line (without the trailing CRLF)
168+ reqLine := data [:endIdx ]
169+
170+ parts := strings .Split (reqLine , " " )
171+ if len (parts ) != 3 {
172+ return nil , endIdx + 2 , errors .New ("invalid number of parts in request line" )
173+ }
174+ // "method" part only contains capital alphabetic characters.
175+ if strings .ToUpper (parts [0 ]) != parts [0 ] {
176+ return nil , endIdx + 2 , errors .New ("http method is not capitalized" )
177+ }
178+
179+ httpVersion := strings .Replace (parts [2 ], "HTTP/" , "" , 1 )
180+
181+ if httpVersion != "1.1" {
182+ return nil , endIdx + 2 , errors .New ("http/1.1 only supported" )
183+ }
184+
185+ return & RequestLine {
186+ Method : parts [0 ],
187+ HttpVersion : httpVersion ,
188+ RequestTarget : parts [1 ],
189+ }, endIdx + 2 , nil
190+ }
0 commit comments