Created
November 19, 2014 10:03
-
-
Save ndavison/6a5d97cb8a9091cffa7a to your computer and use it in GitHub Desktop.
Python socket HTTPS client connection example
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/bin/env python | |
""" | |
A simple example of using Python sockets for a client HTTPS connection. | |
""" | |
import ssl | |
import socket | |
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM) | |
s.connect(('github.com', 443)) | |
s = ssl.wrap_socket(s, keyfile=None, certfile=None, server_side=False, cert_reqs=ssl.CERT_NONE, ssl_version=ssl.PROTOCOL_SSLv23) | |
s.sendall("GET / HTTP/1.1\r\nHost: github.com\r\nConnection: close\r\n\r\n") | |
while True: | |
new = s.recv(4096) | |
if not new: | |
s.close() | |
break | |
print new | |
I am not sure how to thank you!
Btw in python3, the 20th row must be print(new) and12nd row must be s.sendall(b"GET ........
I kept getting code 400 or 301, because of the httpS thing, but this solved the problem. Thanks a lot!
I wrote some code like this before.
import socket
import ssl
target_host = "www.dbappsecurity.com.cn"
target_port = 443
client = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
# connect the client
client.connect((target_host, target_port))
# ssl wrap the socket
context = ssl.create_default_context()
client = context.wrap_socket(client, server_hostname=target_host)
client.send(
f"GET /xyz/../service/ HTTP/1.1\r\nHost:{target_host}\r\n\r\n".encode())
# receive some data
response = b''
while True:
data = client.recv(4096)
print(f'receiving {len(data)} bytes data...')
response += data
if not data:
client.close()
break
http_response = repr(response)
http_response_len = len(http_response)
# display the response
print(f"http_response_len={http_response_len}, http_response={http_response}")
I updated the code mentioned above.
#!/usr/bin/env python
# coding=utf-8
import fire
import logging
import re
import socket
import ssl
from urllib.parse import urlparse
import cchardet as chardet
def socket_http(hostname: str, port: int, path: str, http_version: str, method: str):
"""
Use socket to connect to hostname:port, send GET request, receive response
Args:
hostname (_type_): _description_
port (_type_): _description_
path (_type_): _description_
"""
logging.info(
f'Connecting to {hostname}:{port}, send {method} {path} {http_version} request')
client = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
# connect the client
client.connect((hostname, port))
# ssl wrap the socket
if(port == 443):
context = ssl.create_default_context()
client = context.wrap_socket(client, server_hostname=hostname)
# https://blog.insightdatascience.com/learning-about-the-http-connection-keep-alive-header-7ebe0efa209d
# Keep-alive connections are enabled by default in HTTP/1.1 while not in HTTP/1.0. HTTP/1.0 was designed to close the connection after every request between client and server.
client.send(
f"{method} {path} HTTP/{http_version}\r\nHost:{hostname}\r\n\r\n".encode())
# receive some data
response = b''
while True:
data = client.recv(4096)
logging.debug(f'receiving {len(data)} bytes data...')
response += data
if not data:
client.close()
break
return response
def guess_encoding(data: bytes):
"""
Detect the encoding of the data
# https://stackoverflow.com/questions/2423872/how-to-determine-the-encoding-of-a-string-in-python
# https://dev.to/bowmanjd/character-encodings-and-detection-with-python-chardet-and-cchardet-4hj7
Args:
data (bytes): _description_
"""
detection = chardet.detect(data)
return detection["encoding"]
def main(url: str = "www.jwc.ynu.edu.cn/info/1013/../../gzzd/../info/1009/3129.htm", method: str = "GET", http_version: str = f"1.0", debug: bool = True):
"""
The main function
Args:
url (_type_, optional): _description_. Defaults to "www.jwc.ynu.edu.cn/info/1013/../../gzzd/../info/1009/3129.htm".
method (str, optional): _description_. Defaults to "GET".
http_version (str, optional): _description_. Defaults to "1.0".
"""
# configure the logging
logging.basicConfig(
encoding='utf-8', level=logging.DEBUG if debug else logging.INFO)
# normalize url if the url is not prefixed with a scheme
if not re.match(r"^\w+:\/\/", url):
logging.warning('The scheme of url is not set, default to http://')
url = 'http://' + url
# use urlparse to parse the url, return ParseResult
parsedResult = urlparse(url)
scheme, hostname, port, path = parsedResult.scheme, parsedResult.hostname, parsedResult.port, parsedResult.path
# check if scheme is http or https
if scheme != 'http' and scheme != 'https':
logging.error(f'{url} is not a valid url, only support http or https')
exit(-1)
# nomalize port if port is not specified
port = port if port else 80 if parsedResult.scheme == 'http' else 443
path = path if path else '/'
response = socket_http(hostname, port, path, http_version, method)
# display the response
encoding = guess_encoding(response)
logging.debug(f'The guessed encoding of response is {encoding}')
print(
f"response_len={len(response)}, response={response.decode(encoding)}")
if __name__ == '__main__':
# Make Python Fire not use a pager when it prints a help text
fire.core.Display = lambda lines, out: print(*lines, file=out)
fire.Fire(main)
Thank you so much for this example 🙏
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
"socket.error: [Errno 111] Connection refused"