Skip to content

Commit cfe7cb6

Browse files
committed
revert changes
1 parent 45f0a81 commit cfe7cb6

File tree

2 files changed

+59
-119
lines changed

2 files changed

+59
-119
lines changed

lightbug_http/header.mojo

Lines changed: 54 additions & 112 deletions
Original file line numberDiff line numberDiff line change
@@ -1,125 +1,67 @@
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
63

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"
711

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"
2113

14+
alias rChar = "\r"
15+
alias nChar = "\n"
16+
alias lineBreak = rChar + nChar
17+
alias colonChar = ":"
2218

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)
2724

28-
fn __str__(self) -> String:
29-
return String.write(self)
3025

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)
3331

32+
alias CRLF = bytes(lineBreak)
33+
alias DOUBLE_CRLF = bytes(lineBreak + lineBreak)
3434

35-
@always_inline
36-
fn write_header[T: Writer](mut writer: T, key: String, value: String):
37-
writer.write(key + ": ", value, lineBreak)
3835

36+
fn to_string[T: Writable](value: T) -> String:
37+
return String.write(value)
3938

40-
@value
41-
struct Headers(Writable, Stringable):
42-
"""Represents the header key/values in an http request/response.
4339

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.
4545
"""
46+
return String(StringSlice(unsafe_from_utf8=b))
47+
4648

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^

lightbug_http/strings.mojo

Lines changed: 5 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -60,7 +60,7 @@ fn to_string(b: Span[UInt8]) -> String:
6060

6161
fn to_string_rfc9112_safe[origin: Origin](b: Span[UInt8, origin]) -> String:
6262
try:
63-
var validated_span = validate_http_message_octets_rfc9112(b)
63+
var validated_span = validate_message_octets_iso_8859_1(b)
6464
return String(StringSlice(unsafe_from_utf8=validated_span))
6565
except:
6666
return percent_encode_octets(b)
@@ -109,7 +109,7 @@ fn percent_encode_octets[origin: Origin](data: Span[UInt8, origin]) -> String:
109109

110110
return result
111111

112-
fn validate_http_message_octets_rfc9112[origin: Origin](data: Span[UInt8, origin]) raises -> Span[UInt8, origin]:
112+
fn validate_message_octets_iso_8859_1[origin: Origin](data: Span[UInt8, origin]) raises -> Span[UInt8, origin]:
113113
for i in range(len(data)):
114114
var b = data[i]
115115

@@ -118,21 +118,19 @@ fn validate_http_message_octets_rfc9112[origin: Origin](data: Span[UInt8, origin
118118
if b >= 0xC0 and b <= 0xF7:
119119
if i + 1 < len(data) and data[i + 1] == 0x0A:
120120
raise Error(
121-
"RFC 9112 violation: LF (0x0A) embedded in potential multibyte sequence at position " +
122-
String(i + 1) + ". This creates security vulnerabilities."
121+
"."
123122
)
124123
elif b >= 0x80 and b <= 0xBF:
125124
if i == 0 or (data[i - 1] < 0xC0):
126125
if i + 1 < len(data) and data[i + 1] == 0x0A:
127126
raise Error(
128-
"RFC 9112 violation: LF (0x0A) after invalid UTF-8 continuation byte at position " +
129-
String(i + 1) + ". This creates security vulnerabilities."
127+
"."
130128
)
131129
continue
132130

133131
# This should never happen since is_iso_8859_1_octet covers 0x00-0xFF
134132
raise Error(
135-
"RFC 9112 violation: Invalid octet 0x" + hex(Int(b)) +
133+
"Invalid octet 0x" + hex(Int(b)) +
136134
" at position " + String(i) +
137135
". HTTP messages must use encoding superset of US-ASCII."
138136
)

0 commit comments

Comments
 (0)