2015-12-17 2 views
2

Я сделал простой HTTP прокси-сервер, это отлично работает, но не быстро, потому что в функции handle_request, я используюPerl: асинхронный HTTP прокси через Mojolicious

my $tx = $ua->start(Mojo::Transaction::HTTP->new(req=>$request)); 

сделать запрос, он блокирует.

Я пытаюсь использовать функцию обратного вызова, как:

$ua->start(Mojo::Transaction::HTTP->new(req=>$request))=>sub{ ... } 

сделать это без блокировки, а затем получил ошибку:

'error' => { 'message' => 'Premature connection close'} 

Я предполагаю, что это потому, что функция handle_request возвращение немедленно, его не дождался завершения обратного вызова. Если я использую семафор, чтобы ждать обратного вызова, это значит, что он снова блокирует.

#!/usr/bin/perl 
use strict; 
use warnings; 
use utf8; 
use Mojo::IOLoop::Server; 
use Mojo::UserAgent; 
use Mojo::Message::Response; 
use Mojo::Message::Request; 
use Mojo::Transaction::HTTP; 
use Data::Dumper; 

binmode STDOUT, ":encoding(UTF-8)"; 

my %buffer; 

Mojo::IOLoop->server({port => 3128} => sub { 
    my ($loop, $stream, $client) = @_; 

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

      my $buffer = $buffer{$client}{read_buffer} .= $chunk; 

      if ($buffer =~ /^GET\s+|POST\s+|HEAD\s+(.*)\r\n\r\n$/i) { 
       $buffer{$client}{read_buffer} = ''; 
       &handle_request($client,$stream,$buffer); 
      } 

      elsif ($buffer =~ /^CONNECT\s+(.*)\r\n\r\n$/i) { 
       $buffer{$client}{read_buffer} = ''; 
       &handle_connect($stream,$buffer); 
      } 

      elsif($buffer{$client}{connection}) 
      { 
       $buffer{$client}{read_buffer} = ''; 
       Mojo::IOLoop->stream($buffer{$client}{connection})->write($chunk); 
      } 

      if(length($buffer)>= 20 *1024 * 1024) { 
       delete $buffer{$client}; 
       Mojo::IOLoop->remove($client); 
       return; 
      } 
     }); 
}); 

sub handle_request{ 

    my($client,$stream,$chunk) = @_; 

    my $request = Mojo::Message::Request->new; 
    $request = $request->parse($chunk); 

    my $ua = Mojo::UserAgent->new; 
    my $tx = $ua->start(Mojo::Transaction::HTTP->new(req=>$request)); 

    $stream->write($tx->res->to_string); 
} 

sub handle_connect{ 
    my ($stream, $chunk) = @_; 
    my $request = Mojo::Message::Request->new; 
    my $ua = Mojo::UserAgent->new; 

    $request = $request->parse($chunk); 

    print Dumper($request); 
} 

Mojo::IOLoop->start; 

Надеемся получить некоторые предложения.

ответ

2

У вас есть 2 проблемы:

  1. Вы пытаетесь вызвать вариант неблокирования из $ua->start, когда ваш код блокировки имеют стиль. Функция handle_request должна иметь обратный вызов в качестве параметра. Если у вас есть цепочка обратного вызова, то лучшим способом реализовать его является использование Mojo::IOLoop::Delay.
  2. Когда вы создаете переменную $ ua в неблокирующем стиле в sub handle_request, тогда ваша переменная будет уничтожена сборщиком мусора, потому что сначала выполнить exit sub handle_request и $ ua уничтожен, потому что это локальная переменная, а затем получить ответ от $ ua. Таким образом, вы получаете Premature connection close. Вам нужно сохранить экземпляр $ ua в другом месте, чтобы предотвратить такую ​​ошибку.

Обновление.
I write плохой вариант прокси-сервера http/https, который работает только через метод CONNECT и имеет ошибку с неполным первым HTTP-сообщением.

Обновление.
Я добавляю еще один пример прокси-сервера http/https, который правильно считывает первое http-сообщение и работает не только с помощью метода CONNECT.

Обновление.
О, автор Mojo написал example https proxy

+0

Большое спасибо. Я храню $ ua в хеш-таблице, теперь все в порядке. для первой проблемы я не знаю, что я должен делать. 'my $ ua = Mojo :: UserAgent-> new; $ buffer {$ client} {ua} = $ ua; my $ tx = $ buffer {$ client} {ua} -> start (Mojo :: Transaction :: HTTP-> new (req => $ request) => sub {my ($ ua, $ tx) = @_ ; $ stream-> write ($ tx-> res-> to_string);}}); ' –

+0

Я пишу пример. – Logioniz

Смежные вопросы