Backend Development 12 min read

Using Python's socket Library to Simulate HTTP Requests: Basic and Advanced Examples

This article explains how to use Python's socket module to craft and send raw HTTP GET, POST, and custom‑header requests, then shows how to encapsulate the logic into reusable classes that handle authentication, redirects, cookies, and HTTPS, providing a low‑level networking toolkit for developers.

Test Development Learning Exchange
Test Development Learning Exchange
Test Development Learning Exchange
Using Python's socket Library to Simulate HTTP Requests: Basic and Advanced Examples

The introduction explains that using Python's socket library to simulate HTTP requests bypasses high‑level libraries like requests , giving deeper insight into the HTTP protocol and fine‑grained control over request details.

Basic Example – Sending an HTTP GET request

import socket

def send_http_get_request(host, port, path="/"):
    # Create a socket object
    client_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
    try:
        # Connect to the server
        client_socket.connect((host, port))
        # Prepare HTTP request message
        request = f"GET {path} HTTP/1.1\r\nHost: {host}\r\nConnection: close\r\n\r\n"
        # Send request
        client_socket.sendall(request.encode())
        # Receive response
        response = b""
        while True:
            part = client_socket.recv(1024)
            if not part:
                break
            response += part
        # Print response
        print(response.decode())
    finally:
        # Close connection
        client_socket.close()

send_http_get_request('www.example.com', 80)

Basic Example – Sending an HTTP POST request

import socket

def send_http_post_request(host, port, path="/", data=""):
    client_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
    try:
        client_socket.connect((host, port))
        request = f"POST {path} HTTP/1.1\r\nHost: {host}\r\nContent-Length: {len(data)}\r\nConnection: close\r\n\r\n{data}"
        client_socket.sendall(request.encode())
        response = b""
        while True:
            part = client_socket.recv(1024)
            if not part:
                break
            response += part
        print(response.decode())
    finally:
        client_socket.close()

send_http_post_request('www.example.com', 80, '/submit', 'key=value')

Basic Example – Sending a request with custom headers

import socket

def send_custom_headers_request(host, port, path="/", headers=None):
    client_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
    try:
        client_socket.connect((host, port))
        request = f"GET {path} HTTP/1.1\r\nHost: {host}"
        if headers:
            for key, value in headers.items():
                request += f"\r\n{key}: {value}"
        request += "\r\nConnection: close\r\n\r\n"
        client_socket.sendall(request.encode())
        response = b""
        while True:
            part = client_socket.recv(1024)
            if not part:
                break
            response += part
        print(response.decode())
    finally:
        client_socket.close()

headers = {'User-Agent': 'CustomBrowser', 'Accept-Encoding': 'gzip, deflate'}
send_custom_headers_request('www.example.com', 80, '/', headers)

The notes section reminds readers about default ports (80 for HTTP, 443 for HTTPS), UTF‑8 encoding, timeout handling, and more robust error handling for production use.

Advanced Example – Encapsulating HTTP logic in a class

import socket

class HttpSocketClient:
    def __init__(self, host, port=80, timeout=10):
        self.host = host
        self.port = port
        self.timeout = timeout
        self.socket = None
    def connect(self):
        self.socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
        self.socket.settimeout(self.timeout)
        self.socket.connect((self.host, self.port))
    def send(self, request):
        self.socket.sendall(request.encode())
    def receive(self):
        response = b""
        while True:
            part = self.socket.recv(1024)
            if not part:
                break
            response += part
        return response.decode()
    def close(self):
        if self.socket:
            self.socket.close()
    def execute_request(self, request):
        self.connect()
        self.send(request)
        response = self.receive()
        self.close()
        return response

# Usage example
client = HttpSocketClient('www.example.com')
request = "GET / HTTP/1.1\r\nHost: www.example.com\r\nConnection: close\r\n\r\n"
response = client.execute_request(request)
print(response)

Advanced Example – Adding Basic Authentication

import base64

