Skip to content

Commit 098445d

Browse files
committed
enable serving static files
1 parent bc99c93 commit 098445d

File tree

8 files changed

+97
-16
lines changed

8 files changed

+97
-16
lines changed

README.md

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -127,6 +127,31 @@ Once you have Mojo set up locally,
127127

128128
<p align="right">(<a href="#readme-top">back to top</a>)</p>
129129

130+
### Serving static files
131+
132+
The default welcome screen shows an example of how to serve files like images or HTML using Lightbug. Mojo has built-in `open`, `read` and `read_bytes` methods that you can use to read files from e.g. a `static` directory and serve them on a route:
133+
134+
```mojo
135+
@value
136+
struct Welcome(HTTPService):
137+
fn func(self, req: HTTPRequest) raises -> HTTPResponse:
138+
var uri = req.uri()
139+
140+
if uri.path() == "/":
141+
var html: Bytes
142+
with open("static/lightbug_welcome.html", "r") as f:
143+
html = f.read_bytes()
144+
return OK(html, "text/html; charset=utf-8")
145+
146+
if uri.path() == "/logo.png":
147+
var image: Bytes
148+
with open("static/logo.png", "r") as f:
149+
image = f.read_bytes()
150+
return OK(image, "image/png")
151+
152+
return NotFound(uri.path())
153+
```
154+
130155
### Using the client
131156

132157
Create a file, e.g `client.mojo` with the following code:

external/libc.mojo

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
1+
from lightbug_http.io.bytes import Bytes
2+
13
alias IPPROTO_IPV6 = 41
24
alias IPV6_V6ONLY = 26
35
alias EPROTONOSUPPORT = 93
@@ -83,6 +85,12 @@ fn to_char_ptr(s: String) -> Pointer[c_char]:
8385
return ptr
8486

8587

88+
fn to_char_ptr(s: Bytes) -> Pointer[c_char]:
89+
var ptr = Pointer[c_char]().alloc(len(s))
90+
for i in range(len(s)):
91+
ptr.store(i, int(s[i]))
92+
return ptr
93+
8694
fn c_charptr_to_string(s: Pointer[c_char]) -> String:
8795
return String(s.bitcast[Int8](), strlen(s))
8896

lightbug_http/header.mojo

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -369,6 +369,27 @@ struct ResponseHeader:
369369
self.__server = Bytes()
370370
self.__trailer = Bytes()
371371
self.raw_headers = Bytes()
372+
373+
fn __init__(
374+
inout self,
375+
status_code: Int,
376+
status_message: Bytes,
377+
content_type: Bytes,
378+
content_encoding: Bytes,
379+
) -> None:
380+
self.disable_normalization = False
381+
self.no_http_1_1 = False
382+
self.__connection_close = False
383+
self.__status_code = status_code
384+
self.__status_message = status_message
385+
self.__protocol = Bytes()
386+
self.__content_length = 0
387+
self.__content_length_bytes = Bytes()
388+
self.__content_type = content_type
389+
self.__content_encoding = content_encoding
390+
self.__server = Bytes()
391+
self.__trailer = Bytes()
392+
self.raw_headers = Bytes()
372393

