1
- from collections import Dict, Optional
2
- from lightbug_http.io.bytes import Bytes, ByteReader, ByteWriter, is_newline, is_space
3
- from lightbug_http.strings import BytesConstant, to_string_rfc9112_safe
4
- from lightbug_http._logger import logger
5
- from lightbug_http.strings import rChar, nChar, lineBreak, to_string
1
+ from memory import Span
2
+ from lightbug_http.io.bytes import Bytes, bytes , byte
6
3
4
+ alias strSlash = " /"
5
+ alias strHttp = " http"
6
+ alias http = " http"
7
+ alias strHttps = " https"
8
+ alias https = " https"
9
+ alias strHttp11 = " HTTP/1.1"
10
+ alias strHttp10 = " HTTP/1.0"
7
11
8
- struct HeaderKey :
9
- # TODO : Fill in more of these
10
- alias CONNECTION = " connection"
11
- alias CONTENT_TYPE = " content-type"
12
- alias CONTENT_LENGTH = " content-length"
13
- alias CONTENT_ENCODING = " content-encoding"
14
- alias TRANSFER_ENCODING = " transfer-encoding"
15
- alias DATE = " date"
16
- alias LOCATION = " location"
17
- alias HOST = " host"
18
- alias SERVER = " server"
19
- alias SET_COOKIE = " set-cookie"
20
- alias COOKIE = " cookie"
12
+ alias strMethodGet = " GET"
21
13
14
+ alias rChar = " \r "
15
+ alias nChar = " \n "
16
+ alias lineBreak = rChar + nChar
17
+ alias colonChar = " :"
22
18
23
- @value
24
- struct Header (Writable , Stringable ):
25
- var key : String
26
- var value : String
19
+ alias empty_string = " "
20
+ alias whitespace = " "
21
+ alias whitespace_byte = ord (whitespace)
22
+ alias tab = " \t "
23
+ alias tab_byte = ord (tab)
27
24
28
- fn __str__ (self ) -> String:
29
- return String.write(self )
30
25
31
- fn write_to [T : Writer, //](self , mut writer : T):
32
- writer.write(self .key + " : " , self .value, lineBreak)
26
+ struct BytesConstant :
27
+ alias whitespace = byte(whitespace)
28
+ alias colon = byte(colonChar)
29
+ alias rChar = byte(rChar)
30
+ alias nChar = byte(nChar)
33
31
32
+ alias CRLF = bytes (lineBreak)
33
+ alias DOUBLE_CRLF = bytes (lineBreak + lineBreak)
34
34
35
- @always_inline
36
- fn write_header [T : Writer](mut writer : T, key : String, value : String):
37
- writer.write(key + " : " , value, lineBreak)
38
35
36
+ fn to_string [T : Writable](value : T) -> String:
37
+ return String.write(value)
39
38
40
- @value
41
- struct Headers (Writable , Stringable ):
42
- """ Represents the header key/values in an http request/response.
43
39
44
- Header keys are normalized to lowercase
40
+ fn to_string (b : Span[UInt8]) -> String:
41
+ """ Creates a String from a copy of the provided Span of bytes.
42
+
43
+ Args:
44
+ b: The Span of bytes to convert to a String.
45
45
"""
46
+ return String(StringSlice(unsafe_from_utf8 = b))
47
+
46
48
47
- var _inner : Dict[String, String]
48
-
49
- fn __init__ (out self ):
50
- self ._inner = Dict[String, String]()
51
-
52
- fn __init__ (out self , owned * headers : Header):
53
- self ._inner = Dict[String, String]()
54
- for header in headers:
55
- self [header[].key.lower()] = header[].value
56
-
57
- @always_inline
58
- fn empty (self ) -> Bool:
59
- return len (self ._inner) == 0
60
-
61
- @always_inline
62
- fn __contains__ (self , key : String) -> Bool:
63
- return key.lower() in self ._inner
64
-
65
- @always_inline
66
- fn __getitem__ (self , key : String) raises -> String:
67
- try :
68
- return self ._inner[key.lower()]
69
- except :
70
- raise Error(" KeyError: Key not found in headers: " + key)
71
-
72
- @always_inline
73
- fn get (self , key : String) -> Optional[String]:
74
- return self ._inner.get(key.lower())
75
-
76
- @always_inline
77
- fn __setitem__ (mut self , key : String, value : String):
78
- self ._inner[key.lower()] = value
79
-
80
- fn content_length (self ) -> Int:
81
- try :
82
- return Int(self [HeaderKey.CONTENT_LENGTH ])
83
- except :
84
- return 0
85
-
86
- fn parse_raw (mut self , mut r : ByteReader) raises -> (String, String, String, List[String]):
87
- var first_byte = r.peek()
88
- if not first_byte:
89
- raise Error(" Headers.parse_raw: Failed to read first byte from response header" )
90
-
91
- var first = r.read_word()
92
- r.increment()
93
- var second = r.read_word()
94
- r.increment()
95
- var third = r.read_line()
96
- var cookies = List[String]()
97
-
98
- while not is_newline(r.peek()):
99
- var key = r.read_until(BytesConstant.colon)
100
- r.increment()
101
- if is_space(r.peek()):
102
- r.increment()
103
- # TODO (bgreni): Handle possible trailing whitespace
104
- var value = r.read_line()
105
-
106
- var k = to_string_rfc9112_safe(key._inner).lower()
107
- if k == HeaderKey.SET_COOKIE :
108
- cookies.append(to_string_rfc9112_safe(value._inner))
109
- continue
110
-
111
- self ._inner[k] = to_string_rfc9112_safe(value._inner)
112
-
113
- return (
114
- to_string_rfc9112_safe(first._inner),
115
- to_string_rfc9112_safe(second._inner),
116
- to_string_rfc9112_safe(third._inner),
117
- cookies
118
- )
119
-
120
- fn write_to [T : Writer, //](self , mut writer : T):
121
- for header in self ._inner.items():
122
- write_header(writer, header[].key, header[].value)
123
-
124
- fn __str__ (self ) -> String:
125
- return String.write(self )
49
+ fn to_string (owned bytes : Bytes) -> String:
50
+ """ Creates a String from the provided List of bytes.
51
+ If you do not transfer ownership of the List, the List will be copied.
52
+
53
+ Args:
54
+ bytes: The List of bytes to convert to a String.
55
+ """
56
+ var result = String()
57
+ result.write_bytes(bytes )
58
+ return result^
59
+
60
+
61
+ fn find_all (s : String, sub_str : String) -> List[Int]:
62
+ match_idxs = List[Int]()
63
+ var current_idx : Int = s.find(sub_str)
64
+ while current_idx > - 1 :
65
+ match_idxs.append(current_idx)
66
+ current_idx = s.find(sub_str, start = current_idx + 1 )
67
+ return match_idxs^
0 commit comments