I’m stuck on the last stage with the Failed to decode gzip: Failed to decompress data: gzip: invalid header
error.
Below are the error logs:
remote: [tester::#CR8] Running tests for Stage #CR8 (HTTP Compression - Gzip compression)
remote: [tester::#CR8] Running program
remote: [tester::#CR8] $ ./your_server.sh
remote: [tester::#CR8] Connected to localhost port 4221
remote: [tester::#CR8] $ curl -v http://localhost:4221/echo/raspberry -H "Accept-Encoding: gzip"
remote: [tester::#CR8] > GET /echo/raspberry HTTP/1.1
remote: [tester::#CR8] > Host: localhost:4221
remote: [tester::#CR8] > Accept-Encoding: gzip
remote: [tester::#CR8] >
remote: [tester::#CR8] Sent bytes: "GET /echo/raspberry HTTP/1.1\r\nHost: localhost:4221\r\nAccept-Encoding: gzip\r\n\r\n"
remote: [your_program] HTTP/1.1 200 OK
remote: [your_program] Content-Type: text/plain
remote: [your_program] Content-Length: 29
remote: [your_program] Content-Encoding: gzip
remote: [your_program]
remote: [your_program] b'\x1f\x8b\x08\x00W\x9ddf\x02\xff+J,.HJ-*\xaa\x04\x00a\xd5\x10~\t\x00\x00\x00'
remote: [tester::#CR8] Received bytes: "HTTP/1.1 200 OK\r\nContent-Type: text/plain\r\nContent-Length: 29\r\nContent-Encoding: gzip\r\n\r\nb'\\x1f\\x8b\\x08\\x00W\\x9ddf\\x02"
remote: [tester::#CR8] < HTTP/1.1 200 OK
remote: [tester::#CR8] < Content-Type: text/plain
remote: [tester::#CR8] < Content-Length: 29
remote: [tester::#CR8] < Content-Encoding: gzip
remote: [tester::#CR8] <
remote: [tester::#CR8] < b'\x1f\x8b\x08\x00W\x9ddf\x02
remote: [tester::#CR8] <
remote: [tester::#CR8] Received response with 200 status code
remote: [tester::#CR8] ✓ Content-Encoding header is present
remote: [tester::#CR8] ✓ Content-Length header is present
remote: [tester::#CR8] Failed to decode gzip: Failed to decompress data: gzip: invalid header
remote: [tester::#CR8] Test failed
remote: [tester::#CR8] Terminating program
remote: [tester::#CR8] Program terminated successfully
And here’s my code:
import argparse
import gzip
import os
import socket
import threading
def request_handler(conn: socket.socket, args: argparse.Namespace) -> None:
with conn:
data = conn.recv(1024).decode()
response = process_request(data, args)
conn.sendall(response.encode())
def process_request(data: str, args: argparse.Namespace) -> str:
request_content = data.split("\r\n")
request_method, request_target, _ = request_content[0].split()
# Process headers
request_headers = tuple([tuple(param.split(": ")) for param in request_content[2:-2]])
request_headers = dict((k.lower(), v) for k, v in request_headers)
request_body = request_content[-1]
# Handle routes
response_params = None
if request_target == "/":
response_params = {"status_code": "200", "reason": "OK", "header": "", "body": ""}
if request_target.lower().startswith("/echo/"):
echo_str = request_target[6:] # Remove '/echo/'
# Compression scheme: gzip
compression_scheme = ""
if request_headers.get("accept-encoding"):
if "gzip" in str(request_headers.get("accept-encoding")):
compression_scheme = "Content-Encoding: gzip\r\n"
echo_str = gzip.compress(echo_str.encode())
response_params = {
"status_code": "200",
"reason": "OK",
"header": f"Content-Type: text/plain\r\nContent-Length: {str(len(echo_str))}\r\n{compression_scheme}",
"body": echo_str,
}
if request_target.lower().startswith("/files/"):
filepath = os.path.join(args.directory, request_target.replace("/files/", ""))
# GET Request
if request_method == "GET":
if os.path.isfile(filepath):
with open(filepath, "r") as f:
f_content = f.read()
response_params = {
"status_code": "200",
"reason": "OK",
"header": f"Content-Type: application/octet-stream\r\nContent-Length: {len(f_content)}\r\n",
"body": f_content,
}
# POST request
if request_method == "POST":
with open(filepath, "w") as f:
f.write(request_body)
response_params = {
"status_code": "201",
"reason": "Created",
"header": f"Content-Type: application/octet-stream\r\nContent-Length: {len(request_body)}\r\n",
"body": request_body,
}
if request_target.lower() == "/user-agent":
response_params = {
"status_code": "200",
"reason": "OK",
"header": f"Content-Type: text/plain\r\nContent-Length: {len(str(request_headers.get('user-agent')))}\r\n",
"body": request_headers.get("user-agent"),
}
if not response_params:
response_params = {"status_code": "404", "reason": "Not Found", "header": "", "body": ""}
response = f"HTTP/1.1 {response_params['status_code']} {response_params['reason']}\r\n{response_params['header']}\r\n{response_params['body']}"
print(response)
return response
def main() -> None:
parser = argparse.ArgumentParser()
parser.add_argument("--directory", type=str, required=False)
args = parser.parse_args()
server_socket = socket.create_server(("localhost", 4221), reuse_port=True)
while True:
conn, addr = server_socket.accept()
threading.Thread(target=request_handler, args=(conn, args)).start()
if __name__ == "__main__":
main()
I’ve checked others solutions and it seems to me that I am not doing anything different. If anyone could give me some pointers, it would be greatly appreciated.