373394
fn __init__(
374395
inout self,

lightbug_http/http.mojo

Lines changed: 16 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -216,7 +216,6 @@ struct HTTPResponse(Response):
216216
fn OK(body: Bytes) -> HTTPResponse:
217217
return HTTPResponse(
218218
ResponseHeader(
219-
True,
220219
200,
221220
String("OK").as_bytes(),
222221
String("Content-Type: text/plain").as_bytes(),
@@ -227,10 +226,21 @@ fn OK(body: Bytes) -> HTTPResponse:
227226

228227
fn OK(body: Bytes, content_type: String) -> HTTPResponse:
229228
return HTTPResponse(
230-
ResponseHeader(True, 200, String("OK").as_bytes(), content_type.as_bytes()),
229+
ResponseHeader(200, String("OK").as_bytes(), content_type.as_bytes()),
231230
body,
232231
)
233232

233+
fn OK(body: Bytes, content_type: String, content_encoding: String) -> HTTPResponse:
234+
return HTTPResponse(
235+
ResponseHeader(200, String("OK").as_bytes(), content_type.as_bytes(), content_encoding.as_bytes()),
236+
body,
237+
)
238+
239+
fn NotFound(path: String) -> HTTPResponse:
240+
return HTTPResponse(
241+
ResponseHeader(404, String("Not Found").as_bytes(), String("text/plain").as_bytes()),
242+
String("path " + path + " not found").as_bytes(),
243+
)
234244

235245
fn encode(req: HTTPRequest, uri: URI) raises -> Bytes:
236246
var res_str = String()
@@ -303,8 +313,10 @@ fn encode(res: HTTPResponse) raises -> Bytes:
303313
_ = builder.write(res.header.content_type())
304314
_ = builder.write_string(String("\r\n"))
305315

306-
# TODO: propagate charset
307-
# res_str += String("; charset=utf-8")
316+
if len(res.header.content_encoding()) > 0:
317+
_ = builder.write_string(String("Content-Encoding: "))
318+
_ = builder.write(res.header.content_encoding())
319+
_ = builder.write_string(String("\r\n"))
308320

309321
if len(res.body_raw) > 0:
310322
_ = builder.write_string(String("Content-Length: "))

lightbug_http/service.mojo

Lines changed: 18 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
1-
from lightbug_http.http import HTTPRequest, HTTPResponse, OK
2-
1+
from lightbug_http.http import HTTPRequest, HTTPResponse, OK, NotFound
2+
from lightbug_http.io.bytes import Bytes
33

44
trait HTTPService:
55
fn func(self, req: HTTPRequest) raises -> HTTPResponse:
@@ -18,11 +18,23 @@ struct Printer(HTTPService):
1818
@value
1919
struct Welcome(HTTPService):
2020
fn func(self, req: HTTPRequest) raises -> HTTPResponse:
21-
var html: String
22-
with open("static/lightbug_welcome.html", "r") as f:
23-
html = f.read()
21+
var uri = req.uri()
2422

25-
return OK(html.as_bytes(), "text/html")
23+
if uri.path() == "/":
24+
var html: Bytes
25+
with open("static/lightbug_welcome.html", "r") as f:
26+
html = f.read_bytes()
27+
return OK(html, "text/html; charset=utf-8")
28+
29+
if uri.path() == "/logo.png":
30+
var image: Bytes
31+
with open("static/logo.png", "r") as f:
32+
image = f.read_bytes()
33+
return OK(image, "image/png")
34+
35+
return NotFound(uri.path())
36+
37+
2638

2739

2840
@value

lightbug_http/sys/client.mojo

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -94,6 +94,7 @@ struct MojoClient(Client):
9494
var conn = create_connection(self.fd, host_str, port)
9595

9696
var req_encoded = encode(req, uri)
97+
print(String(req_encoded))
9798
var bytes_sent = conn.write(req_encoded)
9899
if bytes_sent == -1:
99100
raise Error("Failed to send message")

lightbug_http/sys/net.mojo

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -227,10 +227,14 @@ struct SysConnection(Connection):
227227
buf = bytes_str._buffer
228228
return bytes_recv
229229

230-
fn write(self, buf: Bytes) raises -> Int:
231-
var msg = String(buf)
230+
fn write(self, msg: String) raises -> Int:
232231
if send(self.fd, to_char_ptr(msg).bitcast[c_void](), len(msg), 0) == -1:
233232
print("Failed to send response")
233+
return len(msg)
234+
235+
fn write(self, buf: Bytes) raises -> Int:
236+
if send(self.fd, to_char_ptr(buf).bitcast[c_void](), len(buf), 0) == -1:
237+
print("Failed to send response")
234238
return len(buf)
235239

236240
fn close(self) raises:

static/lightbug_welcome.html

Lines changed: 2 additions & 4 deletions
Large diffs are not rendered by default.

0 commit comments

Comments
 (0)