I’m stuck on Stage #AP6.
The weird thing is when I was at the stage before it (#EJ5), the test succeeded normally, but after adding the part about the files endpoint, the files endpoint test succeeds and the previous stage no longer succeeds.
I’ve tried getting the last code that succeeded and just add the if condition for the files endpoint but it didn’t work.
Has anyone faced this in Go (or any other language)?
Here are my logs:
remote: [tester::#AP6] Running tests for Stage #AP6 (Get a file)
remote: [tester::#AP6] Running program
remote: [tester::#AP6] $ ./your_server.sh --directory /tmp/data/codecrafters.io/http-server-tester/
remote: [tester::#AP6] Testing existing file
remote: [tester::#AP6] Creating file apple_grape_blueberry_mango in /tmp/data/codecrafters.io/http-server-tester/
remote: [tester::#AP6] File Content: "pineapple pineapple pineapple strawberry strawberry blueberry banana banana"
remote: [your_program] Logs from your program will appear here!
remote: [tester::#AP6] Connected to localhost port 4221
remote: [tester::#AP6] $ curl -v http://localhost:4221/files/apple_grape_blueberry_mango
remote: [tester::#AP6] > GET /files/apple_grape_blueberry_mango HTTP/1.1
remote: [tester::#AP6] > Host: localhost:4221
remote: [tester::#AP6] >
remote: [tester::#AP6] Sent bytes: "GET /files/apple_grape_blueberry_mango HTTP/1.1\r\nHost: localhost:4221\r\n\r\n"
remote: [tester::#AP6] Received bytes: "HTTP/1.1 200 OK\r\nContent-Type: application/octet-stream\r\nContent-Length: 75\r\n\r\npineapple pineapple pineapple strawberry strawberry blueberry banana banana"
remote: [tester::#AP6] < HTTP/1.1 200 OK
remote: [tester::#AP6] < Content-Type: application/octet-stream
remote: [tester::#AP6] < Content-Length: 75
remote: [tester::#AP6] <
remote: [tester::#AP6] < pineapple pineapple pineapple strawberry strawberry blueberry banana banana
remote: [tester::#AP6] <
remote: [tester::#AP6] Received response with 200 status code
remote: [tester::#AP6] ✓ Content-Type header is present
remote: [tester::#AP6] ✓ Content-Length header is present
remote: [tester::#AP6] ✓ Body is correct
remote: [your_program] filename: apple_grape_blueberry_mango
remote: [tester::#AP6] First test passed.
remote: [tester::#AP6] Testing non existent file returns 404
remote: [tester::#AP6] Connected to localhost port 4221
remote: [tester::#AP6] $ curl -v http://localhost:4221/files/non-existentstrawberry_orange_mango_orange
remote: [tester::#AP6] > GET /files/non-existentstrawberry_orange_mango_orange HTTP/1.1
remote: [tester::#AP6] > Host: localhost:4221
remote: [tester::#AP6] >
remote: [tester::#AP6] Sent bytes: "GET /files/non-existentstrawberry_orange_mango_orange HTTP/1.1\r\nHost: localhost:4221\r\n\r\n"
remote: [your_program] filename: non-existentstrawberry_orange_mango_orange
remote: [tester::#AP6] Received bytes: "HTTP/1.1 404 Not Found\r\n\r\n"
remote: [tester::#AP6] < HTTP/1.1 404 Not Found
remote: [tester::#AP6] <
remote: [tester::#AP6] Received response with 404 status code
remote: [tester::#AP6] Test passed.
remote: [tester::#AP6] Terminating program
remote: [tester::#AP6] Program terminated successfully
remote:
remote: [tester::#EJ5] Running tests for Stage #EJ5 (Concurrent connections)
remote: [tester::#EJ5] Running program
remote: [tester::#EJ5] $ ./your_server.sh
remote: [tester::#EJ5] Creating 4 parallel connections
remote: [tester::#EJ5] Creating connection 1
remote: [your_program] Logs from your program will appear here!
remote: [tester::#EJ5] Creating connection 2
remote: [tester::#EJ5] Creating connection 3
remote: [tester::#EJ5] Creating connection 4
remote: [tester::#EJ5] client-1: $ curl -v http://localhost:4221/
remote: [tester::#EJ5] client-1: > GET / HTTP/1.1
remote: [tester::#EJ5] client-1: > Host: localhost:4221
remote: [tester::#EJ5] client-1: >
remote: [tester::#EJ5] client-1: Sent bytes: "GET / HTTP/1.1\r\nHost: localhost:4221\r\n\r\n"
remote: [tester::#EJ5] Failed to read response:
remote: [tester::#EJ5] Received: "" (no content received)
remote: [tester::#EJ5] ^ error
remote: [tester::#EJ5] Error: Expected: HTTP-version, Received: ""
remote: [tester::#EJ5] Test failed
remote: [tester::#EJ5] Terminating program
remote: [tester::#EJ5] Program terminated successfully
And here’s a snippet of my code:
func doConnection(conn net.Conn, directory string) {
defer func(conn net.Conn) {
if err := conn.Close(); err != nil {
fmt.Printf("error closing the connection: %v", err.Error())
}
}(conn)
var err error
var n int
var bytesBuffer bytes.Buffer
temp := make([]byte, 10)
for {
if n, err = conn.Read(temp); err != nil && err != io.EOF {
return
}
if n == 0 {
break
}
bytesBuffer.Write(temp[:n])
if n < len(temp) {
break
}
}
if bytesBuffer.Len() == 0 {
return
}
buffer := bytesBuffer.Bytes()
var requestSepIndex int
if requestSepIndex = bytes.Index(buffer, []byte{'\r', '\n'}); requestSepIndex == -1 {
return
}
requestComponents := bytes.Split(buffer[0:requestSepIndex:requestSepIndex], []byte{' '})
//method := string(requestComponents[0])
path := string(requestComponents[1])
//version := string(requestComponents[2])
var headerSepIndex int
if headerSepIndex = bytes.Index(buffer, []byte{'\r', '\n', '\r', '\n'}); headerSepIndex == -1 {
return
}
headers := make(map[string]string)
if headerSepIndex+4 < len(buffer) {
headerEntries := bytes.Split(buffer[requestSepIndex+2:headerSepIndex:headerSepIndex], []byte{'\r', '\n'})
var splitHeader [][]byte
for _, headerEntry := range headerEntries {
if splitHeader = bytes.Split(headerEntry, []byte{':', ' '}); len(splitHeader) == 2 {
headers[string(splitHeader[0])] = string(splitHeader[1])
}
}
}
var output string
if path == "/" {
output = "HTTP/1.1 200 OK\r\n\r\n"
} else if i := strings.Index(path, "/echo/"); i != -1 {
param := path[i+6:]
output = fmt.Sprintf("HTTP/1.1 200 OK\r\nContent-Type: text/plain\r\nContent-Length: %d\r\n\r\n%s", len(param), param)
} else if path == "/user-agent" {
userAgent := headers["User-Agent"]
output = fmt.Sprintf("HTTP/1.1 200 OK\r\nContent-Type: text/plain\r\nContent-Length: %d\r\n\r\n%s", len(userAgent), userAgent)
} else if i := strings.Index(path, "/files/"); i != -1 {
filename := path[i+7:]
fmt.Println("filename:", filename)
dirFs := os.DirFS(directory)
var f fs.File
if f, err = dirFs.Open(filename); err != nil {
if errors.Is(err, fs.ErrNotExist) {
output = "HTTP/1.1 404 Not Found\r\n\r\n"
} else {
output = "HTTP/1.1 400 Bad Request\r\n\r\n"
}
} else {
if fc, err := io.ReadAll(f); err != nil {
output = "HTTP/1.1 400 Bad Request\r\n\r\n"
} else {
output = fmt.Sprintf("HTTP/1.1 200 OK\r\nContent-Type: application/octet-stream\r\nContent-Length: %d\r\n\r\n%s", len(fc), string(fc))
}
}
} else {
output = "HTTP/1.1 404 Not Found\r\n\r\n"
}
if _, err = conn.Write([]byte(output)); err != nil {
return
}
}