Skip to content

Commit 3510e66

Browse files
authored
Merge pull request #26 from SchmittB/feature/MojoHttpClient
Add a Mojo-based Client
2 parents 12b6feb + a21c5f0 commit 3510e66

File tree

3 files changed

+113
-1
lines changed

3 files changed

+113
-1
lines changed

lightbug_http/sys/client.mojo

Lines changed: 92 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,92 @@
1+
from lightbug_http.client import Client
2+
from lightbug_http.http import HTTPRequest, HTTPResponse
3+
from external.libc import (
4+
c_void,
5+
c_int,
6+
c_uint,
7+
c_char,
8+
sockaddr,
9+
sockaddr_in,
10+
AF_INET,
11+
SOCK_STREAM,
12+
SHUT_RDWR,
13+
htons,
14+
inet_pton,
15+
to_char_ptr,
16+
socket,
17+
connect,
18+
send,
19+
recv,
20+
shutdown,
21+
close,
22+
)
23+
24+
struct MojoClient(Client):
25+
var fd: c_int
26+
var name: String
27+
28+
var host: StringLiteral
29+
var port: Int
30+
31+
fn __init__(inout self) raises:
32+
self.fd = socket(AF_INET, SOCK_STREAM, 0)
33+
self.host = "127.0.0.1"
34+
self.port = 8888
35+
self.name = "lightbug_http_client"
36+
37+
fn __init__(inout self, host: StringLiteral, port: Int) raises:
38+
self.fd = socket(AF_INET, SOCK_STREAM, 0)
39+
self.host = host
40+
self.port = port
41+
self.name = "lightbug_http_client"
42+
43+
fn close(self) raises:
44+
_ = shutdown(self.fd, SHUT_RDWR)
45+
var close_status = close(self.fd)
46+
if close_status == -1:
47+
print("Failed to close new_sockfd")
48+
49+
fn do(self, req: HTTPRequest) raises -> HTTPResponse:
50+
var uri = req.uri()
51+
try:
52+
_ = uri.parse()
53+
except e:
54+
print("error parsing uri: " + e.__str__())
55+
56+
var host = String(uri.host())
57+
58+
if host == "":
59+
raise Error("URI is nil")
60+
var is_tls = False
61+
if uri.is_https():
62+
is_tls = True
63+
64+
var host_port = host.split(":")
65+
var host_str = host_port[0]
66+
67+
var ip_buf = Pointer[c_void].alloc(4)
68+
var conv_status = inet_pton(AF_INET, to_char_ptr(host_str), ip_buf)
69+
var raw_ip = ip_buf.bitcast[c_uint]().load()
70+
71+
var port = atol(host_port[1])
72+
73+
var bin_port = htons(UInt16(port))
74+
75+
var ai = sockaddr_in(AF_INET, bin_port, raw_ip, StaticTuple[c_char, 8]())
76+
var ai_ptr = Pointer[sockaddr_in].address_of(ai).bitcast[sockaddr]()
77+
78+
if connect(self.fd, ai_ptr, sizeof[sockaddr_in]()) == -1:
79+
_ = shutdown(self.fd, SHUT_RDWR)
80+
raise Error("Connection error") # Ensure to exit if connection fails
81+
82+
var bytes_sent = send(self.fd, to_char_ptr(req.body_raw), len(req.body_raw), 0)
83+
if bytes_sent == -1:
84+
print("Failed to send message")
85+
86+
var buf_size = 1024
87+
var buf = Pointer[UInt8]().alloc(buf_size)
88+
var bytes_recv = recv(self.fd, buf, buf_size, 0)
89+
var bytes_str = String(buf.bitcast[Int8](), bytes_recv)
90+
_ = close(self.fd)
91+
92+
return HTTPResponse(bytes_str._buffer)

lightbug_http/tests/run.mojo

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
from lightbug_http.python.client import PythonClient
2-
from lightbug_http.tests.test_client import test_python_client_lightbug
2+
from lightbug_http.sys.client import MojoClient
3+
from lightbug_http.tests.test_client import test_python_client_lightbug,test_mojo_client_lightbug
34

45

56
fn run_tests() raises:
@@ -8,11 +9,14 @@ fn run_tests() raises:
89

910
fn run_client_tests() raises:
1011
var py_client = PythonClient()
12+
var mojo_client = MojoClient()
1113
test_python_client_lightbug(py_client)
14+
test_mojo_client_lightbug(mojo_client)
1215

1316

1417
fn main():
1518
try:
1619
run_tests()
20+
print("Test suite passed")
1721
except e:
1822
print("Test suite failed: " + e.__str__())

lightbug_http/tests/test_client.mojo

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
import testing
22
from lightbug_http.python.client import PythonClient
3+
from lightbug_http.sys.client import MojoClient
34
from lightbug_http.http import HTTPRequest
45
from lightbug_http.uri import URI
56
from lightbug_http.header import RequestHeader
@@ -9,6 +10,21 @@ from lightbug_http.tests.utils import (
910
getRequest,
1011
)
1112

13+
fn test_mojo_client_lightbug(client: MojoClient) raises:
14+
var res = client.do(
15+
HTTPRequest(
16+
URI(default_server_conn_string),
17+
String("Hello world!")._buffer,
18+
RequestHeader(getRequest),
19+
)
20+
)
21+
testing.assert_equal(
22+
String(res.body_raw[0:112]),
23+
String(
24+
"HTTP/1.1 200 OK\r\nServer: lightbug_http\r\nContent-Type:"
25+
" text/plain\r\nContent-Length: 12\r\nConnection: close\r\nDate: "
26+
),
27+
)
1228

1329
fn test_python_client_lightbug(client: PythonClient) raises:
1430
var res = client.do(

0 commit comments

Comments
 (0)