Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Invalid calculation for max header size when headers are sent in at least two chunks #371

Closed
Skrethel opened this issue Mar 22, 2022 · 0 comments · Fixed by #376
Closed
Assignees
Labels

Comments

@Skrethel
Copy link

Waitress incorrectly calculates header_bytes_received when headers are sent in more than one chunk. Issue is related to following code in parser.py

            if index >= 0:
                # If the headers have ended, and we also have part of the body
                # message in data we still want to validate we aren't going
                # over our limit for received headers.
                self.header_bytes_received += index
                consumed = datalen - (len(s) - index)
            else:
                self.header_bytes_received += datalen
                consumed = datalen

Length of data from chunk first to n - 1 (n is last) is added to header_bytes_received and when finally end of headers is is found in last chunk the header_bytes_received is incremented by size of all headers. This means that length of chunks from 1 to n - 1 is counted twice in header_bytes_received.

I think that if end of headers is found, header_bytes_received should be set to position of end of headers (index).

To reproduce this issue following code can be used.
Server:

import waitress


def application(environ, start_response):
    start_response(
        "200 OK", [("Content-Type", "text/plain")]
    )
    yield b"OK\r\n"


if __name__ == "__main__":
    waitress.serve(
        application,
        max_request_header_size = 200,
    )

Client:

import socket
import time

header_data = b'1' * 100
s = socket.create_connection(('127.0.0.1', 8080), timeout = 60)

to_send = (
    b"GET /long_header HTTP/1.0\r\n"
    b"x-header:  " + header_data + b"\r\n"
)

to_send2 = (
    b"Content-Length: 0\r\n"
    b"\r\n"
)

s.send(to_send)
time.sleep(2)
s.send(to_send2)
print("Headers size: ", len(to_send) + len(to_send2))

with s.makefile('rb', 0) as fp:
    data = fp.read()
    print(data.decode())
    assert data.splitlines()[0] == b"HTTP/1.0 200 OK"

s.close()

Currently this code produces 431 HTTP error when it should work because sent headers are smaller than 200 (161 bytes)

HTTP/1.0 431 Request Header Fields Too Large
Connection: close
Content-Length: 91
Content-Type: text/plain
Date: Tue, 22 Mar 2022 12:01:39 GMT
Server: waitress

Request Header Fields Too Large

exceeds max_header of 200

(generated by waitress)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

Successfully merging a pull request may close this issue.

2 participants