Skip to content

Add lightbug_http v0.1.19 #37

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 40 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from 9 commits
Commits
Show all changes
40 commits
Select commit Hold shift + click to select a range
70495fb
add recipe readme and image
saviorand Dec 28, 2024
7558b01
update to hotfix version and fix recipe
saviorand Jan 1, 2025
ffad8b8
add test files and bump version
saviorand Jan 8, 2025
b3290ee
update rev
saviorand Jan 8, 2025
5d87180
add more maintainers
saviorand Jan 8, 2025
9474399
Merge branch 'main' into main
carolinefrasca Jan 9, 2025
d3e41c7
Merge branch 'main' into main
carolinefrasca Jan 9, 2025
98a3fa7
remove README
saviorand Jan 11, 2025
7e4d621
Merge branch 'main' into main
carolinefrasca Jan 14, 2025
c04fcf7
update build script
saviorand Jan 14, 2025
9d1a8c4
remove tests
saviorand Jan 16, 2025
dba1b03
Merge branch 'main' into main
saviorand Jan 16, 2025
274d68f
pin max version
saviorand Jan 17, 2025
b060396
Merge branch 'main' into main
carolinefrasca Jan 17, 2025
965dcb0
bump version
saviorand Jan 17, 2025
7a3e621
Merge branch 'main' into main
carolinefrasca Jan 24, 2025
4017571
Merge branch 'main' into main
carolinefrasca Feb 7, 2025
be480a0
Merge branch 'main' into main
carolinefrasca Feb 11, 2025
693dc5c
update commit sha
saviorand Feb 11, 2025
3ed1655
Update recipe.yaml
saviorand Feb 11, 2025
aa0184b
remove magic run
saviorand Feb 12, 2025
6553b36
Merge branch 'main' into main
carolinefrasca Feb 14, 2025
d6e16ab
Merge branch 'main' into main
carolinefrasca Feb 14, 2025
51fcc25
Merge branch 'main' into main
carolinefrasca Feb 19, 2025
272eded
Merge branch 'main' into main
carolinefrasca Feb 19, 2025
f3d02c2
bump the version
saviorand Feb 23, 2025
4ded186
Merge branch 'main' into main
carolinefrasca Feb 26, 2025
0202995
Merge branch 'main' into main
carolinefrasca Feb 26, 2025
37b69b7
Merge branch 'main' into main
carolinefrasca Feb 26, 2025
74c4114
fix max version
saviorand Feb 26, 2025
a85b4db
Merge branch 'main' into main
carolinefrasca Feb 27, 2025
e9c80a0
bump small time version
saviorand Mar 2, 2025
d8f3928
Merge branch 'main' into main
carolinefrasca Mar 3, 2025
fa6822c
Merge branch 'main' into main
carolinefrasca Mar 24, 2025
81f7b63
Merge branch 'main' into main
carolinefrasca Mar 31, 2025
6566c87
Merge branch 'main' into main
carolinefrasca Apr 9, 2025
a3b8c1e
update to latest release
saviorand Apr 10, 2025
81d01c4
Merge branch 'main' into main
saviorand Apr 21, 2025
606d3ae
add small_time to external
saviorand Apr 22, 2025
20909d2
bump to 0.1.19
saviorand Apr 22, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Binary file added recipes/lightbug_http/image.jpeg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
54 changes: 54 additions & 0 deletions recipes/lightbug_http/recipe.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
# yaml-language-server: $schema=https://raw.githubusercontent.com/prefix-dev/recipe-format/main/schema.json

context:
version: "0.1.8"

package:
name: "lightbug_http"
version: ${{ version }}

source:
- git: https://github.com/saviorand/lightbug_http.git
rev: bcd2967c6177ac2c7800b0c4d51ddc0630326b28

build:
number: 0
script:
- mkdir -p ${PREFIX}/lib/mojo
- magic run mojo package . -o ${PREFIX}/lib/mojo/lightbug_http.mojopkg

requirements:
host:
- max
run:
- ${{ pin_compatible('max') }}
- small_time == 0.1.6

tests:
- script:
- if: unix
then:
- magic run test
files:
recipe:
- tests/lightbug_http/io/test_bytes.mojo
- tests/lightbug_http/test_client.mojo
- tests/lightbug_http/test_cookie.mojo
- tests/lightbug_http/test_header.mojo
- tests/lightbug_http/test_http.mojo
- tests/lightbug_http/test_net.mojo
- tests/lightbug_http/test_uri.mojo

