blob: 1df9e092b24257e05fcfac1fef341fb128a485dd [file] [log] [blame]
#!/usr/bin/env python3
"""Common logic between the ad hoc client and server."""
# Licensed to the Apache Software Foundation (ASF) under one
# or more contributor license agreements. See the NOTICE file
# distributed with this work for additional information
# regarding copyright ownership. The ASF licenses this file
# to you under the Apache License, Version 2.0 (the
# "License"); you may not use this file except in compliance
# with the License. You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
import socket
def wait_for_headers_complete(sock: socket.socket) -> bytes:
"""Wait for the headers to be complete.
:param sock: The socket to read from.
:returns: The bytes read off the socket.
"""
headers = b""
while True:
data = sock.recv(1024)
if not data:
print("Socket closed.")
break
print(f'Received:\n{data}')
headers += data
if b"\r\n\r\n" in headers:
break
return headers
def determine_outstanding_bytes_to_read(read_bytes: bytes) -> int:
"""Determine how many more bytes to read from the headers.
This parses the Content-Length header to determine how many more bytes to
read.
:param read_bytes: The bytes read so far.
:returns: The number of bytes to read, or -1 if it is chunked encoded.
"""
headers = read_bytes.decode("utf-8").split("\r\n")
content_length_value = None
for header in headers:
if header.lower().startswith("content-length:"):
content_length_value = int(header.split(":")[1].strip())
elif header.lower().startswith("transfer-encoding: chunked"):
return -1
if content_length_value is None:
raise ValueError("No Content-Length header found.")
end_of_headers = read_bytes.find(b"\r\n\r\n")
if end_of_headers == -1:
raise ValueError("No end of headers found.")
end_of_headers += 4
return content_length_value - (len(read_bytes) - end_of_headers)
def drain_socket(sock: socket.socket, previously_read_data: bytes, num_bytes_to_drain: int) -> None:
"""Read the rest of the request.
:param sock: The socket to drain.
:param num_bytes_to_drain: The number of bytes to drain. If -1, then drain
bytes until the final zero-length chunk is read.
"""
read_data = previously_read_data
num_bytes_drained = 0
while True:
if num_bytes_to_drain > 0:
if num_bytes_drained >= num_bytes_to_drain:
break
elif b'0\r\n\r\n' == read_data[-5:]:
print("Found end of chunked data.")
break
data = sock.recv(1024)
print(f'Received:\n{data}')
if not data:
print("Socket closed.")
break
num_bytes_drained += len(data)
read_data += data