saviorand / lightbug_http

Simple and fast HTTP framework for Mojo! 🔥
MIT License
567 stars 36 forks source link

Request handler is called on a body with unexpected length #36

Closed saviorand closed 5 months ago

saviorand commented 5 months ago

Issue raised by the author of https://github.com/alainrollejr/mocodes

Describe the bug Test client sends POST messages of a certain length L (smaller than 4096 bytes). Currently in selected cases handler func() is called on body with unexpected length that is smaller than L. This requires maintaining additional state to handle these cases

Expected behavior The handler should only be called when the full L bytes have been received on the socket

alainrollejr commented 5 months ago

My test client is written in Python and performs following lines of code:

import requests

# Define the number of bytes you want to send
nc = 1872 # number of codeword bits in codeword, TODO waaaaay to hard coded
npacket = 1300 # nr of packets to send in for loop

# Create a binary blob of LLR bytes all with the value "10" (essentially an all-zeroes codeword)
data = bytes([0x0A] * nc)

# Print the first 4 and last 4 bytes of the data as signed integers
first_4_bytes = [int.from_bytes(data[i:i+1], byteorder='little', signed=True) for i in range(4)]
print("First 4 bytes:", first_4_bytes)

# URL of the server
url = "http://0.0.0.0:8080"

# Send the data as a POST request to the server
# response = requests.post(url, data=data)
headers = {'Content-Type': 'application/octet-stream'}

# Print the response headers
#print("Response Headers:", response.headers)

for i in range(npacket):
    response = requests.post(url, data=data, headers=headers)
    try:
        # Get the response body as bytes
        response_bytes = response.content

    except Exception as e:
        print("Error parsing server response:", e)
saviorand commented 5 months ago

Thanks @alainrollejr ! One more question: how does your handler look like/how do you process these requests on the Lightbug side? Or are you just using the default one in lightbug.🔥?

saviorand commented 5 months ago

If I use the handler from bench.mojo (by running mojo bench.mojo, which would start a server), everything seems to work, this is the output I'm getting. Will try more, let me know if this is not the correct way to reproduce

First 4 bytes: [10, 10, 10, 10]

The code:

import requests

# Define the number of bytes you want to send
nc = 1872 # number of codeword bits in codeword, TODO waaaaay to hard coded
npacket = 1300 # nr of packets to send in for loop

# Create a binary blob of LLR bytes all with the value "10" (essentially an all-zeroes codeword)
data = bytes([0x0A] * nc)

# Print the first 4 and last 4 bytes of the data as signed integers
first_4_bytes = [int.from_bytes(data[i:i+1], byteorder='little', signed=True) for i in range(4)]
print("First 4 bytes:", first_4_bytes)

# URL of the server
url = "http://0.0.0.0:8080"

# Send the data as a POST request to the server
# response = requests.post(url, data=data)
headers = {'Content-Type': 'application/octet-stream'}

# Print the response headers
#print("Response Headers:", response.headers)

for i in range(npacket):
    response = requests.post(url, data=data, headers=headers)
    try:
        # Get the response body as bytes
        response_bytes = response.content
        response_len = len(response_bytes)
        if response_len != 12:
            print('response is not equal to expected length')

    except Exception as e:
        print("Error parsing server response:", e)
alainrollejr commented 5 months ago

Hi, this is example server code to reproduce the issue (I am on MacBook Pro M3):

from lightbug_http import *

from sys import is_defined

@value
struct MyPrinter(HTTPService):
    fn func(self, req: HTTPRequest) raises -> HTTPResponse:
        var body = req.body_raw
        var n = body.__len__()
        if n < 1872:
            print("unexpected length n = ",n)
        else:
            print(n)

        return OK(body)

fn main() raises:
    var server = SysServer()
    var handler = MyPrinter()
    server.listen_and_serve("0.0.0.0:8080", handler)

If I connect the above python client to this service, output would look like:

Ready to accept connections...
2078
unexpected length n =  206
unexpected length n =  206
2078
unexpected length n =  206
unexpected length n =  206
unexpected length n =  206
unexpected length n =  206
unexpected length n =  206
2078
unexpected length n =  206
unexpected length n =  206
unexpected length n =  206
unexpected length n =  206
unexpected length n =  206
unexpected length n =  206
unexpected length n =  206
2078
2078
2078
2078
2078
2078
2078
2078
2078

Note that the occurrences of "unexpected length" would be at random different positions every time I run the client

saviorand commented 5 months ago

Fixed in https://github.com/saviorand/lightbug_http/pull/39 . Can you confirm if this helped?

saviorand commented 5 months ago

Closing as per discussion on Discord, this seemed to help!