ViewVC Help
View File | Revision Log | Show Annotations | Download File
/cvs/AnyEvent-HTTP/HTTP.pm
(Generate patch)

Comparing AnyEvent-HTTP/HTTP.pm (file contents):
Revision 1.63 by root, Thu Dec 30 04:31:55 2010 UTC vs.
Revision 1.64 by root, Fri Dec 31 02:53:29 2010 UTC

100second argument. 100second argument.
101 101
102All the headers in that hash are lowercased. In addition to the response 102All the headers in that hash are lowercased. In addition to the response
103headers, the "pseudo-headers" (uppercase to avoid clashing with possible 103headers, the "pseudo-headers" (uppercase to avoid clashing with possible
104response headers) C<HTTPVersion>, C<Status> and C<Reason> contain the 104response headers) C<HTTPVersion>, C<Status> and C<Reason> contain the
105three parts of the HTTP Status-Line of the same name. 105three parts of the HTTP Status-Line of the same name. If an error occurs
106during the body phase of a request, then the original C<Status> and
107C<Reason> values from the header are available as C<OrigStatus> and
108C<OrigReason>.
106 109
107The pseudo-header C<URL> contains the actual URL (which can differ from 110The pseudo-header C<URL> contains the actual URL (which can differ from
108the requested URL when following redirects - for example, you might get 111the requested URL when following redirects - for example, you might get
109an error that your URL scheme is not supported even though your URL is a 112an error that your URL scheme is not supported even though your URL is a
110valid http URL because it redirected to an ftp URL, in which case you can 113valid http URL because it redirected to an ftp URL, in which case you can
377 my @pseudo = (URL => $url); 380 my @pseudo = (URL => $url);
378 push @pseudo, Redirect => delete $arg{Redirect} if exists $arg{Redirect}; 381 push @pseudo, Redirect => delete $arg{Redirect} if exists $arg{Redirect};
379 382
380 my $recurse = exists $arg{recurse} ? delete $arg{recurse} : $MAX_RECURSE; 383 my $recurse = exists $arg{recurse} ? delete $arg{recurse} : $MAX_RECURSE;
381 384
382 return $cb->(undef, { Status => 599, Reason => "Too many redirections", @pseudo }) 385 return $cb->(undef, { @pseudo, Status => 599, Reason => "Too many redirections" })
383 if $recurse < 0; 386 if $recurse < 0;
384 387
385 my $proxy = $arg{proxy} || $PROXY; 388 my $proxy = $arg{proxy} || $PROXY;
386 my $timeout = $arg{timeout} || $TIMEOUT; 389 my $timeout = $arg{timeout} || $TIMEOUT;
387 390
390 393
391 $uscheme = lc $uscheme; 394 $uscheme = lc $uscheme;
392 395
393 my $uport = $uscheme eq "http" ? 80 396 my $uport = $uscheme eq "http" ? 80
394 : $uscheme eq "https" ? 443 397 : $uscheme eq "https" ? 443
395 : return $cb->(undef, { Status => 599, Reason => "Only http and https URL schemes supported", @pseudo }); 398 : return $cb->(undef, { @pseudo, Status => 599, Reason => "Only http and https URL schemes supported" });
396 399
397 $uauthority =~ /^(?: .*\@ )? ([^\@:]+) (?: : (\d+) )?$/x 400 $uauthority =~ /^(?: .*\@ )? ([^\@:]+) (?: : (\d+) )?$/x
398 or return $cb->(undef, { Status => 599, Reason => "Unparsable URL", @pseudo }); 401 or return $cb->(undef, { @pseudo, Status => 599, Reason => "Unparsable URL" });
399 402
400 my $uhost = $1; 403 my $uhost = $1;
401 $uport = $2 if defined $2; 404 $uport = $2 if defined $2;
402 405
403 $hdr{host} = defined $2 ? "$uhost:$2" : "$uhost" 406 $hdr{host} = defined $2 ? "$uhost:$2" : "$uhost"
465 _get_slot $uhost, sub { 468 _get_slot $uhost, sub {
466 $state{slot_guard} = shift; 469 $state{slot_guard} = shift;
467 470
468 return unless $state{connect_guard}; 471 return unless $state{connect_guard};
469 472
470 my $tcp_connect = $arg{tcp_connect} 473 my $connect_cb = sub {
471 || do { require AnyEvent::Socket; \&AnyEvent::Socket::tcp_connect };
472
473 $state{connect_guard} = $tcp_connect->(
474 $rhost,
475 $rport,
476 sub {
477 $state{fh} = shift 474 $state{fh} = shift
478 or do { 475 or do {
479 my $err = "$!"; 476 my $err = "$!";
480 %state = (); 477 %state = ();
481 return $cb->(undef, { Status => 599, Reason => $err, @pseudo }); 478 return $cb->(undef, { @pseudo, Status => 599, Reason => $err });
482 }; 479 };
483 480
484 pop; # free memory, save a tree 481 pop; # free memory, save a tree
485 482
486 return unless delete $state{connect_guard}; 483 return unless delete $state{connect_guard};
487 484
488 # get handle 485 # get handle
489 $state{handle} = new AnyEvent::Handle 486 $state{handle} = new AnyEvent::Handle
490 fh => $state{fh}, 487 fh => $state{fh},
491 peername => $rhost, 488 peername => $rhost,
492 tls_ctx => $arg{tls_ctx}, 489 tls_ctx => $arg{tls_ctx},
493 # these need to be reconfigured on keepalive handles 490 # these need to be reconfigured on keepalive handles
494 timeout => $timeout, 491 timeout => $timeout,
495 on_error => sub { 492 on_error => sub {
496 %state = (); 493 %state = ();
497 $cb->(undef, { Status => 599, Reason => $_[2], @pseudo }); 494 $cb->(undef, { @pseudo, Status => 599, Reason => $_[2] });
498 }, 495 },
499 on_eof => sub { 496 on_eof => sub {
500 %state = (); 497 %state = ();
501 $cb->(undef, { Status => 599, Reason => "Unexpected end-of-file", @pseudo }); 498 $cb->(undef, { @pseudo, Status => 599, Reason => "Unexpected end-of-file" });
502 }, 499 },
503 ; 500 ;
504 501
505 # limit the number of persistent connections 502 # limit the number of persistent connections
506 # keepalive not yet supported 503 # keepalive not yet supported
507# if ($KA_COUNT{$_[1]} < $MAX_PERSISTENT_PER_HOST) { 504# if ($KA_COUNT{$_[1]} < $MAX_PERSISTENT_PER_HOST) {
508# ++$KA_COUNT{$_[1]}; 505# ++$KA_COUNT{$_[1]};
509# $state{handle}{ka_count_guard} = AnyEvent::Util::guard { 506# $state{handle}{ka_count_guard} = AnyEvent::Util::guard {
510# --$KA_COUNT{$_[1]} 507# --$KA_COUNT{$_[1]}
511# }; 508# };
512# $hdr{connection} = "keep-alive"; 509# $hdr{connection} = "keep-alive";
513# } else { 510# } else {
514 delete $hdr{connection}; 511 delete $hdr{connection};
515# } 512# }
516 513
517 $state{handle}->starttls ("connect") if $rscheme eq "https"; 514 $state{handle}->starttls ("connect") if $rscheme eq "https";
518 515
519 # handle actual, non-tunneled, request 516 # handle actual, non-tunneled, request
520 my $handle_actual_request = sub { 517 my $handle_actual_request = sub {
521 $state{handle}->starttls ("connect") if $uscheme eq "https" && !exists $state{handle}{tls}; 518 $state{handle}->starttls ("connect") if $uscheme eq "https" && !exists $state{handle}{tls};
522 519
523 # send request 520 # send request
524 $state{handle}->push_write ( 521 $state{handle}->push_write (
525 "$method $rpath HTTP/1.0\015\012" 522 "$method $rpath HTTP/1.0\015\012"
526 . (join "", map "\u$_: $hdr{$_}\015\012", grep defined $hdr{$_}, keys %hdr) 523 . (join "", map "\u$_: $hdr{$_}\015\012", grep defined $hdr{$_}, keys %hdr)
527 . "\015\012" 524 . "\015\012"
528 . (delete $arg{body}) 525 . (delete $arg{body})
529 ); 526 );
530 527
531 # return if error occured during push_write() 528 # return if error occured during push_write()
532 return unless %state; 529 return unless %state;
533 530
534 %hdr = (); # reduce memory usage, save a kitten, also make it possible to re-use 531 %hdr = (); # reduce memory usage, save a kitten, also make it possible to re-use
535 532
536 # status line and headers 533 # status line and headers
537 $state{handle}->push_read (line => $qr_nlnl, sub { 534 $state{handle}->push_read (line => $qr_nlnl, sub {
535 my $keepalive = pop;
536
538 for ("$_[1]") { 537 for ("$_[1]") {
539 y/\015//d; # weed out any \015, as they show up in the weirdest of places. 538 y/\015//d; # weed out any \015, as they show up in the weirdest of places.
540 539
541 /^HTTP\/([0-9\.]+) \s+ ([0-9]{3}) (?: \s+ ([^\015\012]*) )? \015?\012/igxc 540 /^HTTP\/([0-9\.]+) \s+ ([0-9]{3}) (?: \s+ ([^\015\012]*) )? \015?\012/igxc
542 or return (%state = (), $cb->(undef, { Status => 599, Reason => "Invalid server response", @pseudo })); 541 or return (%state = (), $cb->(undef, { @pseudo, Status => 599, Reason => "Invalid server response" }));
543 542
544 push @pseudo, 543 push @pseudo,
545 HTTPVersion => $1, 544 HTTPVersion => $1,
546 Status => $2, 545 Status => $2,
547 Reason => $3, 546 Reason => $3,
548 ; 547 ;
549 548
550 # things seen, not parsed: 549 # things seen, not parsed:
551 # p3pP="NON CUR OTPi OUR NOR UNI" 550 # p3pP="NON CUR OTPi OUR NOR UNI"
552 551
553 $hdr{lc $1} .= ",$2" 552 $hdr{lc $1} .= ",$2"
554 while /\G 553 while /\G
555 ([^:\000-\037]*): 554 ([^:\000-\037]*):
556 [\011\040]* 555 [\011\040]*
557 ((?: [^\012]+ | \012[\011\040] )*) 556 ((?: [^\012]+ | \012[\011\040] )*)
558 \012 557 \012
559 /gxc; 558 /gxc;
560 559
561 /\G$/ 560 /\G$/
562 or return (%state = (), $cb->(undef, { Status => 599, Reason => "Garbled response headers", @pseudo })); 561 or return (%state = (), $cb->(undef, { @pseudo, Status => 599, Reason => "Garbled response headers" }));
562 }
563
564 # remove the "," prefix we added to all headers above
565 substr $_, 0, 1, ""
566 for values %hdr;
567
568 # patch in all pseudo headers
569 %hdr = (%hdr, @pseudo);
570
571 # redirect handling
572 # microsoft and other shitheads don't give a shit for following standards,
573 # try to support some common forms of broken Location headers.
574 if ($hdr{location} !~ /^(?: $ | [^:\/?\#]+ : )/x) {
575 $hdr{location} =~ s/^\.\/+//;
576
577 my $url = "$rscheme://$uhost:$uport";
578
579 unless ($hdr{location} =~ s/^\///) {
580 $url .= $upath;
581 $url =~ s/\/[^\/]*$//;
563 } 582 }
564 583
565 # remove the "," prefix we added to all headers above
566 substr $_, 0, 1, ""
567 for values %hdr;
568
569 # patch in all pseudo headers
570 %hdr = (%hdr, @pseudo);
571
572 # redirect handling
573 # microsoft and other shitheads don't give a shit for following standards,
574 # try to support some common forms of broken Location headers.
575 if ($hdr{location} !~ /^(?: $ | [^:\/?\#]+ : )/x) {
576 $hdr{location} =~ s/^\.\/+//;
577
578 my $url = "$rscheme://$uhost:$uport";
579
580 unless ($hdr{location} =~ s/^\///) {
581 $url .= $upath;
582 $url =~ s/\/[^\/]*$//;
583 }
584
585 $hdr{location} = "$url/$hdr{location}"; 584 $hdr{location} = "$url/$hdr{location}";
585 }
586
587 my $redirect;
588
589 if ($recurse) {
590 my $status = $hdr{Status};
591
592 # industry standard is to redirect POST as GET for
593 # 301, 302 and 303, in contrast to http/1.0 and 1.1.
594 # also, the UA should ask the user for 301 and 307 and POST,
595 # industry standard seems to be to simply follow.
596 # we go with the industry standard.
597 if ($status == 301 or $status == 302 or $status == 303) {
598 # HTTP/1.1 is unclear on how to mutate the method
599 $method = "GET" unless $method eq "HEAD";
600 $redirect = 1;
601 } elsif ($status == 307) {
602 $redirect = 1;
586 } 603 }
604 }
587 605
588 my $redirect; 606 my $finish = sub { # ($data, $err_status, $err_reason[, $keepalive])
607 $state{handle}->destroy if $state{handle};
608 %state = ();
589 609
610 if (defined $_[1]) {
611 $hdr{OrigStatus} = $hdr{Status}; $hdr{Status} = $_[1];
612 $hdr{OrigReason} = $hdr{Reason}; $hdr{Reason} = $_[2];
613 }
614
615 # set-cookie processing
590 if ($recurse) { 616 if ($arg{cookie_jar}) {
591 my $status = $hdr{Status}; 617 for ($hdr{"set-cookie"}) {
618 # parse NAME=VALUE
619 my @kv;
592 620
593 # industry standard is to redirect POST as GET for 621 while (/\G\s* ([^=;,[:space:]]+) \s*=\s* (?: "((?:[^\\"]+|\\.)*)" | ([^=;,[:space:]]*) )/gcxs) {
594 # 301, 302 and 303, in contrast to http/1.0 and 1.1.
595 # also, the UA should ask the user for 301 and 307 and POST,
596 # industry standard seems to be to simply follow.
597 # we go with the industry standard.
598 if ($status == 301 or $status == 302 or $status == 303) {
599 # HTTP/1.1 is unclear on how to mutate the method
600 $method = "GET" unless $method eq "HEAD";
601 $redirect = 1; 622 my $name = $1;
602 } elsif ($status == 307) { 623 my $value = $3;
624
625 unless ($value) {
626 $value = $2;
627 $value =~ s/\\(.)/$1/gs;
628 }
629
630 push @kv, $name => $value;
631
632 last unless /\G\s*;/gc;
633 }
634
635 last unless @kv;
636
637 my $name = shift @kv;
638 my %kv = (value => shift @kv, @kv);
639
640 my $cdom;
641 my $cpath = (delete $kv{path}) || "/";
642
643 if (exists $kv{domain}) {
644 $cdom = delete $kv{domain};
645
646 $cdom =~ s/^\.?/./; # make sure it starts with a "."
647
648 next if $cdom =~ /\.$/;
649
650 # this is not rfc-like and not netscape-like. go figure.
651 my $ndots = $cdom =~ y/.//;
652 next if $ndots < ($cdom =~ /\.[^.][^.]\.[^.][^.]$/ ? 3 : 2);
653 } else {
654 $cdom = $uhost;
655 }
656
603 $redirect = 1; 657 # store it
658 $arg{cookie_jar}{version} = 1;
659 $arg{cookie_jar}{$cdom}{$cpath}{$name} = \%kv;
660
661 redo if /\G\s*,/gc;
604 } 662 }
605 } 663 }
606 664
607 my $finish = sub { 665 if ($redirect && exists $hdr{location}) {
608 $state{handle}->destroy if $state{handle}; 666 # we ignore any errors, as it is very common to receive
609 %state = (); 667 # Content-Length != 0 but no actual body
610 668 # we also access %hdr, as $_[1] might be an erro
611 # set-cookie processing 669 http_request (
612 if ($arg{cookie_jar}) { 670 $method => $hdr{location},
613 for ($_[1]{"set-cookie"}) {
614 # parse NAME=VALUE
615 my @kv;
616
617 while (/\G\s* ([^=;,[:space:]]+) \s*=\s* (?: "((?:[^\\"]+|\\.)*)" | ([^=;,[:space:]]*) )/gcxs) {
618 my $name = $1;
619 my $value = $3;
620
621 unless ($value) {
622 $value = $2;
623 $value =~ s/\\(.)/$1/gs;
624 } 671 %arg,
672 recurse => $recurse - 1,
673 Redirect => [$_[0], \%hdr],
674 $cb);
675 } else {
676 $cb->($_[0], \%hdr);
677 }
678 };
625 679
626 push @kv, $name => $value; 680 my $len = $hdr{"content-length"};
627 681
628 last unless /\G\s*;/gc; 682 if (!$redirect && $arg{on_header} && !$arg{on_header}(\%hdr)) {
683 $finish->(undef, 598 => "Request cancelled by on_header");
684 } elsif (
685 $hdr{Status} =~ /^(?:1..|204|205|304)$/
686 or $method eq "HEAD"
687 or (defined $len && !$len)
688 ) {
689 # no body
690 $finish->("", undef, undef, 1);
691 } else {
692 # body handling, four different code paths
693 # for want_body_handle, on_body (2x), normal (2x)
694 # we might read too much here, but it does not matter yet (no pipelining)
695 if (!$redirect && $arg{want_body_handle}) {
696 $_[0]->on_eof (undef);
697 $_[0]->on_error (undef);
698 $_[0]->on_read (undef);
699
700 $finish->(delete $state{handle});
701
702 } elsif ($arg{on_body}) {
703 $_[0]->on_error (sub { $finish->(undef, 599 => $_[2]) });
704 if ($len) {
705 $_[0]->on_read (sub {
706 $len -= length $_[0]{rbuf};
707
708 $arg{on_body}(delete $_[0]{rbuf}, \%hdr)
709 or $finish->(undef, 598 => "Request cancelled by on_body");
710
629 } 711 $len > 0
630 712 or $finish->("", undef, undef, 1);
631 last unless @kv;
632
633 my $name = shift @kv;
634 my %kv = (value => shift @kv, @kv);
635
636 my $cdom;
637 my $cpath = (delete $kv{path}) || "/";
638
639 if (exists $kv{domain}) {
640 $cdom = delete $kv{domain};
641
642 $cdom =~ s/^\.?/./; # make sure it starts with a "."
643
644 next if $cdom =~ /\.$/;
645
646 # this is not rfc-like and not netscape-like. go figure.
647 my $ndots = $cdom =~ y/.//;
648 next if $ndots < ($cdom =~ /\.[^.][^.]\.[^.][^.]$/ ? 3 : 2);
649 } else {
650 $cdom = $uhost;
651 }
652
653 # store it
654 $arg{cookie_jar}{version} = 1;
655 $arg{cookie_jar}{$cdom}{$cpath}{$name} = \%kv;
656
657 redo if /\G\s*,/gc;
658 } 713 });
714 } else {
715 $_[0]->on_eof (sub {
716 $finish->("");
717 });
718 $_[0]->on_read (sub {
719 $arg{on_body}(delete $_[0]{rbuf}, \%hdr)
720 or $finish->(undef, 598 => "Request cancelled by on_body");
721 });
659 } 722 }
723 } else {
724 $_[0]->on_eof (undef);
660 725
661 if ($redirect && exists $hdr{location}) { 726 if ($len) {
662 # we ignore any errors, as it is very common to receive 727 $_[0]->on_error (sub { $finish->(undef, 599 => $_[2]) });
663 # Content-Length != 0 but no actual body 728 $_[0]->on_read (sub {
664 # we also access %hdr, as $_[1] might be an erro 729 $finish->((substr delete $_[0]{rbuf}, 0, $len, ""), undef, undef, 1)
665 http_request ( 730 if $len <= length $_[0]{rbuf};
666 $method => $hdr{location},
667 %arg,
668 recurse => $recurse - 1,
669 Redirect => \@_,
670 $cb); 731 });
671 } else { 732 } else {
672 $cb->($_[0], $_[1]);
673 }
674 };
675
676 my $len = $hdr{"content-length"};
677
678 if (!$redirect && $arg{on_header} && !$arg{on_header}(\%hdr)) {
679 $finish->(undef, { Status => 598, Reason => "Request cancelled by on_header", @pseudo });
680 } elsif (
681 $hdr{Status} =~ /^(?:1..|[23]04)$/
682 or $method eq "HEAD"
683 or (defined $len && !$len)
684 ) {
685 # no body
686 $finish->("", \%hdr);
687 } else {
688 # body handling, four different code paths
689 # for want_body_handle, on_body (2x), normal (2x)
690 # we might read too much here, but it does not matter yet (no pers. connections)
691 if (!$redirect && $arg{want_body_handle}) {
692 $_[0]->on_eof (undef);
693 $_[0]->on_error (undef);
694 $_[0]->on_read (undef);
695
696 $finish->(delete $state{handle}, \%hdr);
697
698 } elsif ($arg{on_body}) {
699 $_[0]->on_error (sub { $finish->(undef, { Status => 599, Reason => $_[2], @pseudo }) });
700 if ($len) {
701 $_[0]->on_eof (undef);
702 $_[0]->on_read (sub {
703 $len -= length $_[0]{rbuf};
704
705 $arg{on_body}(delete $_[0]{rbuf}, \%hdr)
706 or $finish->(undef, { Status => 598, Reason => "Request cancelled by on_body", @pseudo });
707
708 $len > 0
709 or $finish->("", \%hdr);
710 });
711 } else {
712 $_[0]->on_eof (sub {
713 $finish->("", \%hdr);
714 });
715 $_[0]->on_read (sub {
716 $arg{on_body}(delete $_[0]{rbuf}, \%hdr)
717 or $finish->(undef, { Status => 598, Reason => "Request cancelled by on_body", @pseudo });
718 });
719 }
720 } else {
721 $_[0]->on_eof (undef);
722
723 if ($len) {
724 $_[0]->on_error (sub { $finish->(undef, { Status => 599, Reason => $_[2], @pseudo }) });
725 $_[0]->on_read (sub {
726 $finish->((substr delete $_[0]{rbuf}, 0, $len, ""), \%hdr)
727 if $len <= length $_[0]{rbuf};
728 });
729 } else {
730 $_[0]->on_error (sub { 733 $_[0]->on_error (sub {
731 ($! == Errno::EPIPE || !$!) 734 ($! == Errno::EPIPE || !$!)
732 ? $finish->(delete $_[0]{rbuf}, \%hdr) 735 ? $finish->(delete $_[0]{rbuf})
733 : $finish->(undef, { Status => 599, Reason => $_[2], @pseudo }); 736 : $finish->(undef, 599 => $_[2]);
734 }); 737 });
735 $_[0]->on_read (sub { }); 738 $_[0]->on_read (sub { });
736 }
737 } 739 }
738 } 740 }
739 }); 741 }
740 }; 742 });
743 };
741 744
742 # now handle proxy-CONNECT method 745 # now handle proxy-CONNECT method
743 if ($proxy && $uscheme eq "https") { 746 if ($proxy && $uscheme eq "https") {
744 # oh dear, we have to wrap it into a connect request 747 # oh dear, we have to wrap it into a connect request
745 748
746 # maybe re-use $uauthority with patched port? 749 # maybe re-use $uauthority with patched port?
747 $state{handle}->push_write ("CONNECT $uhost:$uport HTTP/1.0\015\012Host: $uhost\015\012\015\012"); 750 $state{handle}->push_write ("CONNECT $uhost:$uport HTTP/1.0\015\012Host: $uhost\015\012\015\012");
748 $state{handle}->push_read (line => $qr_nlnl, sub { 751 $state{handle}->push_read (line => $qr_nlnl, sub {
749 $_[1] =~ /^HTTP\/([0-9\.]+) \s+ ([0-9]{3}) (?: \s+ ([^\015\012]*) )?/ix 752 $_[1] =~ /^HTTP\/([0-9\.]+) \s+ ([0-9]{3}) (?: \s+ ([^\015\012]*) )?/ix
750 or return (%state = (), $cb->(undef, { Status => 599, Reason => "Invalid proxy connect response ($_[1])", @pseudo })); 753 or return (%state = (), $cb->(undef, { @pseudo, Status => 599, Reason => "Invalid proxy connect response ($_[1])" }));
751 754
752 if ($2 == 200) { 755 if ($2 == 200) {
753 $rpath = $upath; 756 $rpath = $upath;
754 &$handle_actual_request; 757 &$handle_actual_request;
755 } else { 758 } else {
756 %state = (); 759 %state = ();
757 $cb->(undef, { Status => $2, Reason => $3, @pseudo }); 760 $cb->(undef, { @pseudo, Status => $2, Reason => $3 });
758 }
759 }); 761 }
762 });
760 } else { 763 } else {
761 &$handle_actual_request; 764 &$handle_actual_request;
762 }
763
764 }, 765 }
765 $arg{on_prepare} || sub { $timeout }
766 ); 766 };
767
768 my $tcp_connect = $arg{tcp_connect}
769 || do { require AnyEvent::Socket; \&AnyEvent::Socket::tcp_connect };
770
771 $state{connect_guard} = $tcp_connect->($rhost, $rport, $connect_cb, $arg{on_prepare} || sub { $timeout });
772
767 }; 773 };
768 774
769 defined wantarray && AnyEvent::Util::guard { %state = () } 775 defined wantarray && AnyEvent::Util::guard { %state = () }
770} 776}
771 777

Diff Legend

Removed lines
+ Added lines
< Changed lines
> Changed lines