Module spin_sdk.http

Module with helpers for wasi http

Sub-modules

spin_sdk.http.poll_loop

Defines a custom asyncio event loop backed by wasi:io/poll#poll

Functions

def send(request: Request) ‑> Response

Send an HTTP request and return a response or raise an error

async def send_and_close(sink: Sink,
data: bytes)
async def send_async(request: Request) ‑> Response

Classes

class IncomingHandler (*args, **kwargs)

Simplified handler for incoming HTTP requests using blocking, buffered I/O.

Expand source code
class IncomingHandler(exports.IncomingHandler):
    """Simplified handler for incoming HTTP requests using blocking, buffered I/O."""
    
    def handle_request(self, request: Request) -> Response:
        """Handle an incoming HTTP request and return a response or raise an error"""
        raise NotImplementedError
    
    def handle(self, request: IncomingRequest, response_out: ResponseOutparam):
        method = request.method()

        if isinstance(method, Method_Get):
            method_str = "GET"
        elif isinstance(method, Method_Head):
            method_str = "HEAD"
        elif isinstance(method, Method_Post):
            method_str = "POST"
        elif isinstance(method, Method_Put):
            method_str = "PUT"
        elif isinstance(method, Method_Delete):
            method_str = "DELETE"
        elif isinstance(method, Method_Connect):
            method_str = "CONNECT"
        elif isinstance(method, Method_Options):
            method_str = "OPTIONS"
        elif isinstance(method, Method_Trace):
            method_str = "TRACE"
        elif isinstance(method, Method_Patch):
            method_str = "PATCH"
        elif isinstance(method, Method_Other):
            method_str = method.value
        else:
            raise AssertionError

        request_body = request.consume()
        request_stream = request_body.stream()
        body = bytearray()
        while True:
            try:
                body += request_stream.blocking_read(16 * 1024)
            except Err as e:
                if isinstance(e.value, StreamError_Closed):
                    request_stream.__exit__(None, None, None)
                    IncomingBody.finish(request_body)
                    break
                else:
                    raise e

        request_uri = request.path_with_query()
        if request_uri is None:
            uri = "/"
        else:
            uri = request_uri

        try:
            simple_response = self.handle_request(Request(
                method_str,
                uri,
                dict(map(lambda pair: (pair[0], str(pair[1], "utf-8")), request.headers().entries())),
                bytes(body)
            ))
        except:
            traceback.print_exc()

            response = OutgoingResponse(Fields())
            response.set_status_code(500)
            ResponseOutparam.set(response_out, Ok(response))
            return

        if simple_response.headers.get('content-length') is None:
            content_length = len(simple_response.body) if simple_response.body is not None else 0
            simple_response.headers['content-length'] = str(content_length)

        response = OutgoingResponse(Fields.from_list(list(map(
            lambda pair: (pair[0], bytes(pair[1], "utf-8")),
            simple_response.headers.items()
        ))))
        response_body = response.body()
        response.set_status_code(simple_response.status)
        ResponseOutparam.set(response_out, Ok(response))
        response_stream = response_body.write()
        if simple_response.body is not None:
            MAX_BLOCKING_WRITE_SIZE = 4096
            offset = 0
            while offset < len(simple_response.body):
                count = min(len(simple_response.body) - offset, MAX_BLOCKING_WRITE_SIZE)
                response_stream.blocking_write_and_flush(simple_response.body[offset:offset+count])
                offset += count
        response_stream.__exit__(None, None, None)
        OutgoingBody.finish(response_body, None)

Ancestors

Methods

def handle_request(self,
request: Request) ‑> Response

Handle an incoming HTTP request and return a response or raise an error

Inherited members

class Request (method: str, uri: str, headers: MutableMapping[str, str], body: bytes | None)

An HTTP request

Expand source code
@dataclass
class Request:
    """An HTTP request"""
    method: str
    uri: str
    headers: MutableMapping[str, str]
    body: Optional[bytes]

Class variables

var body : bytes | None
var headers : MutableMapping[str, str]
var method : str
var uri : str
class Response (status: int, headers: MutableMapping[str, str], body: bytes | None)

An HTTP response

Expand source code
@dataclass
class Response:
    """An HTTP response"""
    status: int
    headers: MutableMapping[str, str]
    body: Optional[bytes]

Class variables

var body : bytes | None
var headers : MutableMapping[str, str]
var status : int