Skip to content

Commit

Permalink
Browse files Browse the repository at this point in the history
fixed Mojo::UserAgent to ignore unexpected 1xx responses
  • Loading branch information
kraih committed Nov 22, 2012
1 parent 842814f commit 9a977da
Show file tree
Hide file tree
Showing 4 changed files with 57 additions and 21 deletions.
4 changes: 2 additions & 2 deletions Changes
@@ -1,9 +1,9 @@

3.60 2012-11-22
- Improved Mojo::UserAgent to remove Expect headers if they are set to
"100-Continue".
- Added unexpected event to Mojo::Transaction::HTTP.
- Improved documentation.
- Improved tests.
- Fixed Mojo::UserAgent to ignore unexpected 1xx responses.

3.59 2012-11-20
- Improved tests.
Expand Down
22 changes: 20 additions & 2 deletions lib/Mojo/Transaction/HTTP.pm
Expand Up @@ -9,9 +9,13 @@ sub client_read {
# Skip body for HEAD request
my $res = $self->res;
$res->content->skip_body(1) if $self->req->method eq 'HEAD';
return unless $res->parse($chunk)->is_finished;

# Parse response
$self->{state} = 'finished' if $res->parse($chunk)->is_finished;
# Unexpected 1xx reponse
return $self->{state} = 'finished'
if $res->headers->upgrade || !$res->is_status_class(100);
$self->res($res->new)->emit(unexpected => $res);
$self->client_read($res->leftovers) if $res->has_leftovers;
}

sub client_write {
Expand Down Expand Up @@ -236,6 +240,20 @@ Emitted when a request is ready and needs to be handled.
$tx->res->headers->header('X-Bender' => 'Bite my shiny metal ass!');
});
=head2 C<unexpected>
$tx->on(unexpected => sub {
my ($tx, $res) = @_;
...
});
Emitted for unexpected C<1xx> responses that will be ignored.
$tx->on(unexpected => sub {
my $tx = shift;
$tx->res->on(finish => sub { say 'Followup response is finished.' });
});
=head2 C<upgrade>
$tx->on(upgrade => sub {
Expand Down
3 changes: 1 addition & 2 deletions lib/Mojo/UserAgent.pm
Expand Up @@ -455,11 +455,10 @@ sub _start {
if $https && !defined $req->proxy && $scheme eq 'https';
}

# We identify ourselves and accept gzip compression but no 100 Continue
# We identify ourselves and accept gzip compression
my $headers = $req->headers;
$headers->user_agent($self->name) unless $headers->user_agent;
$headers->accept_encoding('gzip') unless $headers->accept_encoding;
$headers->remove('Expect') if ($headers->expect // '') =~ /100-continue/i;

# Inject cookies
if (my $jar = $self->cookie_jar) { $jar->inject($tx) }
Expand Down
49 changes: 34 additions & 15 deletions t/mojo/user_agent.t
Expand Up @@ -9,6 +9,7 @@ BEGIN {
use Test::More;
use IO::Compress::Gzip 'gzip';
use Mojo::IOLoop;
use Mojo::Message::Request;
use Mojo::UserAgent;
use Mojolicious::Lite;

Expand Down Expand Up @@ -213,16 +214,6 @@ ok $tx->res->is_finished, 'response is finished';
is $tx->res->code, 200, 'right status';
is $tx->res->body, 'works!', 'right content';

# GET /echo (removed Expect header)
my $expect;
$ua->once(start => sub { $expect = pop->req->headers->expect });
$tx = $ua->get('/echo' => {Expect => '100-Continue'} => 'Hello Continue!');
ok $tx->success, 'successful';
ok !$expect, 'no "Expect" header';
ok !$tx->req->headers->expect, 'no "Expect" header';
is $tx->res->code, 200, 'right status';
is $tx->res->body, 'Hello Continue!', 'right content';

# GET /no_length (missing Content-Length header)
($finished_req, $finished_tx, $finished_res) = ();
$tx = $ua->build_tx(GET => '/no_length');
Expand Down Expand Up @@ -464,12 +455,40 @@ ok !$tx->kept_alive, 'kept connection not alive';
is $tx->res->code, 200, 'right status';
is $tx->res->body, 'works!', 'right content';

# Premature connection close
# Unexpected 1xx responses
my $port = Mojo::IOLoop->generate_port;
my $id = Mojo::IOLoop->server(
address => '127.0.0.1',
port => $port,
sub { Mojo::IOLoop->remove(pop) }
$req = Mojo::Message::Request->new;
Mojo::IOLoop->server(
{address => '127.0.0.1', port => $port} => sub {
my ($loop, $stream) = @_;
$stream->on(
read => sub {
my ($stream, $chunk) = @_;
$stream->write("HTTP/1.1 100 Continue\x0d\x0a"
. "X-Foo: Bar\x0d\x0a\x0d\x0a"
. "HTTP/1.1 101 Switching Protocols\x0d\x0a\x0d\x0a"
. "HTTP/1.1 200 OK\x0d\x0a"
. "Content-Length: 3\x0d\x0a\x0d\x0a" . 'Hi!')
if $req->parse($chunk)->is_finished;
}
);
}
);
$tx = $ua->build_tx(GET => "http://localhost:$port/");
my @unexpected;
$tx->on(unexpected => sub { push @unexpected, pop });
$tx = $ua->start($tx);
is $unexpected[0]->code, 100, 'right status';
is $unexpected[0]->headers->header('X-Foo'), 'Bar', 'right "X-Foo" value';
is $unexpected[1]->code, 101, 'right status';
ok $tx->success, 'successful';
is $tx->res->code, 200, 'right status';
is $tx->res->body, 'Hi!', 'right content';

# Premature connection close
$port = Mojo::IOLoop->generate_port;
Mojo::IOLoop->server(
{address => '127.0.0.1', port => $port} => sub { Mojo::IOLoop->remove(pop) }
);
$tx = $ua->get("http://localhost:$port/");
ok !$tx->success, 'not successful';
Expand Down

0 comments on commit 9a977da

Please sign in to comment.