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.79 by root, Sat Jan 1 20:01:07 2011 UTC vs.
Revision 1.88 by root, Sun Jan 2 20:57:03 2011 UTC

36 36
37=cut 37=cut
38 38
39package AnyEvent::HTTP; 39package AnyEvent::HTTP;
40 40
41use strict; 41use common::sense;
42no warnings;
43 42
44use Errno (); 43use Errno ();
45 44
46use AnyEvent 5.0 (); 45use AnyEvent 5.0 ();
47use AnyEvent::Util (); 46use AnyEvent::Util ();
58our $MAX_PERSISTENT = 8; 57our $MAX_PERSISTENT = 8;
59our $PERSISTENT_TIMEOUT = 2; 58our $PERSISTENT_TIMEOUT = 2;
60our $TIMEOUT = 300; 59our $TIMEOUT = 300;
61 60
62# changing these is evil 61# changing these is evil
63our $MAX_PERSISTENT_PER_HOST = 0; 62our $MAX_PERSISTENT_PER_HOST = 2;
64our $MAX_PER_HOST = 4; 63our $MAX_PER_HOST = 4;
65 64
66our $PROXY; 65our $PROXY;
67our $ACTIVE = 0; 66our $ACTIVE = 0;
68 67
196=item cookie_jar => $hash_ref 195=item cookie_jar => $hash_ref
197 196
198Passing this parameter enables (simplified) cookie-processing, loosely 197Passing this parameter enables (simplified) cookie-processing, loosely
199based on the original netscape specification. 198based on the original netscape specification.
200 199
201The C<$hash_ref> must be an (initially empty) hash reference which will 200The C<$hash_ref> must be an (initially empty) hash reference which
202get updated automatically. It is possible to save the cookie jar to 201will get updated automatically. It is possible to save the cookie jar
203persistent storage with something like JSON or Storable, but this is not 202to persistent storage with something like JSON or Storable - see the
204recommended, as session-only cookies might survive longer than expected. 203C<AnyEvent::HTTP::cookie_jar_expire> function if you wish to remove
204expired or session-only cookies, and also for documentation on the format
205of the cookie jar.
205 206
206Note that this cookie implementation is not meant to be complete. If 207Note that this cookie implementation is not meant to be complete. If
207you want complete cookie management you have to do that on your 208you want complete cookie management you have to do that on your
208own. C<cookie_jar> is meant as a quick fix to get some cookie-using sites 209own. C<cookie_jar> is meant as a quick fix to get most cookie-using sites
209working. Cookies are a privacy disaster, do not use them unless required 210working. Cookies are a privacy disaster, do not use them unless required
210to. 211to.
211 212
212When cookie processing is enabled, the C<Cookie:> and C<Set-Cookie:> 213When cookie processing is enabled, the C<Cookie:> and C<Set-Cookie:>
213headers will be set and handled by this module, otherwise they will be 214headers will be set and handled by this module, otherwise they will be
378 push @{ $CO_SLOT{$_[0]}[1] }, $_[1]; 379 push @{ $CO_SLOT{$_[0]}[1] }, $_[1];
379 380
380 _slot_schedule $_[0]; 381 _slot_schedule $_[0];
381} 382}
382 383
384#############################################################################
385
386# expire cookies
387sub cookie_jar_expire($;$) {
388 my ($jar, $session_end) = @_;
389
390 %$jar = () if $jar->{version} != 1;
391
392 my $anow = AE::now;
393
394 while (my ($chost, $paths) = each %$jar) {
395 next unless ref $paths;
396
397 while (my ($cpath, $cookies) = each %$paths) {
398 while (my ($cookie, $kv) = each %$cookies) {
399 if (exists $kv->{_expires}) {
400 delete $cookies->{$cookie}
401 if $anow > $kv->{_expires};
402 } elsif ($session_end) {
403 delete $cookies->{$cookie};
404 }
405 }
406
407 delete $paths->{$cpath}
408 unless %$cookies;
409 }
410
411 delete $jar->{$chost}
412 unless %$paths;
413 }
414}
415
383# extract cookies from jar 416# extract cookies from jar
384sub cookie_jar_extract($$$$) { 417sub cookie_jar_extract($$$$) {
385 my ($jar, $uscheme, $uhost, $upath) = @_; 418 my ($jar, $uscheme, $uhost, $upath) = @_;
386 419
387 %$jar = () if $jar->{version} != 1; 420 %$jar = () if $jar->{version} != 1;
403 next unless $cpath eq substr $upath, 0, length $cpath; 436 next unless $cpath eq substr $upath, 0, length $cpath;
404 437
405 while (my ($cookie, $kv) = each %$cookies) { 438 while (my ($cookie, $kv) = each %$cookies) {
406 next if $uscheme ne "https" && exists $kv->{secure}; 439 next if $uscheme ne "https" && exists $kv->{secure};
407 440
408 if (exists $kv->{expires}) { 441 if (exists $kv->{_expires} and AE::now > $kv->{_expires}) {
409 if (AE::now > parse_date ($kv->{expires})) {
410 delete $cookies->{$cookie}; 442 delete $cookies->{$cookie};
411 next; 443 next;
412 }
413 } 444 }
414 445
415 my $value = $kv->{value}; 446 my $value = $kv->{value};
416 447
417 if ($value =~ /[=;,[:space:]]/) { 448 if ($value =~ /[=;,[:space:]]/) {
426 457
427 \@cookies 458 \@cookies
428} 459}
429 460
430# parse set_cookie header into jar 461# parse set_cookie header into jar
431sub cookie_jar_set_cookie($$$) { 462sub cookie_jar_set_cookie($$$$) {
432 my ($jar, $set_cookie, $uhost) = @_; 463 my ($jar, $set_cookie, $uhost, $date) = @_;
464
465 my $anow = int AE::now;
466 my $snow; # server-now
433 467
434 for ($set_cookie) { 468 for ($set_cookie) {
435 # parse NAME=VALUE 469 # parse NAME=VALUE
436 my @kv; 470 my @kv;
437 471
440 while ( 474 while (
441 m{ 475 m{
442 \G\s* 476 \G\s*
443 (?: 477 (?:
444 expires \s*=\s* ([A-Z][a-z][a-z]+,\ [^,;]+) 478 expires \s*=\s* ([A-Z][a-z][a-z]+,\ [^,;]+)
445 | ([^=;,[:space:]]+) \s*=\s* (?: "((?:[^\\"]+|\\.)*)" | ([^=;,[:space:]]*) ) 479 | ([^=;,[:space:]]+) (?: \s*=\s* (?: "((?:[^\\"]+|\\.)*)" | ([^=;,[:space:]]*) ) )?
446 ) 480 )
447 }gcxsi 481 }gcxsi
448 ) { 482 ) {
449 my $name = $2; 483 my $name = $2;
450 my $value = $4; 484 my $value = $4;
451 485
452 unless (defined $name) { 486 if (defined $1) {
453 # expires 487 # expires
454 $name = "expires"; 488 $name = "expires";
455 $value = $1; 489 $value = $1;
456 } elsif (!defined $value) { 490 } elsif (defined $3) {
457 # quoted 491 # quoted
458 $value = $3; 492 $value = $3;
459 $value =~ s/\\(.)/$1/gs; 493 $value =~ s/\\(.)/$1/gs;
460 } 494 }
461 495
467 last unless @kv; 501 last unless @kv;
468 502
469 my $name = shift @kv; 503 my $name = shift @kv;
470 my %kv = (value => shift @kv, @kv); 504 my %kv = (value => shift @kv, @kv);
471 505
472 $kv{expires} ||= format_date (AE::now + $kv{"max-age"})
473 if exists $kv{"max-age"}; 506 if (exists $kv{"max-age"}) {
507 $kv{_expires} = $anow + delete $kv{"max-age"};
508 } elsif (exists $kv{expires}) {
509 $snow ||= parse_date ($date) || $anow;
510 $kv{_expires} = $anow + (parse_date (delete $kv{expires}) - $snow);
511 } else {
512 delete $kv{_expires};
513 }
474 514
475 my $cdom; 515 my $cdom;
476 my $cpath = (delete $kv{path}) || "/"; 516 my $cpath = (delete $kv{path}) || "/";
477 517
478 if (exists $kv{domain}) { 518 if (exists $kv{domain}) {
489 $cdom = $uhost; 529 $cdom = $uhost;
490 } 530 }
491 531
492 # store it 532 # store it
493 $jar->{version} = 1; 533 $jar->{version} = 1;
494 $jar->{$cdom}{$cpath}{$name} = \%kv; 534 $jar->{lc $cdom}{$cpath}{$name} = \%kv;
495 535
496 redo if /\G\s*,/gc; 536 redo if /\G\s*,/gc;
497 } 537 }
498} 538}
499 539
566 : return $cb->(undef, { @pseudo, Status => 599, Reason => "Only http and https URL schemes supported" }); 606 : return $cb->(undef, { @pseudo, Status => 599, Reason => "Only http and https URL schemes supported" });
567 607
568 $uauthority =~ /^(?: .*\@ )? ([^\@:]+) (?: : (\d+) )?$/x 608 $uauthority =~ /^(?: .*\@ )? ([^\@:]+) (?: : (\d+) )?$/x
569 or return $cb->(undef, { @pseudo, Status => 599, Reason => "Unparsable URL" }); 609 or return $cb->(undef, { @pseudo, Status => 599, Reason => "Unparsable URL" });
570 610
571 my $uhost = $1; 611 my $uhost = lc $1;
572 $uport = $2 if defined $2; 612 $uport = $2 if defined $2;
573 613
574 $hdr{host} = defined $2 ? "$uhost:$2" : "$uhost" 614 $hdr{host} = defined $2 ? "$uhost:$2" : "$uhost"
575 unless exists $hdr{host}; 615 unless exists $hdr{host};
576 616
595 $rscheme = "http" unless defined $rscheme; 635 $rscheme = "http" unless defined $rscheme;
596 636
597 # don't support https requests over https-proxy transport, 637 # don't support https requests over https-proxy transport,
598 # can't be done with tls as spec'ed, unless you double-encrypt. 638 # can't be done with tls as spec'ed, unless you double-encrypt.
599 $rscheme = "http" if $uscheme eq "https" && $rscheme eq "https"; 639 $rscheme = "http" if $uscheme eq "https" && $rscheme eq "https";
640
641 $rhost = lc $rhost;
642 $rscheme = lc $rscheme;
600 } else { 643 } else {
601 ($rhost, $rport, $rscheme, $rpath) = ($uhost, $uport, $uscheme, $upath); 644 ($rhost, $rport, $rscheme, $rpath) = ($uhost, $uport, $uscheme, $upath);
602 } 645 }
603 646
604 # leave out fragment and query string, just a heuristic 647 # leave out fragment and query string, just a heuristic
606 $hdr{"user-agent"} = $USERAGENT unless exists $hdr{"user-agent"}; 649 $hdr{"user-agent"} = $USERAGENT unless exists $hdr{"user-agent"};
607 650
608 $hdr{"content-length"} = length $arg{body} 651 $hdr{"content-length"} = length $arg{body}
609 if length $arg{body} || $method ne "GET"; 652 if length $arg{body} || $method ne "GET";
610 653
611 $hdr{connection} = "close TE"; #1.1 654 $hdr{connection} = "close Te"; #1.1
612 $hdr{te} = "trailers" unless exists $hdr{te}; #1.1 655 $hdr{te} = "trailers" unless exists $hdr{te}; #1.1
613 656
614 my %state = (connect_guard => 1); 657 my %state = (connect_guard => 1);
615 658
616 _get_slot $uhost, sub {
617 $state{slot_guard} = shift;
618
619 return unless $state{connect_guard};
620
621 my $ae_error = 595; # connecting 659 my $ae_error = 595; # connecting
622 660
623 my $connect_cb = sub { 661 # handle actual, non-tunneled, request
624 $state{fh} = shift 662 my $handle_actual_request = sub {
663 $ae_error = 596; # request phase
664
665 $state{handle}->starttls ("connect") if $uscheme eq "https" && !exists $state{handle}{tls};
666
667 # send request
668 $state{handle}->push_write (
669 "$method $rpath HTTP/1.1\015\012"
670 . (join "", map "\u$_: $hdr{$_}\015\012", grep defined $hdr{$_}, keys %hdr)
671 . "\015\012"
672 . (delete $arg{body})
673 );
674
675 # return if error occured during push_write()
676 return unless %state;
677
678 %hdr = (); # reduce memory usage, save a kitten, also make it possible to re-use
679
680 # status line and headers
681 $state{read_response} = sub {
682 for ("$_[1]") {
683 y/\015//d; # weed out any \015, as they show up in the weirdest of places.
684
685 /^HTTP\/0*([0-9\.]+) \s+ ([0-9]{3}) (?: \s+ ([^\012]*) )? \012/gxci
686 or return (%state = (), $cb->(undef, { @pseudo, Status => 599, Reason => "Invalid server response" }));
687
688 # 100 Continue handling
689 # should not happen as we don't send expect: 100-continue,
690 # but we handle it just in case.
691 # since we send the request body regardless, if we get an error
692 # we are out of-sync, which we currently do NOT handle correctly.
693 return $state{handle}->push_read (line => $qr_nlnl, $state{read_response})
694 if $2 eq 100;
695
696 push @pseudo,
697 HTTPVersion => $1,
698 Status => $2,
699 Reason => $3,
625 or do { 700 ;
626 my $err = "$!"; 701
702 my $hdr = parse_hdr
703 or return (%state = (), $cb->(undef, { @pseudo, Status => 599, Reason => "Garbled response headers" }));
704
705 %hdr = (%$hdr, @pseudo);
706 }
707
708 # redirect handling
709 # microsoft and other shitheads don't give a shit for following standards,
710 # try to support some common forms of broken Location headers.
711 if ($hdr{location} !~ /^(?: $ | [^:\/?\#]+ : )/x) {
712 $hdr{location} =~ s/^\.\/+//;
713
714 my $url = "$rscheme://$uhost:$uport";
715
716 unless ($hdr{location} =~ s/^\///) {
717 $url .= $upath;
718 $url =~ s/\/[^\/]*$//;
719 }
720
721 $hdr{location} = "$url/$hdr{location}";
722 }
723
724 my $redirect;
725
726 if ($recurse) {
727 my $status = $hdr{Status};
728
729 # industry standard is to redirect POST as GET for
730 # 301, 302 and 303, in contrast to HTTP/1.0 and 1.1.
731 # also, the UA should ask the user for 301 and 307 and POST,
732 # industry standard seems to be to simply follow.
733 # we go with the industry standard.
734 if ($status == 301 or $status == 302 or $status == 303) {
735 # HTTP/1.1 is unclear on how to mutate the method
736 $method = "GET" unless $method eq "HEAD";
737 $redirect = 1;
738 } elsif ($status == 307) {
739 $redirect = 1;
740 }
741 }
742
743 my $finish = sub { # ($data, $err_status, $err_reason[, $keepalive])
744 my $may_keep_alive = $_[3];
745
746 $state{handle}->destroy if $state{handle};
627 %state = (); 747 %state = ();
628 return $cb->(undef, { @pseudo, Status => $ae_error, Reason => $err }); 748
749 if (defined $_[1]) {
750 $hdr{OrigStatus} = $hdr{Status}; $hdr{Status} = $_[1];
751 $hdr{OrigReason} = $hdr{Reason}; $hdr{Reason} = $_[2];
752 }
753
754 # set-cookie processing
755 if ($arg{cookie_jar}) {
756 cookie_jar_set_cookie $arg{cookie_jar}, $hdr{"set-cookie"}, $uhost, $hdr{date};
757 }
758
759 if ($redirect && exists $hdr{location}) {
760 # we ignore any errors, as it is very common to receive
761 # Content-Length != 0 but no actual body
762 # we also access %hdr, as $_[1] might be an erro
763 http_request (
764 $method => $hdr{location},
765 %arg,
766 recurse => $recurse - 1,
767 Redirect => [$_[0], \%hdr],
768 $cb);
769 } else {
770 $cb->($_[0], \%hdr);
771 }
772 };
773
774 $ae_error = 597; # body phase
775
776 my $len = $hdr{"content-length"};
777
778 # body handling, many different code paths
779 # - no body expected
780 # - want_body_handle
781 # - te chunked
782 # - 2x length known (with or without on_body)
783 # - 2x length not known (with or without on_body)
784 if (!$redirect && $arg{on_header} && !$arg{on_header}(\%hdr)) {
785 $finish->(undef, 598 => "Request cancelled by on_header");
786 } elsif (
787 $hdr{Status} =~ /^(?:1..|204|205|304)$/
788 or $method eq "HEAD"
789 or (defined $len && $len == 0) # == 0, not !, because "0 " is true
790 ) {
791 # no body
792 $finish->("", undef, undef, 1);
793
794 } elsif (!$redirect && $arg{want_body_handle}) {
795 $_[0]->on_eof (undef);
796 $_[0]->on_error (undef);
797 $_[0]->on_read (undef);
798
799 $finish->(delete $state{handle});
800
801 } elsif ($hdr{"transfer-encoding"} =~ /\bchunked\b/i) {
802 my $cl = 0;
803 my $body = undef;
804 my $on_body = $arg{on_body} || sub { $body .= shift; 1 };
805
806 $state{read_chunk} = sub {
807 $_[1] =~ /^([0-9a-fA-F]+)/
808 or $finish->(undef, $ae_error => "Garbled chunked transfer encoding");
809
810 my $len = hex $1;
811
812 if ($len) {
813 $cl += $len;
814
815 $_[0]->push_read (chunk => $len, sub {
816 $on_body->($_[1], \%hdr)
817 or return $finish->(undef, 598 => "Request cancelled by on_body");
818
819 $_[0]->push_read (line => sub {
820 length $_[1]
821 and return $finish->(undef, $ae_error => "Garbled chunked transfer encoding");
822 $_[0]->push_read (line => $state{read_chunk});
823 });
824 });
825 } else {
826 $hdr{"content-length"} ||= $cl;
827
828 $_[0]->push_read (line => $qr_nlnl, sub {
829 if (length $_[1]) {
830 for ("$_[1]") {
831 y/\015//d; # weed out any \015, as they show up in the weirdest of places.
832
833 my $hdr = parse_hdr
834 or return $finish->(undef, $ae_error => "Garbled response trailers");
835
836 %hdr = (%hdr, %$hdr);
837 }
838 }
839
840 $finish->($body, undef, undef, 1);
841 });
842 }
629 }; 843 };
630 844
845 $_[0]->push_read (line => $state{read_chunk});
846
847 } elsif ($arg{on_body}) {
848 if (defined $len) {
849 $_[0]->on_read (sub {
850 $len -= length $_[0]{rbuf};
851
852 $arg{on_body}(delete $_[0]{rbuf}, \%hdr)
853 or return $finish->(undef, 598 => "Request cancelled by on_body");
854
855 $len > 0
856 or $finish->("", undef, undef, 1);
857 });
858 } else {
859 $_[0]->on_eof (sub {
860 $finish->("");
861 });
862 $_[0]->on_read (sub {
863 $arg{on_body}(delete $_[0]{rbuf}, \%hdr)
864 or $finish->(undef, 598 => "Request cancelled by on_body");
865 });
866 }
867 } else {
868 $_[0]->on_eof (undef);
869
870 if (defined $len) {
871 $_[0]->on_read (sub {
872 $finish->((substr delete $_[0]{rbuf}, 0, $len, ""), undef, undef, 1)
873 if $len <= length $_[0]{rbuf};
874 });
875 } else {
876 $_[0]->on_error (sub {
877 ($! == Errno::EPIPE || !$!)
878 ? $finish->(delete $_[0]{rbuf})
879 : $finish->(undef, $ae_error => $_[2]);
880 });
881 $_[0]->on_read (sub { });
882 }
883 }
884 };
885
886 $state{handle}->push_read (line => $qr_nlnl, $state{read_response});
887 };
888
889 my $connect_cb = sub {
890 $state{fh} = shift
891 or do {
892 my $err = "$!";
893 %state = ();
894 return $cb->(undef, { @pseudo, Status => $ae_error, Reason => $err });
895 };
896
631 return unless delete $state{connect_guard}; 897 return unless delete $state{connect_guard};
632 898
633 # get handle 899 # get handle
634 $state{handle} = new AnyEvent::Handle 900 $state{handle} = new AnyEvent::Handle
635 fh => $state{fh}, 901 fh => $state{fh},
636 peername => $rhost, 902 peername => $rhost,
637 tls_ctx => $arg{tls_ctx}, 903 tls_ctx => $arg{tls_ctx},
638 # these need to be reconfigured on keepalive handles 904 # these need to be reconfigured on keepalive handles
639 timeout => $timeout, 905 timeout => $timeout,
640 on_error => sub { 906 on_error => sub {
641 %state = (); 907 %state = ();
642 $cb->(undef, { @pseudo, Status => $ae_error, Reason => $_[2] }); 908 $cb->(undef, { @pseudo, Status => $ae_error, Reason => $_[2] });
643 }, 909 },
644 on_eof => sub { 910 on_eof => sub {
645 %state = (); 911 %state = ();
646 $cb->(undef, { @pseudo, Status => $ae_error, Reason => "Unexpected end-of-file" }); 912 $cb->(undef, { @pseudo, Status => $ae_error, Reason => "Unexpected end-of-file" });
647 }, 913 },
648 ; 914 ;
649 915
650 # limit the number of persistent connections 916 # limit the number of persistent connections
651 # keepalive not yet supported 917 # keepalive not yet supported
652# if ($KA_COUNT{$_[1]} < $MAX_PERSISTENT_PER_HOST) { 918# if ($KA_COUNT{$_[1]} < $MAX_PERSISTENT_PER_HOST) {
653# ++$KA_COUNT{$_[1]}; 919# ++$KA_COUNT{$_[1]};
654# $state{handle}{ka_count_guard} = AnyEvent::Util::guard { 920# $state{handle}{ka_count_guard} = AnyEvent::Util::guard {
655# --$KA_COUNT{$_[1]} 921# --$KA_COUNT{$_[1]}
656# }; 922# };
657# $hdr{connection} = "keep-alive"; 923# $hdr{connection} = "keep-alive";
658# } 924# }
659 925
660 $state{handle}->starttls ("connect") if $rscheme eq "https"; 926 $state{handle}->starttls ("connect") if $rscheme eq "https";
661 927
662 # handle actual, non-tunneled, request
663 my $handle_actual_request = sub {
664 $ae_error = 596; # request phase
665
666 $state{handle}->starttls ("connect") if $uscheme eq "https" && !exists $state{handle}{tls};
667
668 # send request
669 $state{handle}->push_write (
670 "$method $rpath HTTP/1.1\015\012"
671 . (join "", map "\u$_: $hdr{$_}\015\012", grep defined $hdr{$_}, keys %hdr)
672 . "\015\012"
673 . (delete $arg{body})
674 );
675
676 # return if error occured during push_write()
677 return unless %state;
678
679 %hdr = (); # reduce memory usage, save a kitten, also make it possible to re-use
680
681 # status line and headers
682 $state{read_response} = sub {
683 for ("$_[1]") {
684 y/\015//d; # weed out any \015, as they show up in the weirdest of places.
685
686 /^HTTP\/0*([0-9\.]+) \s+ ([0-9]{3}) (?: \s+ ([^\012]*) )? \012/gxci
687 or return (%state = (), $cb->(undef, { @pseudo, Status => 599, Reason => "Invalid server response" }));
688
689 # 100 Continue handling
690 # should not happen as we don't send expect: 100-continue,
691 # but we handle it just in case.
692 # since we send the request body regardless, if we get an error
693 # we are out of-sync, which we currently do NOT handle correctly.
694 return $state{handle}->push_read (line => $qr_nlnl, $state{read_response})
695 if $2 eq 100;
696
697 push @pseudo,
698 HTTPVersion => $1,
699 Status => $2,
700 Reason => $3,
701 ;
702
703 my $hdr = parse_hdr
704 or return (%state = (), $cb->(undef, { @pseudo, Status => 599, Reason => "Garbled response headers" }));
705
706 %hdr = (%$hdr, @pseudo);
707 }
708
709 # redirect handling
710 # microsoft and other shitheads don't give a shit for following standards,
711 # try to support some common forms of broken Location headers.
712 if ($hdr{location} !~ /^(?: $ | [^:\/?\#]+ : )/x) {
713 $hdr{location} =~ s/^\.\/+//;
714
715 my $url = "$rscheme://$uhost:$uport";
716
717 unless ($hdr{location} =~ s/^\///) {
718 $url .= $upath;
719 $url =~ s/\/[^\/]*$//;
720 }
721
722 $hdr{location} = "$url/$hdr{location}";
723 }
724
725 my $redirect;
726
727 if ($recurse) {
728 my $status = $hdr{Status};
729
730 # industry standard is to redirect POST as GET for
731 # 301, 302 and 303, in contrast to HTTP/1.0 and 1.1.
732 # also, the UA should ask the user for 301 and 307 and POST,
733 # industry standard seems to be to simply follow.
734 # we go with the industry standard.
735 if ($status == 301 or $status == 302 or $status == 303) {
736 # HTTP/1.1 is unclear on how to mutate the method
737 $method = "GET" unless $method eq "HEAD";
738 $redirect = 1;
739 } elsif ($status == 307) {
740 $redirect = 1;
741 }
742 }
743
744 my $finish = sub { # ($data, $err_status, $err_reason[, $keepalive])
745 my $may_keep_alive = $_[3];
746
747 $state{handle}->destroy if $state{handle};
748 %state = ();
749
750 if (defined $_[1]) {
751 $hdr{OrigStatus} = $hdr{Status}; $hdr{Status} = $_[1];
752 $hdr{OrigReason} = $hdr{Reason}; $hdr{Reason} = $_[2];
753 }
754
755 # set-cookie processing
756 if ($arg{cookie_jar}) {
757 cookie_jar_set_cookie $arg{cookie_jar}, $hdr{"set-cookie"}, $uhost;
758 }
759
760 if ($redirect && exists $hdr{location}) {
761 # we ignore any errors, as it is very common to receive
762 # Content-Length != 0 but no actual body
763 # we also access %hdr, as $_[1] might be an erro
764 http_request (
765 $method => $hdr{location},
766 %arg,
767 recurse => $recurse - 1,
768 Redirect => [$_[0], \%hdr],
769 $cb);
770 } else {
771 $cb->($_[0], \%hdr);
772 }
773 };
774
775 $ae_error = 597; # body phase
776
777 my $len = $hdr{"content-length"};
778
779 if (!$redirect && $arg{on_header} && !$arg{on_header}(\%hdr)) {
780 $finish->(undef, 598 => "Request cancelled by on_header");
781 } elsif (
782 $hdr{Status} =~ /^(?:1..|204|205|304)$/
783 or $method eq "HEAD"
784 or (defined $len && !$len)
785 ) {
786 # no body
787 $finish->("", undef, undef, 1);
788 } else {
789 # body handling, many different code paths
790 # - no body expected
791 # - want_body_handle
792 # - te chunked
793 # - 2x length known (with or without on_body)
794 # - 2x length not known (with or without on_body)
795 if (!$redirect && $arg{want_body_handle}) {
796 $_[0]->on_eof (undef);
797 $_[0]->on_error (undef);
798 $_[0]->on_read (undef);
799
800 $finish->(delete $state{handle});
801
802 } elsif ($hdr{"transfer-encoding"} =~ /\bchunked\b/i) {
803 my $cl = 0;
804 my $body = undef;
805 my $on_body = $arg{on_body} || sub { $body .= shift; 1 };
806
807 my $read_chunk; $read_chunk = sub {
808 $_[1] =~ /^([0-9a-fA-F]+)/
809 or $finish->(undef, $ae_error => "Garbled chunked transfer encoding");
810
811 my $len = hex $1;
812
813 if ($len) {
814 $cl += $len;
815
816 $_[0]->push_read (chunk => $len, sub {
817 $on_body->($_[1], \%hdr)
818 or return $finish->(undef, 598 => "Request cancelled by on_body");
819
820 $_[0]->push_read (line => sub {
821 length $_[1]
822 and return $finish->(undef, $ae_error => "Garbled chunked transfer encoding");
823 $_[0]->push_read (line => $read_chunk);
824 });
825 });
826 } else {
827 $hdr{"content-length"} ||= $cl;
828
829 $_[0]->push_read (line => $qr_nlnl, sub {
830 if (length $_[1]) {
831 for ("$_[1]") {
832 y/\015//d; # weed out any \015, as they show up in the weirdest of places.
833
834 my $hdr = parse_hdr
835 or return $finish->(undef, $ae_error => "Garbled response trailers");
836
837 %hdr = (%hdr, %$hdr);
838 }
839 }
840
841 $finish->($body, undef, undef, 1);
842 });
843 }
844 };
845
846 $_[0]->push_read (line => $read_chunk);
847
848 } elsif ($arg{on_body}) {
849 if ($len) {
850 $_[0]->on_read (sub {
851 $len -= length $_[0]{rbuf};
852
853 $arg{on_body}(delete $_[0]{rbuf}, \%hdr)
854 or return $finish->(undef, 598 => "Request cancelled by on_body");
855
856 $len > 0
857 or $finish->("", undef, undef, 1);
858 });
859 } else {
860 $_[0]->on_eof (sub {
861 $finish->("");
862 });
863 $_[0]->on_read (sub {
864 $arg{on_body}(delete $_[0]{rbuf}, \%hdr)
865 or $finish->(undef, 598 => "Request cancelled by on_body");
866 });
867 }
868 } else {
869 $_[0]->on_eof (undef);
870
871 if ($len) {
872 $_[0]->on_read (sub {
873 $finish->((substr delete $_[0]{rbuf}, 0, $len, ""), undef, undef, 1)
874 if $len <= length $_[0]{rbuf};
875 });
876 } else {
877 $_[0]->on_error (sub {
878 ($! == Errno::EPIPE || !$!)
879 ? $finish->(delete $_[0]{rbuf})
880 : $finish->(undef, $ae_error => $_[2]);
881 });
882 $_[0]->on_read (sub { });
883 }
884 }
885 }
886 };
887
888 $state{handle}->push_read (line => $qr_nlnl, $state{read_response});
889 };
890
891 # now handle proxy-CONNECT method 928 # now handle proxy-CONNECT method
892 if ($proxy && $uscheme eq "https") { 929 if ($proxy && $uscheme eq "https") {
893 # oh dear, we have to wrap it into a connect request 930 # oh dear, we have to wrap it into a connect request
894 931
895 # maybe re-use $uauthority with patched port? 932 # maybe re-use $uauthority with patched port?
896 $state{handle}->push_write ("CONNECT $uhost:$uport HTTP/1.0\015\012Host: $uhost\015\012\015\012"); 933 $state{handle}->push_write ("CONNECT $uhost:$uport HTTP/1.0\015\012\015\012");
897 $state{handle}->push_read (line => $qr_nlnl, sub { 934 $state{handle}->push_read (line => $qr_nlnl, sub {
898 $_[1] =~ /^HTTP\/([0-9\.]+) \s+ ([0-9]{3}) (?: \s+ ([^\015\012]*) )?/ix 935 $_[1] =~ /^HTTP\/([0-9\.]+) \s+ ([0-9]{3}) (?: \s+ ([^\015\012]*) )?/ix
899 or return (%state = (), $cb->(undef, { @pseudo, Status => 599, Reason => "Invalid proxy connect response ($_[1])" })); 936 or return (%state = (), $cb->(undef, { @pseudo, Status => 599, Reason => "Invalid proxy connect response ($_[1])" }));
900 937
901 if ($2 == 200) { 938 if ($2 == 200) {
902 $rpath = $upath; 939 $rpath = $upath;
903 &$handle_actual_request; 940 $handle_actual_request->();
904 } else { 941 } else {
905 %state = (); 942 %state = ();
906 $cb->(undef, { @pseudo, Status => $2, Reason => $3 }); 943 $cb->(undef, { @pseudo, Status => $2, Reason => $3 });
907 }
908 }); 944 }
909 } else {
910 &$handle_actual_request;
911 } 945 });
946 } else {
947 $handle_actual_request->();
912 }; 948 }
949 };
950
951 _get_slot $uhost, sub {
952 $state{slot_guard} = shift;
953
954 return unless $state{connect_guard};
913 955
914 my $tcp_connect = $arg{tcp_connect} 956 my $tcp_connect = $arg{tcp_connect}
915 || do { require AnyEvent::Socket; \&AnyEvent::Socket::tcp_connect }; 957 || do { require AnyEvent::Socket; \&AnyEvent::Socket::tcp_connect };
916 958
917 $state{connect_guard} = $tcp_connect->($rhost, $rport, $connect_cb, $arg{on_prepare} || sub { $timeout }); 959 $state{connect_guard} = $tcp_connect->($rhost, $rport, $connect_cb, $arg{on_prepare} || sub { $timeout });
918
919 }; 960 };
920 961
921 defined wantarray && AnyEvent::Util::guard { %state = () } 962 defined wantarray && AnyEvent::Util::guard { %state = () }
922} 963}
923 964
957Sets the default proxy server to use. The proxy-url must begin with a 998Sets the default proxy server to use. The proxy-url must begin with a
958string of the form C<http://host:port> (optionally C<https:...>), croaks 999string of the form C<http://host:port> (optionally C<https:...>), croaks
959otherwise. 1000otherwise.
960 1001
961To clear an already-set proxy, use C<undef>. 1002To clear an already-set proxy, use C<undef>.
1003
1004=item AnyEvent::HTTP::cookie_jar_expire $jar[, $session_end]
1005
1006Remove all cookies from the cookie jar that have been expired. If
1007C<$session_end> is given and true, then additionally remove all session
1008cookies.
1009
1010You should call this function (with a true C<$session_end>) before you
1011save cookies to disk, and you should call this function after loading them
1012again. If you have a long-running program you can additonally call this
1013function from time to time.
1014
1015A cookie jar is initially an empty hash-reference that is managed by this
1016module. It's format is subject to change, but currently it is like this:
1017
1018The key C<version> has to contain C<1>, otherwise the hash gets
1019emptied. All other keys are hostnames or IP addresses pointing to
1020hash-references. The key for these inner hash references is the
1021server path for which this cookie is meant, and the values are again
1022hash-references. The keys of those hash-references is the cookie name, and
1023the value, you guessed it, is another hash-reference, this time with the
1024key-value pairs from the cookie, except for C<expires> and C<max-age>,
1025which have been replaced by a C<_expires> key that contains the cookie
1026expiry timestamp.
1027
1028Here is an example of a cookie jar with a single cookie, so you have a
1029chance of understanding the above paragraph:
1030
1031 {
1032 version => 1,
1033 "10.0.0.1" => {
1034 "/" => {
1035 "mythweb_id" => {
1036 _expires => 1293917923,
1037 value => "ooRung9dThee3ooyXooM1Ohm",
1038 },
1039 },
1040 },
1041 }
962 1042
963=item $date = AnyEvent::HTTP::format_date $timestamp 1043=item $date = AnyEvent::HTTP::format_date $timestamp
964 1044
965Takes a POSIX timestamp (seconds since the epoch) and formats it as a HTTP 1045Takes a POSIX timestamp (seconds since the epoch) and formats it as a HTTP
966Date (RFC 2616). 1046Date (RFC 2616).

Diff Legend

Removed lines
+ Added lines
< Changed lines
> Changed lines