Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- def make_http_request(host, port, resource, file_name):
- """
- Get an HTTP resource from a server
- :param bytes host: the ASCII domain name or IP address of the server machine (i.e., host) to connect to
- :param int port: port number to connect to on server host
- :param bytes resource: the ASCII path/name of resource to get. This is everything in the URL after the domain name,
- including the first /.
- :param file_name: string (str) containing name of file in which to store the retrieved resource
- :return: the status code
- :rtype: int
- :author: Noah Mayers
- """
- # Open socket, establish connection, and request web resource
- tcp_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
- tcp_socket.connect((host, port))
- tcp_socket.sendall(b'GET ' + resource + b' HTTP/1.1\x0d\x0a' + b'Host: ' + host + b'\x0d\x0a\x0d\x0a')
- # Obtains length, and receives content based on that length
- response = b''
- length = get_length(tcp_socket)
- for i in range(0, length):
- response += tcp_socket.recv(1)
- # Creates file and writes to the file
- file_object = open(file_name, "w+b")
- file_object.write(response)
- file_object.close()
- tcp_socket.close()
- return response
- def get_length(data_socket):
- """
- Reads length until proper indicator is given
- :return: length of response
- :rtype: int
- :author: Matthew Kouzios
- """
- message = b''
- numCRLF = 0
- CR = b'\x0d'
- data = list()
- # Loop through header storing each line in a list until CRLF is found back to back,
- # as that indicates the end of header
- while numCRLF != 2:
- val = next_byte(data_socket)
- if val == CR:
- numCRLF += 1
- message = message.decode('ASCII')
- data.append(message)
- message = b''
- next_byte(data_socket) # Clear LF value
- else:
- numCRLF = 0
- message += val
- # Loop through list of header lines to find length of header through chunking or Content-Length
- for i in range(len(data)):
- message = data[i]
- message_no_nums = re.sub("\d+", "", message)
- if message_no_nums == 'Content-Length: ':
- message_only_nums = re.sub(r"\D", "", message)
- return int(message_only_nums)
- if message == 'Transfer-Encoding: chunked':
- return get_chunked_length(data_socket) - 2 # \r\n are last 2 bytes, thus subtract 2
- def get_chunked_length(data_socket):
- """
- Reads length of chunked data until proper indicator is given
- :return: length of response
- :rtype: int
- :author: Matthew Kouzios
- """
- find_length = True
- CR = b'\x0d'
- message = b''
- # Clear the first two bytes to ensure proper length
- next_byte(data_socket)
- next_byte(data_socket)
- # Loop until \r\n is hit, then return the values
- while find_length:
- val = next_byte(data_socket)
- if val == CR:
- length = int.from_bytes(message, 'big')
- return length
- message += val
- def next_byte(data_socket):
- """
- Read the next byte from the socket data_socket.
- The data_socket argument should be an open tcp data connection
- socket (either a client socket or a server data socket).
- It should not be a tcp server's listening socket.
- Read the next byte from the server.
- If the byte is not yet available, this method blocks (waits)
- until the byte becomes available.
- If there are no more bytes, this method blocks indefinitely.
- :param data_socket: The socket to read from
- :return: the next byte, as a bytes object with a single byte in it
- """
- return data_socket.recv(1)
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement