Skip to content

Commit 2bd4ee8

Browse files
authored
Merge pull request #239 from Lightbug-HQ/feature/parse-localhost
Improve parse_address logic
2 parents 0cbb77b + d6c6828 commit 2bd4ee8

22 files changed

+1232
-986
lines changed

β€ŽREADME.md

Lines changed: 53 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -29,11 +29,10 @@ Lightbug is a simple and sweet HTTP framework for Mojo that builds on best pract
2929
This is not production ready yet. We're aiming to keep up with new developments in Mojo, but it might take some time to get to a point when this is safe to use in real-world applications.
3030

3131
Lightbug currently has the following features:
32-
- [x] Pure Mojo networking! No dependencies on Python by default
33-
- [x] TCP-based server and client implementation
34-
- [x] Assign your own custom handler to a route
35-
- [x] Craft HTTP requests and responses with built-in primitives
36-
- [x] Everything is fully typed, with no `def` functions used
32+
- [x] Pure Mojo! No Python dependencies. Everything is fully typed, with no `def` functions used
33+
- [x] HTTP Server and Client implementations
34+
- [x] TCP and UDP support
35+
- [x] Cookie support
3736

3837
### Check Out These Mojo Libraries:
3938

@@ -123,12 +122,12 @@ Once you have a Mojo project set up locally,
123122
fn main() raises:
124123
var server = Server()
125124
var handler = Welcome()
126-
server.listen_and_serve("0.0.0.0:8080", handler)
125+
server.listen_and_serve("localhost:8080", handler)
127126
```
128127
129128
Feel free to change the settings in `listen_and_serve()` to serve on a particular host and port.
130129
131-
Now send a request `0.0.0.0:8080`. You should see some details about the request printed out to the console.
130+
Now send a request `localhost:8080`. You should see some details about the request printed out to the console.
132131
133132
Congrats πŸ₯³ You're using Lightbug!
134133
@@ -197,19 +196,15 @@ from lightbug_http import *
197196
from lightbug_http.client import Client
198197
199198
fn test_request(mut client: Client) raises -> None:
200-
var uri = URI.parse_raises("http://httpbin.org/status/404")
201-
var headers = Header("Host", "httpbin.org")
202-
199+
var uri = URI.parse("google.com")
200+
var headers = Headers(Header("Host", "google.com"))
203201
var request = HTTPRequest(uri, headers)
204202
var response = client.do(request^)
205203
206204
# print status code
207205
print("Response:", response.status_code)
208206
209-
# print parsed headers (only some are parsed for now)
210-
print("Content-Type:", response.headers["Content-Type"])
211-
print("Content-Length", response.headers["Content-Length"])
212-
print("Server:", to_string(response.headers["Server"]))
207+
print(response.headers)
213208
214209
print(
215210
"Is connection set to connection-close? ", response.connection_close()
@@ -229,16 +224,50 @@ fn main() -> None:
229224

230225
Pure Mojo-based client is available by default. This client is also used internally for testing the server.
231226

232-
## Switching between pure Mojo and Python implementations
233-
234-
By default, Lightbug uses the pure Mojo implementation for networking. To use Python's `socket` library instead, just import the `PythonServer` instead of the `Server` with the following line:
227+
### UDP Support
228+
To get started with UDP, just use the `listen_udp` and `dial_udp` functions, along with `write_to` and `read_from` methods, like below.
235229

230+
On the client:
236231
```mojo
237-
from lightbug_http.python.server import PythonServer
232+
from lightbug_http.connection import dial_udp
233+
from lightbug_http.address import UDPAddr
234+
from utils import StringSlice
235+
236+
alias test_string = "Hello, lightbug!"
237+
238+
fn main() raises:
239+
print("Dialing UDP server...")
240+
alias host = "127.0.0.1"
241+
alias port = 12000
242+
var udp = dial_udp(host, port)
243+
244+
print("Sending " + str(len(test_string)) + " messages to the server...")
245+
for i in range(len(test_string)):
246+
_ = udp.write_to(str(test_string[i]).as_bytes(), host, port)
247+
248+
try:
249+
response, _, _ = udp.read_from(16)
250+
print("Response received:", StringSlice(unsafe_from_utf8=response))
251+
except e:
252+
if str(e) != str("EOF"):
253+
raise e
254+
238255
```
239256

240-
You can then use all the regular server commands in the same way as with the default server.
241-
Note: as of September, 2024, `PythonServer` and `PythonClient` throw a compilation error when starting. There's an open [issue](https://github.com/saviorand/lightbug_http/issues/41) to fix this - contributions welcome!
257+
On the server:
258+
```mojo
259+
fn main() raises:
260+
var listener = listen_udp("127.0.0.1", 12000)
261+
262+
while True:
263+
response, host, port = listener.read_from(16)
264+
var message = StringSlice(unsafe_from_utf8=response)
265+
print("Message received:", message)
266+
267+
# Response with the same message in uppercase
268+
_ = listener.write_to(String.upper(message).as_bytes(), host, port)
269+
270+
```
242271

243272
<!-- ROADMAP -->
244273
## Roadmap
@@ -249,19 +278,17 @@ Note: as of September, 2024, `PythonServer` and `PythonClient` throw a compilati
249278

250279
We're working on support for the following (contributors welcome!):
251280

252-
- [ ] [WebSocket Support](https://github.com/saviorand/lightbug_http/pull/57)
281+
- [ ] [JSON support](https://github.com/saviorand/lightbug_http/issues/4)
282+
- [ ] Complete HTTP/1.x support compliant with RFC 9110/9112 specs (see issues)
253283
- [ ] [SSL/HTTPS support](https://github.com/saviorand/lightbug_http/issues/20)
254-
- [ ] UDP support
255-
- [ ] [Better error handling](https://github.com/saviorand/lightbug_http/issues/3), [improved form/multipart and JSON support](https://github.com/saviorand/lightbug_http/issues/4)
256284
- [ ] [Multiple simultaneous connections](https://github.com/saviorand/lightbug_http/issues/5), [parallelization and performance optimizations](https://github.com/saviorand/lightbug_http/issues/6)
257285
- [ ] [HTTP 2.0/3.0 support](https://github.com/saviorand/lightbug_http/issues/8)
258-
- [ ] [ASGI spec conformance](https://github.com/saviorand/lightbug_http/issues/17)
259286

260287
The plan is to get to a feature set similar to Python frameworks like [Starlette](https://github.com/encode/starlette), but with better performance.
261288

262289
Our vision is to develop three libraries, with `lightbug_http` (this repo) as a starting point:
263-
- `lightbug_http` - HTTP infrastructure and basic API development
264-
- `lightbug_api` - (coming later in 2024!) Tools to make great APIs fast, with support for OpenAPI spec and domain driven design
290+
- `lightbug_http` - Lightweight and simple HTTP framework, basic networking primitives
291+
- [`lightbug_api`](https://github.com/saviorand/lightbug_api) - Tools to make great APIs fast, with OpenAPI support and automated docs
265292
- `lightbug_web` - (release date TBD) Full-stack web framework for Mojo, similar to NextJS or SvelteKit
266293

267294
The idea is to get to a point where the entire codebase of a simple modern web application can be written in Mojo.

β€Žbenchmark/bench_server.mojo

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ def main():
66
try:
77
var server = Server(tcp_keep_alive=True)
88
var handler = TechEmpowerRouter()
9-
server.listen_and_serve("0.0.0.0:8080", handler)
9+
server.listen_and_serve("localhost:8080", handler)
1010
except e:
1111
print("Error starting server: " + e.__str__())
1212
return

β€Žlightbug.πŸ”₯

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,4 +3,4 @@ from lightbug_http import Welcome, Server
33
fn main() raises:
44
var server = Server()
55
var handler = Welcome()
6-
server.listen_and_serve("0.0.0.0:8080", handler)
6+
server.listen_and_serve("localhost:8080", handler)

β€Žlightbug_http/_libc.mojo

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -574,7 +574,7 @@ fn inet_pton[address_family: Int32](src: UnsafePointer[c_char]) raises -> c_uint
574574
* This function is valid for `AF_INET` and `AF_INET6`.
575575
"""
576576
constrained[
577-
int(address_family) in [AF_INET, AF_INET6], "Address family must be either INET_ADDRSTRLEN or INET6_ADDRSTRLEN."
577+
int(address_family) in [AF_INET, AF_INET6], "Address family must be either AF_INET or AF_INET6."
578578
]()
579579
var ip_buffer: UnsafePointer[c_void]
580580

0 commit comments

Comments
Β (0)