@@ -24,6 +24,8 @@ This constructor returns a new HTTP::Tiny object. Valid attributes include:
2424* C<local_address > — The local IP address to bind to
2525* C<keep_alive > — Whether to reuse the last connection (if for the same
2626 scheme, host and port) (defaults to 1)
27+ * C<keep_alive_timeout > — How many seconds between a request to keep a
28+ keepalive connection available for (defaults to 0, unlimited)
2729* C<max_redirect > — Maximum number of redirects allowed (defaults to 5)
2830* C<max_size > — Maximum response size in bytes (only when not using a data
2931 callback). If defined, requests with responses larger than this will return
@@ -65,6 +67,12 @@ attributes are modified via accessor, or if the process ID or thread ID change,
6567the persistent connection will be dropped. If you want persistent connections
6668across multiple destinations, use multiple HTTP::Tiny objects.
6769
70+ The C<keep_alive_timeout > parameter allows you to control how long a
71+ keep alive connection will be considered for reuse. By setting this lower
72+ than the server keep alive time, this allows you to avoid race conditions where
73+ the server closes the connection while preparing to write the request on
74+ a reused persistent connection.
75+
6876See L</TLS/SSL SUPPORT> for more on the C<verify_SSL > and C<SSL_options >
6977attributes.
7078
@@ -127,6 +135,7 @@ sub new {
127135 max_redirect => 5,
128136 timeout => defined $args {timeout } ? $args {timeout } : 60,
129137 keep_alive => 1,
138+ keep_alive_timeout => 0,
130139 verify_SSL => defined $args {verify_SSL } ? $args {verify_SSL } : _verify_SSL_default(),
131140 no_proxy => $ENV {no_proxy },
132141 };
@@ -694,6 +703,7 @@ sub _request {
694703 && $response -> {protocol } eq ' HTTP/1.1'
695704 && ($response -> {headers }{connection } || ' ' ) ne ' close'
696705 ) {
706+ $handle -> _update_last_used();
697707 $self -> {handle } = $handle ;
698708 }
699709 else {
@@ -723,9 +733,12 @@ sub _open_handle {
723733 SSL_options => $self -> {SSL_options },
724734 verify_SSL => $self -> {verify_SSL },
725735 local_address => $self -> {local_address },
726- keep_alive => $self -> {keep_alive }
736+ keep_alive => $self -> {keep_alive },
737+ keep_alive_timeout => $self -> {keep_alive_timeout }
727738 );
728739
740+ require Time::HiRes if $self -> {keep_alive_timeout } > 0;
741+
729742 if ($self -> {_has_proxy }{$scheme } && ! grep { $host =~ / \Q $_ \E $ / } @{$self -> {no_proxy }}) {
730743 return $self -> _proxy_connect( $request , $handle );
731744 }
@@ -1621,6 +1634,19 @@ sub can_write {
16211634 return $self -> _do_timeout(' write' , @_ )
16221635}
16231636
1637+ sub _has_keep_alive_expired {
1638+ my $self = shift ;
1639+ return unless $self -> {keep_alive_timeout } > 0;
1640+ my $now = Time::HiRes::time ();
1641+ return $now - ($self -> {last_used } || $now ) > $self -> {keep_alive_timeout };
1642+ }
1643+
1644+ sub _update_last_used {
1645+ my $self = shift ;
1646+ return unless $self -> {keep_alive_timeout } > 0;
1647+ $self -> {last_used } = Time::HiRes::time ();
1648+ }
1649+
16241650sub _assert_ssl {
16251651 my ($ok , $reason ) = HTTP::Tiny-> can_ssl();
16261652 die $reason unless $ok ;
@@ -1636,6 +1662,7 @@ sub can_reuse {
16361662 || $host ne $self -> {host }
16371663 || $port ne $self -> {port }
16381664 || $peer ne $self -> {peer }
1665+ || $self -> _has_keep_alive_expired()
16391666 || eval { $self -> can_read(0) }
16401667 || $@ ;
16411668 return 1;
0 commit comments