Stuck on "Extract URL path"

I’m stuck on Stage “Extract URL path” in Build your own HTTP server challenge (by Rust). I don’t really understand how my code differs from others in code examples, I am just totally lost here. Locally, in console I see the correct output, but test runner just doesn’t see it. What am I missing here?

Here are my logs:

Debug = true
[tester::#IH0] Running tests for Stage #IH0 (Extract URL path)
[tester::#IH0] Running program
[tester::#IH0] $ ./your_program.sh
[your_program] Logs from your program will appear here!
[tester::#IH0] Connected to localhost port 4221
[tester::#IH0] $ curl -v http://localhost:4221/strawberry
[tester::#IH0] > GET /strawberry HTTP/1.1
[tester::#IH0] > Host: localhost:4221
[tester::#IH0] > 
[tester::#IH0] Sent bytes: "GET /strawberry HTTP/1.1\r\nHost: localhost:4221\r\n\r\n"
[your_program] New connection: 127.0.0.1:49424
[tester::#IH0] Failed to read response: 
[tester::#IH0] Received: "" (no content received)
[tester::#IH0]            ^ error
[tester::#IH0] Error: Expected: HTTP-version, Received: ""
[tester::#IH0] Test failed
[tester::#IH0] Terminating program
[your_program] Length of stream is: 50
[your_program] Request target found: "/strawberry"
[your_program] Result found: false
[your_program] Status Line: 404 Not Found
[your_program] 
[your_program] 
[your_program] HTTP/1.1 404 Not Found
[your_program] 
[tester::#IH0] Program terminated successfully

And here’s a snippet of my code:

fn main() {
    // You can use print statements as follows for debugging, they'll be visible when running tests.
    println!("Logs from your program will appear here!");

    // Uncomment this block to pass the first stage
    //
    let listener = TcpListener::bind("127.0.0.1:4221").unwrap();

    for stream in listener.incoming() {
        match stream {
            Ok(mut stream) => {
                println!("New connection: {}", stream.peer_addr().unwrap());
                handle_connection(stream);
            }
            Err(e) => {
                println!("error: {}", e);
            }
        }
    }
}

fn read_stream_content(stream: &mut TcpStream) -> Vec<String> {
    // Reading content of TCP stream
    let mut buffer = String::new();
    let content = stream.read_to_string(&mut buffer);

    if let Ok(length) = content {
        println!("Length of stream is: {:?}", length);
    } else {
        println!("Content is None!");
    }

    let content_ref_vector: Vec<&str> = buffer.split("\r\n").collect();
    let content_value_vector: Vec<String> = content_ref_vector.iter().map(|&s| s.to_string()).collect();
    content_value_vector

}

fn read_request_target(content: &Vec<String>) -> String {
    let request_line = content[0].clone();
    let request_line_split = {
        let mut parts = request_line.splitn(3, ' ');
        (parts.next().unwrap(), parts.next().unwrap(), parts.next().unwrap())
    };
    String::from(request_line_split.1)
}

fn match_request_line(request_line: &String) -> bool {
    if request_line.eq("/") {
        true
    } else {
        false
    }
}

fn handle_connection(mut stream: TcpStream) {
    let content_vector = read_stream_content(&mut stream);
    let request_target = read_request_target(&content_vector);
    println!("Request target found: {:?}", request_target);
    let result = match_request_line(&request_target);
    println!("Result found: {:?}", result);

    let status_line: String;
    if result == true {
        status_line = String::from("200 OK\r\n\r\n");
    } else {
        status_line = String::from("404 Not Found\r\n\r\n");
    }
    println!("Status Line: {}", status_line);

    let response = format!("HTTP/1.1 {status_line}");
    println!("{}", response);

    stream.write_all(response.as_bytes()).unwrap();

}

I’ll take a look shortly.

Hi @TaosMonk, I tried running your code against the previous stages, but it’s actually no longer passing the previous stage #IA4 (Respond with 200).

The issue originates from read_to_string(), which will try to read until EOF (end of file), which doesn’t work well with TCP streams as they’re continuous connections.

You might find the Building a Single-Threaded Web Server chapter from the the Rust book helpful.

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

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