about:
homepage: https://lightbug.site
license: MIT
license_file: LICENSE
summary: Lightbug is a simple and sweet HTTP framework for Mojo
repository: https://github.com/saviorand/lightbug_http

extra:
maintainers:
- saviorand
- bgreni
- thatstoasty
project_name: lightbug_http
37 changes: 37 additions & 0 deletions recipes/lightbug_http/tests/lightbug_http/io/test_bytes.mojo
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
import testing
from collections import Dict, List
from lightbug_http.io.bytes import Bytes, bytes


fn test_string_literal_to_bytes() raises:
var cases = Dict[StringLiteral, Bytes]()
cases[""] = Bytes()
cases["Hello world!"] = Bytes(
72, 101, 108, 108, 111, 32, 119, 111, 114, 108, 100, 33
)
cases["\0"] = Bytes(0)
cases["\0\0\0\0"] = Bytes(0, 0, 0, 0)
cases["OK"] = Bytes(79, 75)
cases["HTTP/1.1 200 OK"] = Bytes(
72, 84, 84, 80, 47, 49, 46, 49, 32, 50, 48, 48, 32, 79, 75
)

for c in cases.items():
testing.assert_equal(Bytes(c[].key.as_bytes()), c[].value)


fn test_string_to_bytes() raises:
var cases = Dict[String, Bytes]()
cases[String("")] = Bytes()
cases[String("Hello world!")] = Bytes(
72, 101, 108, 108, 111, 32, 119, 111, 114, 108, 100, 33
)
cases[String("\0")] = Bytes(0)
cases[String("\0\0\0\0")] = Bytes(0, 0, 0, 0)
cases[String("OK")] = Bytes(79, 75)
cases[String("HTTP/1.1 200 OK")] = Bytes(
72, 84, 84, 80, 47, 49, 46, 49, 32, 50, 48, 48, 32, 79, 75
)

for c in cases.items():
testing.assert_equal(Bytes(c[].key.as_bytes()), c[].value)
93 changes: 93 additions & 0 deletions recipes/lightbug_http/tests/lightbug_http/test_client.mojo
Original file line number Diff line number Diff line change
@@ -0,0 +1,93 @@
import testing
from lightbug_http.client import Client
from lightbug_http.http import HTTPRequest, encode
from lightbug_http.uri import URI
from lightbug_http.header import Header, Headers
from lightbug_http.io.bytes import bytes


fn test_mojo_client_redirect_external_req_google() raises:
var client = Client()
var req = HTTPRequest(
uri=URI.parse_raises("http://google.com"),
headers=Headers(
Header("Connection", "close")),
method="GET",
)
try:
var res = client.do(req)
testing.assert_equal(res.status_code, 200)
except e:
print(e)

fn test_mojo_client_redirect_external_req_302() raises:
var client = Client()
var req = HTTPRequest(
uri=URI.parse_raises("http://httpbin.org/status/302"),
headers=Headers(
Header("Connection", "close")),
method="GET",
)
try:
var res = client.do(req)
testing.assert_equal(res.status_code, 200)
except e:
print(e)

fn test_mojo_client_redirect_external_req_308() raises:
var client = Client()
var req = HTTPRequest(
uri=URI.parse_raises("http://httpbin.org/status/308"),
headers=Headers(
Header("Connection", "close")),
method="GET",
)
try:
var res = client.do(req)
testing.assert_equal(res.status_code, 200)
except e:
print(e)

fn test_mojo_client_redirect_external_req_307() raises:
var client = Client()
var req = HTTPRequest(
uri=URI.parse_raises("http://httpbin.org/status/307"),
headers=Headers(
Header("Connection", "close")),
method="GET",
)
try:
var res = client.do(req)
testing.assert_equal(res.status_code, 200)
except e:
print(e)

fn test_mojo_client_redirect_external_req_301() raises:
var client = Client()
var req = HTTPRequest(
uri=URI.parse_raises("http://httpbin.org/status/301"),
headers=Headers(
Header("Connection", "close")),
method="GET",
)
try:
var res = client.do(req)
testing.assert_equal(res.status_code, 200)
testing.assert_equal(res.headers.content_length(), 228)
except e:
print(e)

