@@ -35,6 +35,15 @@ fn encode(owned res: HTTPResponse) -> Bytes:
3535 return res._encoded()
3636
3737
38+ struct StatusCode :
39+ alias OK = 200
40+ alias MOVED_PERMANENTLY = 301
41+ alias FOUND = 302
42+ alias TEMPORARY_REDIRECT = 307
43+ alias PERMANENT_REDIRECT = 308
44+ alias NOT_FOUND = 404
45+
46+
3847@value
3948struct HTTPRequest (Formattable , Stringable ):
4049 var headers : Headers
@@ -48,9 +57,7 @@ struct HTTPRequest(Formattable, Stringable):
4857 var timeout : Duration
4958
5059 @ staticmethod
51- fn from_bytes (
52- addr : String, max_body_size : Int, owned b : Bytes
53- ) raises -> HTTPRequest:
60+ fn from_bytes (addr : String, max_body_size : Int, owned b : Bytes) raises -> HTTPRequest:
5461 var reader = ByteReader(b^ )
5562 var headers = Headers()
5663 var method : String
@@ -65,16 +72,10 @@ struct HTTPRequest(Formattable, Stringable):
6572
6673 var content_length = headers.content_length()
6774
68- if (
69- content_length > 0
70- and max_body_size > 0
71- and content_length > max_body_size
72- ):
75+ if content_length > 0 and max_body_size > 0 and content_length > max_body_size:
7376 raise Error(" Request body too large" )
7477
75- var request = HTTPRequest(
76- uri, headers = headers, method = method, protocol = protocol
77- )
78+ var request = HTTPRequest(uri, headers = headers, method = method, protocol = protocol)
7879
7980 try :
8081 request.read_body(reader, content_length, max_body_size)
@@ -103,6 +104,8 @@ struct HTTPRequest(Formattable, Stringable):
103104 self .set_content_length(len (body))
104105 if HeaderKey.CONNECTION not in self .headers:
105106 self .set_connection_close()
107+ if HeaderKey.HOST not in self .headers:
108+ self .headers[HeaderKey.HOST ] = uri.host
106109
107110 fn set_connection_close (inout self ):
108111 self .headers[HeaderKey.CONNECTION ] = " close"
@@ -114,20 +117,22 @@ struct HTTPRequest(Formattable, Stringable):
114117 return self .headers[HeaderKey.CONNECTION ] == " close"
115118
116119 @always_inline
117- fn read_body (
118- inout self , inout r : ByteReader, content_length : Int, max_body_size : Int
119- ) raises -> None :
120+ fn read_body (inout self , inout r : ByteReader, content_length : Int, max_body_size : Int) raises -> None :
120121 if content_length > max_body_size:
121122 raise Error(" Request body too large" )
122123
123- r.consume(self .body_raw)
124+ r.consume(self .body_raw, content_length )
124125 self .set_content_length(content_length)
125126
126127 fn format_to (self , inout writer : Formatter):
128+ writer.write(self .method, whitespace)
129+ path = self .uri.path if len (self .uri.path) > 1 else strSlash
130+ if len (self .uri.query_string) > 0 :
131+ path += " ?" + self .uri.query_string
132+
133+ writer.write(path)
134+
127135 writer.write(
128- self .method,
129- whitespace,
130- self .uri.path if len (self .uri.path) > 1 else strSlash,
131136 whitespace,
132137 self .protocol,
133138 lineBreak,
@@ -147,6 +152,8 @@ struct HTTPRequest(Formattable, Stringable):
147152 writer.write(self .method)
148153 writer.write(whitespace)
149154 var path = self .uri.path if len (self .uri.path) > 1 else strSlash
155+ if len (self .uri.query_string) > 0 :
156+ path += " ?" + self .uri.query_string
150157 writer.write(path)
151158 writer.write(whitespace)
152159 writer.write(self .protocol)
@@ -215,8 +222,16 @@ struct HTTPResponse(Formattable, Stringable):
215222 self .status_text = status_text
216223 self .protocol = protocol
217224 self .body_raw = body_bytes
218- self .set_connection_keep_alive()
219- self .set_content_length(len (body_bytes))
225+ if HeaderKey.CONNECTION not in self .headers:
226+ self .set_connection_keep_alive()
227+ if HeaderKey.CONTENT_LENGTH not in self .headers:
228+ self .set_content_length(len (body_bytes))
229+ if HeaderKey.DATE not in self .headers:
230+ try :
231+ var current_time = now(utc = True ).__str__ ()
232+ self .headers[HeaderKey.DATE ] = current_time
233+ except :
234+ pass
220235
221236 fn get_body_bytes (self ) -> Bytes:
222237 return self .body_raw
@@ -236,9 +251,25 @@ struct HTTPResponse(Formattable, Stringable):
236251 fn set_content_length (inout self , l : Int):
237252 self .headers[HeaderKey.CONTENT_LENGTH ] = str (l)
238253
254+ @always_inline
255+ fn content_length (inout self ) -> Int:
256+ try :
257+ return int (self .headers[HeaderKey.CONTENT_LENGTH ])
258+ except :
259+ return 0
260+
261+ fn is_redirect (self ) -> Bool:
262+ return (
263+ self .status_code == StatusCode.MOVED_PERMANENTLY
264+ or self .status_code == StatusCode.FOUND
265+ or self .status_code == StatusCode.TEMPORARY_REDIRECT
266+ or self .status_code == StatusCode.PERMANENT_REDIRECT
267+ )
268+
239269 @always_inline
240270 fn read_body (inout self , inout r : ByteReader) raises -> None :
241- r.consume(self .body_raw)
271+ r.consume(self .body_raw, self .content_length())
272+ self .set_content_length(len (self .body_raw))
242273
243274 fn format_to (self , inout writer : Formatter):
244275 writer.write(
@@ -252,13 +283,6 @@ struct HTTPResponse(Formattable, Stringable):
252283 lineBreak,
253284 )
254285
255- if HeaderKey.DATE not in self .headers:
256- try :
257- var current_time = now(utc = True ).__str__ ()
258- write_header(writer, HeaderKey.DATE , current_time)
259- except :
260- pass
261-
262286 self .headers.format_to(writer)
263287
264288 writer.write(lineBreak)
@@ -326,9 +350,7 @@ fn OK(body: Bytes, content_type: String) -> HTTPResponse:
326350 )
327351
328352
329- fn OK (
330- body : Bytes, content_type : String, content_encoding : String
331- ) -> HTTPResponse:
353+ fn OK (body : Bytes, content_type : String, content_encoding : String) -> HTTPResponse:
332354 return HTTPResponse(
333355 headers = Headers(
334356 Header(HeaderKey.CONTENT_TYPE , content_type),
0 commit comments