class AuthenticatedHttpSocketClient(HttpSocketClient):
    def __init__(self, host, port=80, username=None, password=None, timeout=10):
        super().__init__(host, port, timeout)
        self.username = username
        self.password = password
    def build_request(self, method, path, headers=None, body=None):
        request = f"{method} {path} HTTP/1.1\r\n"
        request += f"Host: {self.host}\r\n"
        if self.username and self.password:
            auth_header = f"Basic {base64.b64encode(f'{self.username}:{self.password}'.encode()).decode()}"
            request += f"Authorization: {auth_header}\r\n"
        if headers:
            for k, v in headers.items():
                request += f"{k}: {v}\r\n"
        if body:
            request += f"Content-Length: {len(body)}\r\n\r\n{body}"
        else:
            request += "\r\n"
        return request

# Usage example
client = AuthenticatedHttpSocketClient('www.example.com', username='user', password='pass')
request = client.build_request('GET', '/')
response = client.execute_request(request)
print(response)

Advanced Example – Automatic Redirect Handling

from urllib.parse import urlparse

class RedirectHandlingHttpSocketClient(HttpSocketClient):
    def follow_redirects(self, request, max_redirects=5):
        redirects_count = 0
        while redirects_count < max_redirects:
            response = self.execute_request(request)
            status_line = response.split('\r\n')[0]
            status_code = int(status_line.split()[1])
            if 300 <= status_code < 400:
                location_header = self.get_location_header(response)
                if location_header:
                    url = urlparse(location_header)
                    self.host = url.netloc
                    request = f"GET {url.path} HTTP/1.1\r\nHost: {self.host}\r\nConnection: close\r\n\r\n"
                    redirects_count += 1
                else:
                    raise ValueError("Redirect missing Location header.")
            else:
                return response
        raise ValueError("Too many redirects.")
    def get_location_header(self, response):
        for line in response.split('\r\n')[1:]:
            if line.startswith('Location:'):
                return line[len('Location:'):]
        return None

# Usage example
client = RedirectHandlingHttpSocketClient('www.example.com')
request = "GET / HTTP/1.1\r\nHost: www.example.com\r\nConnection: close\r\n\r\n"
response = client.follow_redirects(request)
print(response)

Advanced Example – Cookie Management

import re

class CookieHandlingHttpSocketClient(HttpSocketClient):
    def __init__(self, *args, **kwargs):
        super().__init__(*args, **kwargs)
        self.cookies = {}
    def handle_cookies(self, response):
        cookie_header = self.extract_cookie_header(response)
        if cookie_header:
            for cookie in cookie_header.split('; '):
                name, value = cookie.split('=')
                self.cookies[name] = value
    def extract_cookie_header(self, response):
        for line in response.split('\r\n')[1:]:
            if line.startswith('Set-Cookie:'):
                return line[len('Set-Cookie:'):]
        return None
    def build_request(self, method, path, headers=None, body=None):
        request = super().build_request(method, path, headers, body)
        if self.cookies:
            cookie_header = '; '.join([f"{k}={v}" for k, v in self.cookies.items()])
            request = request.replace('\r\n', f"\r\nCookie: {cookie_header}\r\n", 1)
        return request

# Usage example
client = CookieHandlingHttpSocketClient('www.example.com')
request = "GET / HTTP/1.1\r\nHost: www.example.com\r\nConnection: close\r\n\r\n"
response = client.execute_request(request)
client.handle_cookies(response)
print(client.cookies)

Advanced Example – HTTPS Support

import ssl

class SecureHttpSocketClient(HttpSocketClient):
    def connect(self):
        sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
        sock.settimeout(self.timeout)
        self.socket = ssl.wrap_socket(sock)
        self.socket.connect((self.host, self.port))

# Usage example
client = SecureHttpSocketClient('www.example.com', port=443)
request = "GET / HTTP/1.1\r\nHost: www.example.com\r\nConnection: close\r\n\r\n"
response = client.execute_request(request)
print(response)

The summary reiterates that these examples demonstrate how to build, extend, and reuse socket‑based HTTP clients in Python, covering authentication, redirects, cookies, and secure HTTPS connections, thereby providing a flexible foundation for low‑level network testing and automation.

programmingHTTPNetworkingSocket
Test Development Learning Exchange
Written by

Test Development Learning Exchange

Test Development Learning Exchange

0 followers
Reader feedback

How this landed with the community

login Sign in to like

Rate this article

Was this worth your time?

Sign in to rate
Discussion

0 Comments

Thoughtful readers leave field notes, pushback, and hard-won operational detail here.