Skip to content

Commit

Permalink
switch listen back to string
Browse files Browse the repository at this point in the history
  • Loading branch information
saviorand committed Feb 8, 2025
1 parent 0d24973 commit 81822e9
Show file tree
Hide file tree
Showing 8 changed files with 47 additions and 47 deletions.
2 changes: 2 additions & 0 deletions .env.example
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
DEFAULT_SERVER_PORT=8080
DEFAULT_SERVER_HOST=localhost
4 changes: 2 additions & 2 deletions docker/docker-compose.yml
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,8 @@ services:
build:
context: .
args:
- SERVER_PORT=${SERVER_PORT}
- DEFAULT_SERVER_PORT=${DEFAULT_SERVER_PORT}
ports:
- "${SERVER_PORT}:${SERVER_PORT}"
- "${DEFAULT_SERVER_PORT}:${DEFAULT_SERVER_PORT}"
environment:
- APP_ENTRYPOINT=${APP_ENTRYPOINT}
4 changes: 2 additions & 2 deletions docker/lightbug.dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,8 @@ RUN git clone https://github.com/Lightbug-HQ/lightbug_http

WORKDIR /lightbug_http

ARG SERVER_PORT=8080
EXPOSE ${SERVER_PORT}
ARG DEFAULT_SERVER_PORT=8080
EXPOSE ${DEFAULT_SERVER_PORT}

ENV APP_ENTRYPOINT=lightbug.🔥
CMD magic run mojo ${APP_ENTRYPOINT}
7 changes: 6 additions & 1 deletion lightbug.🔥
Original file line number Diff line number Diff line change
@@ -1,6 +1,11 @@
from lightbug_http import Welcome, Server
from os.env import getenv

fn main() raises:
var server = Server()
var handler = Welcome()
server.listen_and_serve("localhost:8080", handler)

var host = getenv("DEFAULT_SERVER_HOST", "localhost")
var port = getenv("DEFAULT_SERVER_PORT", "8080")

server.listen_and_serve(host + ":" + port, handler)
61 changes: 24 additions & 37 deletions lightbug_http/address.mojo
Original file line number Diff line number Diff line change
Expand Up @@ -382,23 +382,11 @@ fn is_ipv6(network: NetworkType) -> Bool:
"""Check if the network type is IPv6."""
return network in (NetworkType.tcp6, NetworkType.udp6, NetworkType.ip6)

fn resolve_localhost(host: ByteView[StaticConstantOrigin], network: NetworkType) -> ByteView[StaticConstantOrigin]:
"""Resolve localhost to the appropriate IP address based on network type."""
if host != AddressConstants.LOCALHOST.as_bytes():
return host

if network.is_ipv4():
return AddressConstants.IPV4_LOCALHOST.as_bytes()
elif network.is_ipv6():
return AddressConstants.IPV6_LOCALHOST.as_bytes()

return host

fn parse_ipv6_bracketed_address(address: ByteView[StaticConstantOrigin]) raises -> (ByteView[StaticConstantOrigin], UInt16):
fn parse_ipv6_bracketed_address[origin: ImmutableOrigin](address: ByteView[origin]) raises -> (ByteView[origin], UInt16):
"""Parse an IPv6 address enclosed in brackets.
Returns:
Tuple of (host, colon_index_offset)
Tuple of (host, colon_index_offset).
"""
if address[0] != Byte(ord("[")):
return address, UInt16(0)
Expand All @@ -419,9 +407,9 @@ fn parse_ipv6_bracketed_address(address: ByteView[StaticConstantOrigin]) raises
UInt16(end_bracket_index + 1)
)

fn validate_no_brackets(address: ByteView[StaticConstantOrigin], start_idx: UInt16, end_idx: Optional[UInt16] = None) raises:
fn validate_no_brackets[origin: ImmutableOrigin](address: ByteView[origin], start_idx: UInt16, end_idx: Optional[UInt16] = None) raises:
"""Validate that the address segment contains no brackets."""
var segment: ByteView[StaticConstantOrigin]
var segment: ByteView[origin]