fn test_mojo_client_lightbug_external_req_200() raises:
try:
var client = Client()
var req = HTTPRequest(
uri=URI.parse_raises("http://httpbin.org/status/200"),
headers=Headers(
Header("Connection", "close")),
method="GET",
)
var res = client.do(req)
testing.assert_equal(res.status_code, 200)
except e:
print(e)
raise
43 changes: 43 additions & 0 deletions recipes/lightbug_http/tests/lightbug_http/test_cookie.mojo
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
from lightbug_http.cookie import SameSite, Cookie, Duration, Expiration
from small_time.small_time import SmallTime, now
from testing import assert_true, assert_equal
from collections import Optional

fn test_set_cookie() raises:
cookie = Cookie(
name="mycookie",
value="myvalue",
max_age=Duration(minutes=20),
expires=Expiration.from_datetime(SmallTime(2037, 1, 22, 12, 0, 10, 0)),
path=str("/"),
domain=str("localhost"),
secure=True,
http_only=True,
same_site=SameSite.none,
partitioned=False
)
var header = cookie.to_header()
var header_value = header.value
var expected = "mycookie=myvalue; Expires=Thu, 22 Jan 2037 12:00:10 GMT; Max-Age=1200; Domain=localhost; Path=/; Secure; HttpOnly; SameSite=none"
assert_equal("set-cookie", header.key)
assert_equal(header_value, expected)


fn test_set_cookie_partial_arguments() raises:
cookie = Cookie(
name="mycookie",
value="myvalue",
same_site=SameSite.lax
)
var header = cookie.to_header()
var header_value = header.value
var expected = "mycookie=myvalue; SameSite=lax"
assert_equal("set-cookie", header.key)
assert_equal( header_value, expected)


fn test_expires_http_timestamp_format() raises:
var expected = "Thu, 22 Jan 2037 12:00:10 GMT"
var http_date = Expiration.from_datetime(SmallTime(2037, 1, 22, 12, 0, 10, 0)).http_date_timestamp()
assert_true(http_date is not None, msg="Http date is None")
assert_equal(expected , http_date.value())
56 changes: 56 additions & 0 deletions recipes/lightbug_http/tests/lightbug_http/test_header.mojo
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
from testing import assert_equal, assert_true
from memory import Span
from lightbug_http.utils import ByteReader
from lightbug_http.header import Headers, Header
from lightbug_http.io.bytes import Bytes, bytes


def test_header_case_insensitive():
var headers = Headers(Header("Host", "SomeHost"))
assert_true("host" in headers)
assert_true("HOST" in headers)
assert_true("hOST" in headers)
assert_equal(headers["Host"], "SomeHost")
assert_equal(headers["host"], "SomeHost")


def test_parse_request_header():
var headers_str = bytes(
"""GET /index.html HTTP/1.1\r\nHost:example.com\r\nUser-Agent: Mozilla/5.0\r\nContent-Type: text/html\r\nContent-Length: 1234\r\nConnection: close\r\nTrailer: end-of-message\r\n\r\n"""
)
var header = Headers()
var b = Bytes(headers_str)
var reader = ByteReader(Span(b))
var method: String
var protocol: String
var uri: String
var properties = header.parse_raw(reader)
method, uri, protocol = properties[0], properties[1], properties[2]
assert_equal(uri, "/index.html")
assert_equal(protocol, "HTTP/1.1")
assert_equal(method, "GET")
assert_equal(header["Host"], "example.com")
assert_equal(header["User-Agent"], "Mozilla/5.0")
assert_equal(header["Content-Type"], "text/html")
assert_equal(header["Content-Length"], "1234")
assert_equal(header["Connection"], "close")


def test_parse_response_header():
var headers_str = "HTTP/1.1 200 OK\r\nServer: example.com\r\nUser-Agent: Mozilla/5.0\r\nContent-Type: text/html\r\nContent-Encoding: gzip\r\nContent-Length: 1234\r\nConnection: close\r\nTrailer: end-of-message\r\n\r\n"
var header = Headers()
var protocol: String
var status_code: String
var status_text: String
var reader = ByteReader(headers_str.as_bytes())
var properties = header.parse_raw(reader)
protocol, status_code, status_text = properties[0], properties[1], properties[2]
assert_equal(protocol, "HTTP/1.1")
assert_equal(status_code, "200")
assert_equal(status_text, "OK")
assert_equal(header["Server"], "example.com")
assert_equal(header["Content-Type"], "text/html")
assert_equal(header["Content-Encoding"], "gzip")
assert_equal(header["Content-Length"], "1234")
assert_equal(header["Connection"], "close")
assert_equal(header["Trailer"], "end-of-message")
98 changes: 98 additions & 0 deletions recipes/lightbug_http/tests/lightbug_http/test_http.mojo
Original file line number Diff line number Diff line change
@@ -0,0 +1,98 @@
import testing
from testing import assert_true, assert_equal
from collections import Dict, List
from lightbug_http.io.bytes import Bytes, bytes
from lightbug_http.http import HTTPRequest, HTTPResponse, encode, HttpVersion
from lightbug_http.header import Header, Headers, HeaderKey
from lightbug_http.cookie import Cookie, ResponseCookieJar, RequestCookieJar, Duration, ResponseCookieKey
from lightbug_http.uri import URI
from lightbug_http.strings import to_string

