File Coverage

blib/lib/IO/Stream/Proxy/HTTPS.pm
Criterion Covered Total %
statement 13 15 86.6
branch n/a
condition n/a
subroutine 5 5 100.0
pod n/a
total 18 20 90.0


line stmt bran cond sub pod time code
1             package IO::Stream::Proxy::HTTPS;
2              
3 2     2   32288 use warnings;
  2         5  
  2         72  
4 2     2   11 use strict;
  2         4  
  2         71  
5 2     2   10 use Carp;
  2         9  
  2         173  
6              
7 2     2   1901 use version; our $VERSION = qv('1.0.5'); # update POD & Changes & README
  2         4786  
  2         14  
8              
9             # update DEPENDENCIES in POD & Makefile.PL & README
10 2     2   1089 use IO::Stream::const;
  0            
  0            
11             use MIME::Base64;
12             use Scalar::Util qw( weaken );
13              
14             use constant HTTP_OK => 200;
15              
16             sub new {
17             my ($class, $opt) = @_;
18             croak '{host}+{port} required'
19             if !defined $opt->{host}
20             || !defined $opt->{port}
21             ;
22             croak '{user}+{pass} required'
23             if $opt->{user} xor $opt->{pass};
24             my $self = bless {
25             host => undef,
26             port => undef,
27             user => undef,
28             pass => undef,
29             %{$opt},
30             out_buf => q{}, # modified on: OUT
31             out_pos => undef, # modified on: OUT
32             out_bytes => 0, # modified on: OUT
33             in_buf => q{}, # modified on: IN
34             in_bytes => 0, # modified on: IN
35             ip => undef, # modified on: RESOLVED
36             is_eof => undef, # modified on: EOF
37             _want_write => undef,
38             }, $class;
39             return $self;
40             }
41              
42             sub PREPARE {
43             my ($self, $fh, $host, $port) = @_;
44             croak '{fh} already connected'
45             if !defined $host;
46             $self->{out_buf} = "CONNECT ${host}:${port} HTTP/1.0\r\n";
47             if (defined $self->{user}) {
48             $self->{out_buf} .= 'Proxy-Authorization: Basic '
49             . encode_base64($self->{user}.q{:}.$self->{pass}, q{})
50             . "\r\n"
51             ;
52             }
53             $self->{out_buf} .= "\r\n";
54             $self->{_slave}->PREPARE($fh, $self->{host}, $self->{port});
55             $self->{_slave}->WRITE();
56             return;
57             }
58              
59             sub WRITE {
60             my ($self) = @_;
61             $self->{_want_write} = 1;
62             return;
63             }
64              
65             sub EVENT {
66             my ($self, $e, $err) = @_;
67             my $m = $self->{_master};
68             if ($err) {
69             $m->EVENT(0, $err);
70             }
71             if ($e & IN) {
72             if ($self->{in_buf} =~ s{\A(HTTP/\d[.]\d\s(\d+)\s.*?)\r?\n\r?\n}{}xms) {
73             my ($reply, $status) = ($1, $2);
74             if ($status == HTTP_OK) {
75             $e = CONNECTED;
76             if (my $l = length $self->{in_buf}) {
77             $e |= IN;
78             $m->{in_buf} .= $self->{in_buf};
79             $m->{in_bytes} += $l;
80             }
81             $m->EVENT($e);
82             $self->{_slave}->{_master} = $m;
83             weaken($self->{_slave}->{_master});
84             $m->{_slave} = $self->{_slave};
85             if ($self->{_want_write}) {
86             $self->{_slave}->WRITE();
87             }
88             }
89             else {
90             $m->EVENT(0, 'https proxy: '.$reply);
91             }
92             }
93             }
94             if ($e & EOF) {
95             $m->{is_eof} = $self->{is_eof};
96             $m->EVENT(0, 'https proxy: unexpected EOF');
97             }
98             return;
99             }
100              
101              
102             1; # Magic true value required at end of module
103             __END__
104              
105             =head1 NAME
106              
107             IO::Stream::Proxy::HTTPS - HTTPS proxy plugin for IO::Stream
108              
109              
110             =head1 VERSION
111              
112             This document describes IO::Stream::Proxy::HTTPS version 1.0.5
113              
114              
115             =head1 SYNOPSIS
116              
117             use IO::Stream;
118             use IO::Stream::Proxy::HTTPS;
119              
120             IO::Stream->new({
121             ...
122             plugin => [
123             ...
124             proxy => IO::Stream::Proxy::HTTPS->new({
125             host => 'my.proxy.com',
126             port => 3128,
127             user => 'me',
128             pass => 'mypass',
129             }),
130             ...
131             ],
132             });
133              
134              
135             =head1 DESCRIPTION
136              
137             This module is plugin for L<IO::Stream> which allow you to route stream
138             through HTTPS (also called CONNECT) proxy.
139              
140             You may use several IO::Stream::Proxy::HTTPS plugins for single IO::Stream
141             object, effectively creating proxy chain (first proxy plugin will define
142             last proxy in a chain).
143              
144             =head2 EVENTS
145              
146             When using this plugin event RESOLVED will never be delivered to user because
147             target {host} which user provide to IO::Stream will never be resolved on
148             user side (it will be resolved by HTTPS proxy).
149              
150             Event CONNECTED will be generated after HTTPS proxy successfully connects to
151             target {host} (and not when socket will connect to HTTPS proxy itself).
152              
153             =head1 INTERFACE
154              
155             =over
156              
157             =item new({ host=>$host, port=>$port })
158              
159             =item new({ host=>$host, port=>$port, user=>$user, pass=>$pass })
160              
161             Connect to proxy $host:$port, optionally using basic authorization.
162              
163             =back
164              
165              
166             =head1 DIAGNOSTICS
167              
168             =over
169              
170             =item C<< {host}+{port} required >>
171              
172             You must provide both {host} and {port} to IO::Stream::Proxy::HTTPS->new().
173              
174             =item C<< {user}+{pass} required >>
175              
176             You have provided either {user} or {pass} to IO::Stream::Proxy::HTTPS->new()
177             while you have to provide either both or none of them.
178              
179             =item C<< {fh} already connected >>
180              
181             You have provided {fh} to IO::Stream->new(), but this is not supported by
182             this plugin. Either don't use this plugin or provide {host}+{port} to
183             IO::Stream->new() instead.
184              
185             =back
186              
187              
188             =head1 CONFIGURATION AND ENVIRONMENT
189              
190             IO::Stream::Proxy::HTTPS requires no configuration files or environment variables.
191              
192              
193             =head1 DEPENDENCIES
194              
195             L<IO::Stream>.
196              
197              
198             =head1 INCOMPATIBILITIES
199              
200             None reported.
201              
202              
203             =head1 BUGS AND LIMITATIONS
204              
205             No bugs have been reported.
206              
207             Please report any bugs or feature requests to author, or
208             C<bug-io-stream-proxy-https@rt.cpan.org>, or through the web interface at
209             L<http://rt.cpan.org>.
210              
211              
212             =head1 AUTHOR
213              
214             Alex Efros C<< <powerman-asdf@ya.ru> >>
215              
216              
217             =head1 LICENSE AND COPYRIGHT
218              
219             Copyright (c) 2008, Alex Efros C<< <powerman-asdf@ya.ru> >>. All rights reserved.
220              
221             This module is free software; you can redistribute it and/or
222             modify it under the same terms as Perl itself. See L<perlartistic>.
223              
224              
225             =head1 DISCLAIMER OF WARRANTY
226              
227             BECAUSE THIS SOFTWARE IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
228             FOR THE SOFTWARE, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN
229             OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
230             PROVIDE THE SOFTWARE "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER
231             EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
232             WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE
233             ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE SOFTWARE IS WITH
234             YOU. SHOULD THE SOFTWARE PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL
235             NECESSARY SERVICING, REPAIR, OR CORRECTION.
236              
237             IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
238             WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
239             REDISTRIBUTE THE SOFTWARE AS PERMITTED BY THE ABOVE LICENCE, BE
240             LIABLE TO YOU FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL,
241             OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE
242             THE SOFTWARE (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING
243             RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A
244             FAILURE OF THE SOFTWARE TO OPERATE WITH ANY OTHER SOFTWARE), EVEN IF
245             SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF
246             SUCH DAMAGES.