if end_idx is None:
segment = address[int(start_idx):]
Expand All @@ -433,7 +421,7 @@ fn validate_no_brackets(address: ByteView[StaticConstantOrigin], start_idx: UInt
if segment.find(Byte(ord("]"))) != -1:
raise Error("unexpected ']' in address")

fn parse_port(port_str: ByteView[StaticConstantOrigin]) raises -> UInt16:
fn parse_port[origin: ImmutableOrigin](port_str: ByteView[origin]) raises -> UInt16:
"""Parse and validate port number."""
if port_str == AddressConstants.EMPTY.as_bytes():
raise MissingPortError
Expand All @@ -444,39 +432,36 @@ fn parse_port(port_str: ByteView[StaticConstantOrigin]) raises -> UInt16:

return UInt16(port)

fn parse_address(network: NetworkType, address: ByteView[StaticConstantOrigin]) raises -> (ByteView[StaticConstantOrigin], UInt16):
fn parse_address[origin: ImmutableOrigin](network: NetworkType, address: ByteView[origin]) raises -> (ByteView[origin], UInt16):
"""Parse an address string into a host and port.
Args:
network: The network type (tcp, tcp4, tcp6, udp, udp4, udp6, ip, ip4, ip6, unix)
address: The address string
network: The network type (tcp, tcp4, tcp6, udp, udp4, udp6, ip, ip4, ip6, unix).
address: The address string.
Returns:
Tuple containing the host and port
Tuple containing the host and port.
"""
if address == AddressConstants.EMPTY.as_bytes():
raise Error("missing host")

if network.is_ip_protocol():
var host = resolve_localhost(address, network)
if host == AddressConstants.EMPTY.as_bytes():
raise Error("missing host")

# For IPv6 addresses in IP protocol mode, we need to handle the address as-is
if network == NetworkType.ip6 and host.find(Byte(ord(":"))) != -1:
return host, DEFAULT_IP_PORT
if network == NetworkType.ip6 and address.find(Byte(ord(":"))) != -1:
return address, DEFAULT_IP_PORT

# For other IP protocols, no colons allowed
if host.find(Byte(ord(":"))) != -1:
if address.find(Byte(ord(":"))) != -1:
raise Error("IP protocol addresses should not include ports")

return host, DEFAULT_IP_PORT
return address, DEFAULT_IP_PORT

var colon_index = address.rfind(Byte(ord(":")))
if colon_index == -1:
raise MissingPortError

var host: ByteView[StaticConstantOrigin]
var bracket_offset: UInt16 = 0

# Handle IPv6 addresses
if address[0] == Byte(ord("[")):
try:
(host, bracket_offset) = parse_ipv6_bracketed_address(address)
Expand All @@ -491,11 +476,13 @@ fn parse_address(network: NetworkType, address: ByteView[StaticConstantOrigin])
raise TooManyColonsError

var port = parse_port(address[colon_index + 1:])

host = resolve_localhost(host, network)
if host == AddressConstants.EMPTY.as_bytes():
raise Error("missing host")


if address == AddressConstants.LOCALHOST.as_bytes():
if network.is_ipv4():
return ByteView[origin].from_static_span(AddressConstants.IPV4_LOCALHOST.as_bytes()), port
elif network.is_ipv6():
return ByteView[origin].from_static_span(AddressConstants.IPV6_LOCALHOST.as_bytes()), port

return host, port


Expand Down Expand Up @@ -611,7 +598,7 @@ fn getaddrinfo[
```
#### Notes:
* Reference: https://man7.org/linux/man-pages/man3/getaddrinfo.3p.html
* Reference: https://man7.org/linux/man-pages/man3/getaddrinfo.3p.htm .
"""
var result = _getaddrinfo(
node.unsafe_ptr(), service.unsafe_ptr(), Pointer.address_of(hints), Pointer.address_of(res)
Expand Down
6 changes: 3 additions & 3 deletions lightbug_http/connection.mojo
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ from time import sleep
from memory import Span
from sys.info import os_is_macos
from lightbug_http.address import NetworkType
from lightbug_http.io.bytes import Bytes, bytes
from lightbug_http.io.bytes import Bytes, ByteView, bytes
from lightbug_http.io.sync import Duration
from lightbug_http.address import parse_address, TCPAddr, UDPAddr
from lightbug_http._libc import (
Expand Down Expand Up @@ -87,8 +87,8 @@ struct ListenConfig:
fn __init__(out self, keep_alive: Duration = default_tcp_keep_alive):
self._keep_alive = keep_alive

fn listen[network: NetworkType = NetworkType.tcp4](mut self, address: StringLiteral) raises -> NoTLSListener:
var local = parse_address(network, address.as_bytes())
fn listen[network: NetworkType = NetworkType.tcp4](mut self, address: String) raises -> NoTLSListener:
var local = parse_address[__origin_of(address)](network, address.as_bytes())
var addr = TCPAddr(str(local[0]), local[1])
var socket: Socket[TCPAddr]
try:
Expand Down
8 changes: 7 additions & 1 deletion lightbug_http/io/bytes.mojo
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
from utils import StringSlice
from memory.span import Span, _SpanIter
from memory.span import Span, _SpanIter, UnsafePointer
from lightbug_http.strings import BytesConstant
from lightbug_http.connection import default_buffer_size

Expand Down Expand Up @@ -89,6 +89,12 @@ struct ByteView[origin: Origin]():

var _inner: Span[Byte, origin]

@staticmethod
fn from_static_span(span: Span[Byte, StaticConstantOrigin]) -> ByteView[origin]:
var ptr = UnsafePointer[Byte].address_of(span[0])
var new_span = Span[Byte, origin](ptr=ptr, length=len(span))
return ByteView[origin](new_span)

@implicit
fn __init__(out self, b: Span[Byte, origin]):
self._inner = b
Expand Down
2 changes: 1 addition & 1 deletion lightbug_http/server.mojo
Original file line number Diff line number Diff line change
Expand Up @@ -81,7 +81,7 @@ struct Server(Movable):
"""
return self.max_concurrent_connections

fn listen_and_serve[T: HTTPService](mut self, address: StringLiteral, mut handler: T) raises:
fn listen_and_serve[T: HTTPService](mut self, address: String, mut handler: T) raises:
"""Listen for incoming connections and serve HTTP requests.
Parameters:
Expand Down

0 comments on commit 81822e9

Please sign in to comment.