Skip to content

Instantly share code, notes, and snippets.

@afresh1 afresh1/HTTP-Tiny-nc.pm
Last active Jun 6, 2019

Embed
What would you like to do?
An monkey patch to let perl's HTTP::Tiny to use the OpenBSD netcat with TLS support to access https sites without installing IO::Socket::SSL and Net::SSLeay.
package HTTP::Tiny::nc;
use strict;
use warnings;
use parent 'HTTP::Tiny';
# Copyright (c) 2019 Andrew Hewus Fresh <afresh1@openbsd.org>
#
# Permission to use, copy, modify, and distribute this software for any
# purpose with or without fee is hereby granted, provided that the above
# copyright notice and this permission notice appear in all copies.
#
# THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
# ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
# WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
# ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
# OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
=head1 NAME
HTTP::Tiny::nc - An HTTP::Tiny extension that uses nc for ssl connections
=head1 SYNOPSIS
use HTTP::Tiny::nc;
my $client = HTTP::Tiny::nc->new;
# or just HTTP::Tiny->new, as it overrides the parent
if ( $client->get("https://www.openbsd.org")->{success} ) {
print "Hurray!"
}
=head1 DESCRIPTION
A small subclass of L<HTTP::Tiny> that overrides things to use
the OpenBSD version of L<nc(1)> to connect to C<https> sites.
=head1 BUGS
I'm sure there are lots of ways this could go bad, but in simple
tests it Just Works.
=cut
use IO::Socket;
use IO::Select;
my $orig_connect; BEGIN {
$orig_connect = \&HTTP::Tiny::Handle::connect
// die "\&HTTP::Tiny::Handle::connect is not defined";
no warnings 'redefine';
*HTTP::Tiny::Handle::connect = \&connect_with_nc;
use warnings 'redefine';
}
sub connect_with_nc {
@_ == 5
|| die( q/Usage: $handle->connect(scheme, host, port, peer)/ . "\n" );
my ( $self, $scheme, $host, $port, $peer ) = @_;
return $orig_connect->(@_) if $scheme ne 'https' or HTTP::Tiny->can_ssl;
my @nc = '/usr/bin/nc';
if ( $scheme eq 'https' ) {
push @nc, '-c';
}
elsif ( $scheme ne 'http' ) {
die(qq/Unsupported URL scheme '$scheme'\n/);
}
# TODO: Support more SSL_options and other config.
push @nc, $host, $port;
my ( $parent, $child )
= IO::Socket->socketpair( AF_UNIX, SOCK_STREAM, PF_UNSPEC )
or die "socketpair: $!";
my $pid = fork // die "Unable to fork: $!";
if ( !$pid ) {
$parent->close or die "Unable to close parent socket: $!";
open STDIN, '<&', $child or die "unable to dup to STDIN: $!";
open STDOUT, '>&', $child or die "Unable to dup to STDOUT: $!";
exec @nc or die "Unable to exec nc: $!";
}
$child->close or die "Unable to close child socket: $!";
$self->{fh} = $parent;
binmode($self->{fh})
or die(qq/Could not binmode() socket: '$!'\n/);
$self->{scheme} = $scheme;
$self->{host} = $host;
$self->{peer} = $peer;
$self->{port} = $port;
$self->{pid} = $$;
return $self;
}
1;
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
You can’t perform that action at this time.