AnyEvent

 view release on metacpan or  search on metacpan

lib/AnyEvent/Intro.pod  view on Meta::CPAN

register a callback:

   $f1->cb (sub {
      my $response = shift->recv;
      # ...
   });

The callback will be invoked only when C<send> is called. In fact,
instead of returning a condition variable you could also pass a third
parameter to your finger function, the callback to invoke with the
response:

   sub finger($$$) {
      my ($user, $host, $cb) = @_;

How you implement it is a matter of taste - if you expect your function to
be used mainly in an event-based program you would normally prefer to pass
a callback directly. If you write a module and expect your users to use
it "synchronously" often (for example, a simple http-get script would not
really care much for events), then you would use a condition variable and
tell them "simply C<< ->recv >> the data".

=head3 Problems with the implementation and how to fix them

To make this example more real-world-ready, we would not only implement
some write buffering (for the paranoid, or maybe denial-of-service aware
security expert), but we would also have to handle timeouts and maybe
protocol errors.

Doing this quickly gets unwieldy, which is why we introduce
L<AnyEvent::Handle> in the next section, which takes care of all these
details for you and lets you concentrate on the actual protocol.


=head2 Implementing simple HTTP and HTTPS GET requests with AnyEvent::Handle

The L<AnyEvent::Handle> module has been hyped quite a bit in this document
so far, so let's see what it really offers.

As finger is such a simple protocol, let's try something slightly more
complicated: HTTP/1.0.

An HTTP GET request works by sending a single request line that indicates
what you want the server to do and the URI you want to act it on, followed
by as many "header" lines (C<Header: data>, same as e-mail headers) as
required for the request, followed by an empty line.

The response is formatted very similarly, first a line with the response
status, then again as many header lines as required, then an empty line,
followed by any data that the server might send.

Again, let's try it out with C<telnet> (I condensed the output a bit - if
you want to see the full response, do it yourself).

   # telnet www.google.com 80
   Trying 209.85.135.99...
   Connected to www.google.com (209.85.135.99).
   Escape character is '^]'.
   GET /test HTTP/1.0

   HTTP/1.0 404 Not Found
   Date: Mon, 02 Jun 2008 07:05:54 GMT
   Content-Type: text/html; charset=UTF-8

   <html><head>
   [...]
   Connection closed by foreign host.

The C<GET ...> and the empty line were entered manually, the rest of the
telnet output is google's response, in this case a C<404 not found> one.

So, here is how you would do it with C<AnyEvent::Handle>:

   sub http_get {
      my ($host, $uri, $cb) = @_;

      # store results here
      my ($response, $header, $body);

      my $handle; $handle = new AnyEvent::Handle
         connect  => [$host => 'http'],
         on_error => sub {
            $cb->("HTTP/1.0 500 $!");
            $handle->destroy; # explicitly destroy handle
         },
         on_eof   => sub {
            $cb->($response, $header, $body);
            $handle->destroy; # explicitly destroy handle
         };

      $handle->push_write ("GET $uri HTTP/1.0\015\012\015\012");

      # now fetch response status line
      $handle->push_read (line => sub {
         my ($handle, $line) = @_;
         $response = $line;
      });

      # then the headers
      $handle->push_read (line => "\015\012\015\012", sub {
         my ($handle, $line) = @_;
         $header = $line;
      });

      # and finally handle any remaining data as body
      $handle->on_read (sub {
         $body .= $_[0]->rbuf;
         $_[0]->rbuf = "";
      });
   }

And now let's go through it step by step. First, as usual, the overall
C<http_get> function structure:

   sub http_get {
      my ($host, $uri, $cb) = @_;

      # store results here
      my ($response, $header, $body);

      my $handle; $handle = new AnyEvent::Handle
         ... create handle object

      ... push data to write

      ... push what to expect to read queue
   }

Unlike in the finger example, this time the caller has to pass a callback
to C<http_get>. Also, instead of passing a URL as one would expect, the



( run in 0.968 second using v1.01-cache-2.11-cpan-39bf76dae61 )