取势 明道 优术

作者为 扶 凯 发表

IT•技术

很久以前使用 Plack 写过一个很土但能工作的 HTTP 代理. 现在使用 Mojo 也实现了一个, 比原来那个先进一些的 HTTP 代理…其实这是一个 SOCK 的代理, 这是异步事件驱动的, 性能会比原来的好, 并且每次代码取到一部分数据就能转发给客户端, 不象以前那个需要给整个 body 取过来, 然后才返回, 这样节约内存多了.
这个程序, 其实大部分是抄了 Mojo 原作者的一个程序小修改过来, 原作者使用 HTTP 的 CONNECT 协议来代理的 TLS 的 HTTPS 的协议.

use Mojo::Base -strict;
use Mojo::IOLoop;
use Smart::Comments;
use Mojo::Headers;

# Minimal proxy server
my %buffer;
Mojo::IOLoop->server(
    {port => 3000} => sub {
    my ($loop, $stream, $client) = @_;

    # Connection to client
    $stream->on(
        read => sub {
            my ($stream, $chunk) = @_;

            # Write chunk from client to remote server
            my $server = $buffer{$client}{connection};
            return Mojo::IOLoop->stream($server)->write($chunk) if $server;

            my $buffer = $buffer{$client}{client} .= $chunk;
            if ($buffer =~ /\x0d?\x0a\x0d?\x0a$/) {
                $buffer{$client}{client} = '';
                my $headers = Mojo::Headers->new;
                $headers->parse($buffer);
                my $address = $headers->host;
                my $port = 80;

                # Connection to remote server
                $buffer{$client}{connection} = Mojo::IOLoop->client(
                    {address => $address, port => $port} => sub {
                        my ($loop, $err, $stream) = @_;

                        # Connection to server failed
                        if ($err) {
                            say "Connection error for $address:$port: $err";
                            Mojo::IOLoop->remove($client);
                            return delete $buffer{$client};
                        }

                        # write http header
                        $stream->write($buffer);

                        # Start forwarding data in both directions
                        say "Forwarding to $address:$port";
                        # Remote server to client
                        $stream->on(
                            read => sub {
                                my ($stream, $chunk) = @_;
                                Mojo::IOLoop->stream($client)->write($chunk);
                            }
                        );

                        # Server closed connection
                        $stream->on(
                            close => sub {
                                Mojo::IOLoop->remove($client);
                                delete $buffer{$client};
                            }
                        );
                    }
                );
            # Invalid request from client
            } else { 
                Mojo::IOLoop->remove($client) 
            }
        }
    );

    # Client closed connection
    $stream->on(
        close => sub {
            my $buffer = delete $buffer{$client}; 
            Mojo::IOLoop->remove($buffer->{connection}) if $buffer->{connection}; 
        }
    );
    }
);

print <<'EOF';
Starting CONNECT proxy on port 3000.
For testing use something like "HTTP_PROXY=http://127.0.0.1:3000".
EOF

Mojo::IOLoop->start;

1;

下一个看看有没有空基于这个做个 SOCK4 或者 5 的代理, 并且传送的内容加密下来, 来进行"科学上网".

来了就留个评论吧! 2个评论



    Matthew 2015年07月30日 的 22:21

    支持做一个加密的!!!

    Perfi 2015年08月11日 的 21:56

    支持做一个https代理的