NAME

LightTCP::SSLclient - SSL/TLS HTTP client with proxy support and certificate pinning

SYNOPSIS

use LightTCP::SSLclient;

my $client = LightTCP::SSLclient->new(
    timeout      => 30,
    insecure     => 0,
    verbose      => 0,
    keep_alive   => 0,
    user_agent   => 'MyClient/1.0',
    ssl_protocols=> ['TLSv1.2', 'TLSv1.3'],
    ssl_ciphers  => 'HIGH:!aNULL:!MD5',
);

my ($ok, $errors, $debug, $error_code) = $client->connect('example.com', 443);
return error($errors) unless $ok;

($ok, $errors, $debug, $error_code) = $client->request('GET', '/api/data', host => 'example.com');
return error($errors) unless $ok;

my ($code, $state, $headers, $body, $resp_errors, $resp_debug, $resp_code) = $client->response();

$client->close();

DESCRIPTION

Object-oriented SSL/TLS HTTP client with support for HTTP CONNECT proxies, certificate pinning, chunked transfer encoding, and keep-alive connections.

RETURN VALUES

All methods return multiple values. The standard convention is:

connect(), request()

($ok, $errors_ref, $debug_ref, $error_code) = $client->method(...);
$ok

Boolean success indicator (1 = success, 0 = failure)

$errors_ref

Reference to array of error messages

$debug_ref

Reference to array of debug messages (empty unless verbose mode is enabled)

$error_code

Error type constant (0 if successful): - ECONNECT (1): Connection error - EREQUEST (2): Request error - ERESPONSE (3): Response error - ETIMEOUT (4): Timeout error - ESSL (5): SSL/TLS error

response()

($code, $state, $headers_ref, $body, $errors_ref, $debug_ref, $error_code) = $client->response();
$code

HTTP status code (e.g., 200, 404)

$state

HTTP status message (e.g., "OK", "Not Found")

$headers_ref

Reference to hash of response headers (lowercase keys)

$body

Response body as string

$errors_ref, $debug_ref, $error_code

Same as above

CONSTRUCTOR OPTIONS

my $client = LightTCP::SSLclient->new(
    timeout         => 10,                     # Request timeout in seconds (default: 10)
    insecure        => 0,                      # Skip SSL verification (default: 0)
    cert            => '/path/to/client',      # Client certificate base path (optional)
    verbose         => 0,                      # Enable debug output (default: 0)
    user_agent      => 'MyClient/1.0',         # User-Agent header (default: LightTCP::SSLclient/VERSION)
    ssl_protocols   => ['TLSv1.2', 'TLSv1.3'], # Allowed SSL protocols (default: TLSv1.2, TLSv1.3)
    ssl_ciphers     => 'HIGH:!aNULL:!MD5',     # Allowed cipher suites (default: HIGH:!aNULL:!MD5:!RC4)
    keep_alive      => 0,                      # Use HTTP keep-alive (default: 0)
    buffer_size     => 8192,                   # Read buffer size (default: 8192)
    max_redirects   => 5,                      # Max redirects to follow (default: 5)
    follow_redirects=> 1,                      # Follow 3xx redirects (default: 1)
);

METHODS

Connection Methods

connect($host, $port, $proxy, $proxy_auth)

Establish SSL connection to target host.

my ($ok, $errors, $debug, $code) = $client->connect(
    'example.com',      # Target host
    443,                # Target port
    'proxy.com:8080',   # Optional HTTP proxy
    'user:pass',        # Optional proxy auth
);
reconnect()

Reconnect using previously used connection parameters.

my ($ok, $errors, $debug, $code) = $client->reconnect();
close()

Close the connection.

$client->close();

Request Methods

request($method, $path, %options)

Send HTTP request.

my ($ok, $errors, $debug, $code) = $client->request(
    'GET',                    # Method
    '/api/data',              # Path
    host    => 'example.com', # Host header
    payload => $body,         # Request body (optional)
    headers => {              # Custom headers
        'X-Custom' => 'value',
    },
);
response()

Read HTTP response.

my ($code, $state, $headers, $body, $errors, $debug, $code) = $client->response();
request_with_redirects($method, $path, %options)

Send HTTP request and automatically follow redirects.

my ($code, $state, $headers, $body, $errors, $debug, $resp_code, $history) = $client->request_with_redirects(
    'POST',                   # Method
    '/submit',                # Path
    host    => 'example.com', # Host header
    payload => $form_data,    # Request body
);

Returns an 8th value $history - arrayref of redirects followed:

foreach my $redirect (@$history) {
    print "$redirect->{code}: $redirect->{from} -> $redirect->{to}\n";
}

Redirect behavior: - 301/302: POST requests converted to GET, payload dropped - 303: Always converted to GET - 307/308: Method preserved (POST stays POST)

Fingerprint Methods

fingerprint_read($dir, $host, $port)

Read saved certificate fingerprint.

my $fp = $client->fingerprint_read($dir, $host, $port);
fingerprint_save($dir, $host, $port, $fp, $save)

Save certificate fingerprint.

my ($ok, $errors, $debug, $code) = $client->fingerprint_save(
    $dir, $host, $port, $fingerprint, $save
);
# $save = 1 to permanently save, 0 to save as .new file

ACCESSOR METHODS

socket()

Returns the underlying socket object.

is_connected()

Returns 1 if connected, 0 otherwise.

get_timeout(), set_timeout($value)

Get/set timeout.

get_user_agent(), set_user_agent($value)

Get/set User-Agent string.

get_insecure(), set_insecure($value)

Get/set insecure mode.

get_keep_alive(), set_keep_alive($value)

Get/set keep-alive mode.

get_cert(), set_cert($value)

Get/set client certificate path.

get_ssl_protocols()

Get allowed SSL protocols arrayref.

get_ssl_ciphers()

Get allowed cipher suites string.

get_buffer_size()

Get read buffer size.

get_max_redirects(), set_max_redirects($value)

Get/set maximum number of redirects to follow (default: 5).

get_follow_redirects(), set_follow_redirects($value)

Get/set whether to follow 3xx redirects (default: 1 = yes).

get_redirect_count()

Get the number of redirects followed in the last request.

get_redirect_history()

Get the redirect history from the last request (arrayref of {from, to, code}).

ERROR CODES

use LightTCP::SSLclient qw(ECONNECT EREQUEST ERESPONSE ETIMEOUT ESSL);

my ($ok, $errors, $debug, $code) = $client->connect(...);
if (!$ok) {
    if ($code == ECONNECT) { ... }
    elsif ($code == ETIMEOUT) { ... }
    elsif ($code == ESSL) { ... }
}

EXAMPLES

Basic GET request:

my $client = LightTCP::SSLclient->new(timeout => 30);
my ($ok, $errors, $debug) = $client->connect('example.com', 443);
die "Connect failed: @$errors" unless $ok;

($ok, $errors, $debug) = $client->request('GET', '/');
die "Request failed: @$errors" unless $ok;

my ($code, $state, $headers, $body) = $client->response();
print "Response: $code $state\n";
print $body;

With proxy:

my ($ok, $errors, $debug) = $client->connect(
    'api.example.com', 443,
    'proxy.corp.com:8080', 'user:pass'
);

With certificate pinning:

my $client = LightTCP::SSLclient->new(dir => './certs');
my ($ok, $errors, $debug) = $client->connect('example.com', 443);

# First connection - save fingerprint
$client->fingerprint_save('./certs', 'example.com', 443, $fp, 1);

# Subsequent connections will auto-verify
$client->fingerprint_save('./certs', 'example.com', 443, $fp, 0);