alias default_server_conn_string = "http://localhost:8080"

def test_encode_http_request():
var uri = URI.parse_raises(default_server_conn_string + "/foobar?baz")
var req = HTTPRequest(
uri,
body=String("Hello world!").as_bytes(),
cookies=RequestCookieJar(
Cookie(name="session_id", value="123", path=str("/"), secure=True, max_age=Duration(minutes=10)),
Cookie(name="token", value="abc", domain=str("localhost"), path=str("/api"), http_only=True)
),
headers=Headers(Header("Connection", "keep-alive")),
)

var as_str = str(req)
var req_encoded = to_string(encode(req^))


var expected =
"GET /foobar?baz HTTP/1.1\r\n"
"connection: keep-alive\r\n"
"content-length: 12\r\n"
"host: localhost:8080\r\n"
"cookie: session_id=123; token=abc\r\n"
"\r\n"
"Hello world!"

testing.assert_equal(
req_encoded,
expected
)
testing.assert_equal(req_encoded, as_str)


def test_encode_http_response():
var res = HTTPResponse(bytes("Hello, World!"))
res.headers[HeaderKey.DATE] = "2024-06-02T13:41:50.766880+00:00"

res.cookies = ResponseCookieJar(
Cookie(name="session_id", value="123", path=str("/api"), secure=True),
Cookie(name="session_id", value="abc", path=str("/"), secure=True, max_age=Duration(minutes=10)),
Cookie(name="token", value="123", domain=str("localhost"), path=str("/api"), http_only=True)
)
var as_str = str(res)
var res_encoded = to_string(encode(res^))
var expected_full =
"HTTP/1.1 200 OK\r\n"
"server: lightbug_http\r\n"
"content-type: application/octet-stream\r\n"
"connection: keep-alive\r\ncontent-length: 13\r\n"
"date: 2024-06-02T13:41:50.766880+00:00\r\n"
"set-cookie: session_id=123; Path=/api; Secure\r\n"
"set-cookie: session_id=abc; Max-Age=600; Path=/; Secure\r\n"
"set-cookie: token=123; Domain=localhost; Path=/api; HttpOnly\r\n"
"\r\n"
"Hello, World!"

testing.assert_equal(res_encoded, expected_full)
testing.assert_equal(res_encoded, as_str)

def test_decoding_http_response():
var res = String(
"HTTP/1.1 200 OK\r\n"
"server: lightbug_http\r\n"
"content-type: application/octet-stream\r\n"
"connection: keep-alive\r\ncontent-length: 13\r\n"
"date: 2024-06-02T13:41:50.766880+00:00\r\n"
"set-cookie: session_id=123; Path=/; Secure\r\n"
"\r\n"
"Hello, World!"
).as_bytes()

var response = HTTPResponse.from_bytes(res)
var expected_cookie_key = ResponseCookieKey("session_id", "", "/")

assert_equal(1, len(response.cookies))
assert_true(expected_cookie_key in response.cookies, msg="request should contain a session_id header")
var session_id = response.cookies.get(expected_cookie_key)
assert_true(session_id is not None)
assert_equal(session_id.value().path.value(), "/")
assert_equal(200, response.status_code)
assert_equal("OK", response.status_text)

def test_http_version_parse():
var v1 = HttpVersion("HTTP/1.1")
testing.assert_equal(v1._v, 1)
var v2 = HttpVersion("HTTP/2")
testing.assert_equal(v2._v, 2)
7 changes: 7 additions & 0 deletions recipes/lightbug_http/tests/lightbug_http/test_net.mojo
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
def test_net():
test_split_host_port()


def test_split_host_port():
# TODO: Implement this test
...
Loading
Loading