diff --git a/mojoweb/handler.mojo b/mojoweb/handler.mojo deleted file mode 100644 index 6f1073e1..00000000 --- a/mojoweb/handler.mojo +++ /dev/null @@ -1,3 +0,0 @@ -@value -struct RequestHandler: - ... diff --git a/mojoweb/http.mojo b/mojoweb/http.mojo index f3b1c772..3fd4216f 100644 --- a/mojoweb/http.mojo +++ b/mojoweb/http.mojo @@ -5,6 +5,7 @@ from mojoweb.stream import StreamReader from mojoweb.body import Body, RequestBodyWriter, ResponseBodyWriter from mojoweb.io.bytes import Bytes from mojoweb.io.sync import Duration +from mojoweb.net import Addr trait Request: @@ -64,3 +65,146 @@ trait Response: fn connection_close(self) -> Bool: ... + + +@value +struct HTTPRequest(Request): + var header: RequestHeader + var uri: URI + + var post_args: Args + + var body_stream: StreamReader + var w: RequestBodyWriter + var body: Body + var body_raw: Bytes + + # TODO: var multipart_form + # TODO: var multipart_form_boundary + + var parsed_uri: Bool + # TODO: var parsed_post_args: Bool + + # TODO: var keep_body_buffer: Bool + + var server_is_tls: Bool + + var timeout: Duration + + # TODO: var use_host_header: Bool + + var disable_redirect_path_normalization: Bool + + fn __init__(inout self, uri: URI): + self.header = RequestHeader() + self.uri = uri + self.post_args = Args() + self.body_stream = StreamReader() + self.w = RequestBodyWriter() + self.body = Body() + self.body_raw = Bytes() + self.parsed_uri = False + self.server_is_tls = False + self.timeout = Duration() + self.disable_redirect_path_normalization = False + + fn __init__( + inout self, + header: RequestHeader, + uri: URI, + post_args: Args, + body: Bytes, + parsed_uri: Bool, + server_is_tls: Bool, + timeout: Duration, + disable_redirect_path_normalization: Bool, + ): + self.header = header + self.uri = uri + self.post_args = post_args + self.body_stream = StreamReader() + self.w = RequestBodyWriter() + self.body = Body() + self.body_raw = body + self.parsed_uri = parsed_uri + self.server_is_tls = server_is_tls + self.timeout = timeout + self.disable_redirect_path_normalization = disable_redirect_path_normalization + + fn set_host(inout self, host: String) -> Self: + _ = self.uri.set_host(host) + return self + + fn set_host_bytes(inout self, host: Bytes) -> Self: + _ = self.uri.set_host_bytes(host) + return self + + fn host(self) -> String: + return self.uri.host() + + fn set_request_uri(inout self, request_uri: String) -> Self: + _ = self.header.set_request_uri(request_uri._buffer) + self.parsed_uri = False + return self + + fn set_request_uri_bytes(inout self, request_uri: Bytes) -> Self: + _ = self.header.set_request_uri_bytes(request_uri) + return self + + fn request_uri(inout self) -> String: + if self.parsed_uri: + _ = self.set_request_uri_bytes(self.uri.request_uri()) + return self.header.request_uri() + + fn set_connection_close(inout self, connection_close: Bool) -> Self: + _ = self.header.set_connection_close() + return self + + fn connection_close(self) -> Bool: + return self.header.connection_close() + + +@value +struct HTTPResponse(Response): + var header: ResponseHeader + + var stream_immediate_header_flush: Bool + var stream_body: Bool + + var body_stream: StreamReader + var w: ResponseBodyWriter + var body: Body + var body_raw: Bytes + + var skip_reading_writing_body: Bool + + # TODO: var keep_body_buffer: Bool + + var raddr: Addr + var laddr: Addr + + fn __init__(inout self, header: ResponseHeader, body: Bytes): + self.header = header + self.stream_immediate_header_flush = False + self.stream_body = False + self.body_stream = StreamReader() + self.w = ResponseBodyWriter() + self.body = Body() + self.body_raw = body + self.skip_reading_writing_body = False + self.raddr = Addr() + self.laddr = Addr() + + fn set_status_code(inout self, status_code: Int) -> Self: + _ = self.header.set_status_code(status_code) + return self + + fn status_code(self) -> Int: + return self.header.status_code() + + fn set_connection_close(inout self, connection_close: Bool) -> Self: + _ = self.header.set_connection_close() + return self + + fn connection_close(self) -> Bool: + return self.header.connection_close() diff --git a/mojoweb/python/http.mojo b/mojoweb/python/http.mojo deleted file mode 100644 index d4ed78d4..00000000 --- a/mojoweb/python/http.mojo +++ /dev/null @@ -1,152 +0,0 @@ -from mojoweb.header import RequestHeader, ResponseHeader -from mojoweb.uri import URI -from mojoweb.args import Args -from mojoweb.stream import StreamReader -from mojoweb.net import Addr -from mojoweb.body import Body, RequestBodyWriter, ResponseBodyWriter -from mojoweb.io.bytes import Bytes -from mojoweb.io.sync import Duration -from mojoweb.http import Request, Response - - -@value -struct PythonRequest(Request): - var header: RequestHeader - var uri: URI - - var post_args: Args - - var body_stream: StreamReader - var w: RequestBodyWriter - var body: Body - var body_raw: Bytes - - # TODO: var multipart_form - # TODO: var multipart_form_boundary - - var parsed_uri: Bool - # TODO: var parsed_post_args: Bool - - # TODO: var keep_body_buffer: Bool - - var server_is_tls: Bool - - var timeout: Duration - - # TODO: var use_host_header: Bool - - var disable_redirect_path_normalization: Bool - - fn __init__(inout self, uri: URI): - self.header = RequestHeader() - self.uri = uri - self.post_args = Args() - self.body_stream = StreamReader() - self.w = RequestBodyWriter() - self.body = Body() - self.body_raw = Bytes() - self.parsed_uri = False - self.server_is_tls = False - self.timeout = Duration() - self.disable_redirect_path_normalization = False - - fn __init__( - inout self, - header: RequestHeader, - uri: URI, - post_args: Args, - body: Bytes, - parsed_uri: Bool, - server_is_tls: Bool, - timeout: Duration, - disable_redirect_path_normalization: Bool, - ): - self.header = header - self.uri = uri - self.post_args = post_args - self.body_stream = StreamReader() - self.w = RequestBodyWriter() - self.body = Body() - self.body_raw = body - self.parsed_uri = parsed_uri - self.server_is_tls = server_is_tls - self.timeout = timeout - self.disable_redirect_path_normalization = disable_redirect_path_normalization - - fn set_host(inout self, host: String) -> Self: - _ = self.uri.set_host(host) - return self - - fn set_host_bytes(inout self, host: Bytes) -> Self: - _ = self.uri.set_host_bytes(host) - return self - - fn host(self) -> String: - return self.uri.host() - - fn set_request_uri(inout self, request_uri: String) -> Self: - _ = self.header.set_request_uri(request_uri._buffer) - self.parsed_uri = False - return self - - fn set_request_uri_bytes(inout self, request_uri: Bytes) -> Self: - _ = self.header.set_request_uri_bytes(request_uri) - return self - - fn request_uri(inout self) -> String: - if self.parsed_uri: - _ = self.set_request_uri_bytes(self.uri.request_uri()) - return self.header.request_uri() - - fn set_connection_close(inout self, connection_close: Bool) -> Self: - _ = self.header.set_connection_close() - return self - - fn connection_close(self) -> Bool: - return self.header.connection_close() - - -@value -struct PythonResponse(Response): - var header: ResponseHeader - - var stream_immediate_header_flush: Bool - var stream_body: Bool - - var body_stream: StreamReader - var w: ResponseBodyWriter - var body: Body - var body_raw: Bytes - - var skip_reading_writing_body: Bool - - # TODO: var keep_body_buffer: Bool - - var raddr: Addr - var laddr: Addr - - fn __init__(inout self, header: ResponseHeader, body: Bytes): - self.header = header - self.stream_immediate_header_flush = False - self.stream_body = False - self.body_stream = StreamReader() - self.w = ResponseBodyWriter() - self.body = Body() - self.body_raw = body - self.skip_reading_writing_body = False - self.raddr = Addr() - self.laddr = Addr() - - fn set_status_code(inout self, status_code: Int) -> Self: - _ = self.header.set_status_code(status_code) - return self - - fn status_code(self) -> Int: - return self.header.status_code() - - fn set_connection_close(inout self, connection_close: Bool) -> Self: - _ = self.header.set_connection_close() - return self - - fn connection_close(self) -> Bool: - return self.header.connection_close() diff --git a/mojoweb/python/net.mojo b/mojoweb/python/net.mojo index 479992dd..fe026229 100644 --- a/mojoweb/python/net.mojo +++ b/mojoweb/python/net.mojo @@ -10,7 +10,7 @@ from mojoweb.net import ( default_buffer_size, ) from mojoweb.http import Request, Response -from mojoweb.service import Service +from mojoweb.service import HTTPService from mojoweb.net import Connection, default_tcp_keep_alive from mojoweb.strings import NetworkType, CharSet diff --git a/mojoweb/python/server.mojo b/mojoweb/python/server.mojo index 2de74aca..4664e0f6 100644 --- a/mojoweb/python/server.mojo +++ b/mojoweb/python/server.mojo @@ -1,14 +1,15 @@ -from mojoweb.server import Server, DefaultConcurrency +from mojoweb.server import DefaultConcurrency from mojoweb.net import Listener +from mojoweb.http import HTTPRequest, HTTPResponse from mojoweb.python.net import PythonTCPListener, PythonListenConfig, PythonNet -from mojoweb.handler import RequestHandler +from mojoweb.service import RawBytesService from mojoweb.io.sync import Duration +from mojoweb.io.bytes import Bytes from mojoweb.error import ErrorHandler from mojoweb.strings import NetworkType struct PythonServer: - var handler: RequestHandler var error_handler: ErrorHandler # TODO: header_received @@ -52,10 +53,7 @@ struct PythonServer: var open: Atomic[DType.int32] var stop: Atomic[DType.int32] - fn __init__( - inout self, addr: String, handler: RequestHandler, error_handler: ErrorHandler - ): - self.handler = handler + fn __init__(inout self, addr: String, error_handler: ErrorHandler): self.error_handler = error_handler self.name = "mojoweb" @@ -101,13 +99,15 @@ struct PythonServer: return concurrency fn listen_and_serve( - inout self, address: String, handler: RequestHandler + inout self, address: String, handler: RawBytesService ) raises -> None: var __net = PythonNet() let listener = __net.listen(NetworkType.tcp4.value, address) self.serve(listener, handler) - fn serve(inout self, ln: PythonTCPListener, handler: RequestHandler) raises -> None: + fn serve( + inout self, ln: PythonTCPListener, handler: RawBytesService + ) raises -> None: let max_worker_count = self.get_concurrency() # logic for non-blocking read and write here, see for example https://github.com/valyala/fasthttp/blob/9ba16466dfd5d83e2e6a005576ee0d8e127457e2/server.go#L1789 @@ -115,5 +115,13 @@ struct PythonServer: self.ln.append(ln) while True: - let conn = self.ln[0].accept() - self.open.__iadd__(1) + try: + let conn = self.ln[0].accept() + self.open.__iadd__(1) + var buf = Bytes() + _ = conn.read(buf) + let res = handler.func(buf) + _ = conn.write(res) + conn.close() + except: + break diff --git a/mojoweb/server.mojo b/mojoweb/server.mojo index 430b2611..7b2cf83d 100644 --- a/mojoweb/server.mojo +++ b/mojoweb/server.mojo @@ -1,22 +1,22 @@ -from mojoweb.handler import RequestHandler from mojoweb.error import ErrorHandler +from mojoweb.service import HTTPService from mojoweb.net import Listener from mojoweb.io.sync import Duration alias DefaultConcurrency: Int = 256 * 1024 -trait Server: +trait ServerTrait: fn __init__( - inout self, addr: String, handler: RequestHandler, error_handler: ErrorHandler + inout self, addr: String, service: HTTPService, error_handler: ErrorHandler ): ... fn get_concurrency(self) -> Int: ... - fn listen_and_serve(self, address: String, handler: RequestHandler) raises -> None: + fn listen_and_serve(self, address: String, handler: HTTPService) raises -> None: ... - fn serve(self, ln: Listener, handler: RequestHandler) raises -> None: + fn serve(self, ln: Listener, handler: HTTPService) raises -> None: ... diff --git a/mojoweb/service.mojo b/mojoweb/service.mojo index 570dca86..3df7ddbc 100644 --- a/mojoweb/service.mojo +++ b/mojoweb/service.mojo @@ -1,6 +1,12 @@ from mojoweb.http import Request, Response +from mojoweb.io.bytes import Bytes -trait Service(CollectionElement): +trait HTTPService: fn func(self, req: Request) raises -> Response: ... + + +trait RawBytesService: + fn func(self, req: Bytes) raises -> Bytes: + ...