2

I am trying to make a program to process HTTP headers using uasyncio's start_server class, I can see the name headers I am trying to read in Access-Control-Request-Headers after printing the data received from a web request but cannot read the actual data stored in the headers.

Relevant Code:

async def conn(reader, writer):
    try:
        while True:
            res = await reader.read(4096)
            if(str(res) != "b''"):
                print(res)
            writer.write("Recieved!")
            await writer.drain()
    except:
        print("Err")
    print("Client disconnected")
    reader.wait_closed()


async def main():
    anim = uasyncio.create_task(animation())
    serv = await uasyncio.start_server(conn, '0.0.0.0', 80, 10)
    while True:
        await uasyncio.sleep_ms(1000)

Is anyone able to point me in the right direction or link some example code to read the headers?

3 Answers3

1

The function below will process the entire HTTP request. You should be able to give it your buffer from res = await reader.read(4096) and extract the headers from the return value.

For example:

req_buffer = await reader.read(4096)
req = parse_http_request(req_buffer)
print(req['headers'])

Here's the function definition...

# Given a raw HTTP request, return a dictionary with individual elements broken out.
# Takes a buffer containing the HTTP request sent from the client.
# Returns a dictionary containing method, path, query, headers, body, etc. or None if parsing fails.
def parse_http_request(req_buffer):
    req = {}
    req_buffer_lines = req_buffer.decode('utf8').split('\r\n')
    req['method'], target, req['http_version'] = req_buffer_lines[0].split(' ', 2)  # Example: GET /route/path HTTP/1.1
    if (not '?' in target):
        req['path'] = target
    else:  # target can have a query component, so /route/path could be something like /route/path?state=on&timeout=30
        req['path'], query_string = target.split('?', 1)
        req['query'] = parse_query_string(query_string)

    req['headers'] = {}
    for i in range(1, len(req_buffer_lines) - 1):
        if (req_buffer_lines[i] == ''):  # Blank line signifies the end of headers.
            break
        else:
            name, value = req_buffer_lines[i].split(':', 1)
            req['headers'][name.strip()] = value.strip()

    req['body'] = req_buffer_lines[len(req_buffer_lines) - 1]  # Last line is the body (or blank if no body.)
        
    return req

This function does a similar thing with the query parameters if you need them...

def parse_query_string(query_string):
    query = {}
    query_params = query_string.split('&')
    for param in query_params:
        if (not '=' in param):  # Example: somebody sent ?on instead of ?state=on
            key=param
            query[key] = ''
        else:
            key, value = param.split('=')
            query[key] = value
                
    return query
Dave H.
  • 538
  • 5
  • 11
0

The headers follow the request line, this works for me:

    # print("Client connected")
    
    request_line = await reader.readline()
    # print("Request:", request_line)
# We are not interested in HTTP request headers, skip them
    header = b""
    while header != b"\r\n":
      header = await reader.readline()
      # print('Header:', str(header) )
MangoCat
  • 89
  • 5
0

you need to read about HTTP protocol thoroughly. The headers are read using readline() as they are terminated by a \r\n. If you encounter \r\n\r\n i.e a blank line, you have encountered the end of the headers.

So from the header list, you look for a header you are after.

In regards to your byte to ascii do this

items = await reader.readline()

items = items.decode('ascii').strip()
abacusreader
  • 547
  • 1
  • 7
  • 21