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
@@ -53,7 +56,12 @@ func RequestFromReader(reader io.Reader) (*Request, error) {
5356
5457 if err != nil {
5558 if errors .Is (err , io .EOF ) {
56- req .State = RequestStateDone
59+ // if the EOF is reached but req isn't done state
60+ // then partial content
61+ if req .State != RequestStateDone {
62+ req .State = RequestStateDone
63+ return req , errors .New ("partial content" )
64+ }
5765 break
5866 }
5967 return nil , err
@@ -83,39 +91,6 @@ func RequestFromReader(reader io.Reader) (*Request, error) {
8391 return req , nil
8492}
8593
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-
11994func (r * Request ) parse (data []byte ) (int , error ) {
12095 totalBytesParsed := 0
12196 for r .State != RequestStateDone {
@@ -156,10 +131,65 @@ func (r *Request) parseSingle(data []byte) (int, error) {
156131 return 0 , err
157132 }
158133 if done {
159- r .State = RequestStateDone
134+ r .State = RequestParsingBody
160135 }
161136 return numberOfBytes , nil
162137 }
163138
139+ if r .State == RequestParsingBody {
140+ contentLen := r .Headers .GET ("Content-Length" )
141+ // content-length not present in headers no body
142+ if len (contentLen ) == 0 {
143+ r .State = RequestStateDone
144+ return 0 , nil
145+ }
146+ contentLenInt , err := strconv .Atoi (contentLen )
147+ if err != nil {
148+ return 0 , errors .New ("content-length doesn't convert to int" )
149+ }
150+ if len (data ) > contentLenInt {
151+ return 0 , errors .New ("body is larger than the content-length" )
152+ }
153+ if len (data ) == contentLenInt {
154+ r .Body = append (r .Body , data ... )
155+ r .State = RequestStateDone
156+ return len (data ), nil
157+ }
158+ return 0 , nil
159+ }
160+
164161 return 0 , errors .New ("unknown request status" )
165162}
163+
164+ func parseRequestLine (data string ) (* RequestLine , int , error ) {
165+ // Look for the CRLF that marks the end of the request line
166+ endIdx := strings .Index (data , crlf )
167+ if endIdx == - 1 {
168+ // Not enough data yet; no CRLF found
169+ return nil , 0 , nil
170+ }
171+
172+ // Extract the request line (without the trailing CRLF)
173+ reqLine := data [:endIdx ]
174+
175+ parts := strings .Split (reqLine , " " )
176+ if len (parts ) != 3 {
177+ return nil , endIdx + 2 , errors .New ("invalid number of parts in request line" )
178+ }
179+ // "method" part only contains capital alphabetic characters.
180+ if strings .ToUpper (parts [0 ]) != parts [0 ] {
181+ return nil , endIdx + 2 , errors .New ("http method is not capitalized" )
182+ }
183+
184+ httpVersion := strings .Replace (parts [2 ], "HTTP/" , "" , 1 )
185+
186+ if httpVersion != "1.1" {
187+ return nil , endIdx + 2 , errors .New ("http/1.1 only supported" )
188+ }
189+
190+ return & RequestLine {
191+ Method : parts [0 ],
192+ HttpVersion : httpVersion ,
193+ RequestTarget : parts [1 ],
194+ }, endIdx + 2 , nil
195+ }
0 commit comments