Stuck on Stage #AP6

I’m stuck on Stage #AP6.

I’ve been using the Python asyncio library to handle concurrent connections for an earlier stage of my project. I’ve updated my code to fit the new challenge requirements, but I’m running into an error I can’t figure out.

I’d prefer to stick with asyncio rather than switching to threading. Can you help me troubleshoot and fix the issue with my asyncio setup?

Here are my logs:

remote: Running tests on your code. Logs should appear shortly...
remote: 
remote: [compile] Moved ./.codecrafters/run.sh → ./your_program.sh
remote: [compile] Compilation successful.
remote: 
remote: Debug = true
remote: 
remote: [tester::#AP6] Running tests for Stage #AP6 (Return a file)
remote: [tester::#AP6] Running program
remote: [tester::#AP6] $ ./your_program.sh --directory /tmp/data/codecrafters.io/http-server-tester/
remote: [tester::#AP6] Testing existing file
remote: [tester::#AP6] Creating file pineapple_strawberry_apple_banana in /tmp/data/codecrafters.io/http-server-tester/
remote: [tester::#AP6] File Content: "strawberry raspberry orange grape pineapple banana orange pineapple"
remote: [your_program] Usage: python app.py --directory=<directory>
remote: [tester::#AP6] Failed to create connection: dial tcp [::1]:4221: connect: connection refused
remote: [tester::#AP6] Test failed
remote: [tester::#AP6] Terminating program
remote: [tester::#AP6] Program terminated successfully

And here’s a snippet of my code:


import asyncio
import sys
import os

async def handle_client(reader, writer):
    request_data = await reader.read(1024)
    request_lines = request_data.decode().split("\r\n")
    
    if len(request_lines) > 0:
        request_line = request_lines[0]
        parts = request_line.split(" ")
        
        if len(parts) > 1:
            method, path = parts[0], parts[1]

            if path == "/":
                response = build_response("200 OK")
                
            elif path.startswith("/user-agent"):
                user_agent = None
                for line in request_lines[1:]:
                    if line.startswith("User-Agent:"):
                        user_agent = line.split(": ", 1)[1]
                        break
                if user_agent:
                    response = build_response("200 OK", content_type="text/plain", body=user_agent.encode())
                else:
                    response = build_response("400 Bad Request", body=b"Bad Request")

            elif path.startswith("/files"):
                filename = path[len("/files/"):]
                file_path = os.path.join(directory, filename)
                print(f"Requested file path: {file_path}")

                response = await read_file(file_path)
                
            else:
                response = build_response("404 Not Found", body=b"Not Found")
            
            writer.write(response)
            await writer.drain()
            writer.close()
            await writer.wait_closed()

async def read_file(file_path):
    loop = asyncio.get_running_loop()
    try:
        with open(file_path, 'rb') as f:
            file_contents = await loop.run_in_executor(None, f.read)
        return build_response("200 OK", content_type="application/octet-stream", body=file_contents)
    except FileNotFoundError:
        return build_response("404 Not Found", body=b"File not found")

def build_response(status_code, content_type="text/plain", body=b""):
    headers = [
        f"HTTP/1.1 {status_code}",
        f"Content-Type: {content_type}",
        f"Content-Length: {len(body)}",
        "",  # End of headers
    ]
    
    headers_str = "\r\n".join(headers)
    return headers_str.encode() + b"\r\n" + body

async def main():
    global directory
    if len(sys.argv) != 3 or not sys.argv[1].startswith("--directory="):
        print("Usage: python app.py --directory=<directory>")
        return

    directory = sys.argv[1].split("=", 1)[1]

    if not os.path.isdir(directory):
        print(f"Directory does not exist or is not a directory: {directory}")
        return

    server = await asyncio.start_server(handle_client, "localhost", 4221)

    async with server:
        await server.serve_forever()

if __name__ == "__main__":
    asyncio.run(main())


1 Like

@manublackwell I don’t think the error has anything to do with asyncio here, since the logs show this line:

Usage: python app.py --directory=<directory>

When you execute your program like the tester does (./your_program.sh --directory /tmp/data/codecrafters.io/http-server-tester/), maybe the argument parsing code doesn’t work as expected?

1 Like

Closing this thread due to inactivity. If you still need assistance, feel free to start a new discussion!

This topic was automatically closed 5 days after the last reply. New replies are no longer allowed.