Skip to content

Commit

Permalink
improved support for broken responses to CONNECT requests
Browse files Browse the repository at this point in the history
  • Loading branch information
kraih committed Jun 3, 2014
1 parent 73b6911 commit 079514f
Show file tree
Hide file tree
Showing 7 changed files with 37 additions and 10 deletions.
2 changes: 2 additions & 0 deletions Changes
@@ -1,5 +1,7 @@

5.04 2014-06-03
- Added expect_close attribute to Mojo::Content.
- Improved support for broken responses to CONNECT requests.

5.03 2014-06-02
- Fixed bug where Mojo::DOM::HTML could not handle certain broken tags.
Expand Down
14 changes: 10 additions & 4 deletions lib/Mojo/Content.pm
Expand Up @@ -5,7 +5,7 @@ use Carp 'croak';
use Compress::Raw::Zlib qw(WANT_GZIP Z_STREAM_END);
use Mojo::Headers;

has [qw(auto_relax relaxed skip_body)];
has [qw(auto_relax expect_close relaxed skip_body)];
has headers => sub { Mojo::Headers->new };
has max_buffer_size => sub { $ENV{MOJO_MAX_BUFFER_SIZE} || 262144 };
has max_leftover_size => sub { $ENV{MOJO_MAX_LEFTOVER_SIZE} || 262144 };
Expand Down Expand Up @@ -114,11 +114,10 @@ sub parse {

# Relaxed parsing
my $headers = $self->headers;
if ($self->auto_relax) {
if ($self->auto_relax && !length($headers->content_length // '')) {
my $connection = lc($headers->connection // '');
my $len = $headers->content_length // '';
$self->relaxed(1)
if !length $len && ($connection eq 'close' || $headers->content_type);
if $connection eq 'close' || (!$connection && $self->expect_close);
}

# Chunked or relaxed content
Expand Down Expand Up @@ -386,6 +385,13 @@ L<Mojo::Content> implements the following attributes.
Try to detect when relaxed parsing is necessary.
=head2 expect_close
my $bool = $content->expect_close;
$content = $content->expect_close($bool);
Expect a response that is terminated with a connection close.
=head2 headers
my $headers = $content->headers;
Expand Down
8 changes: 6 additions & 2 deletions lib/Mojo/Message/Response.pm
Expand Up @@ -97,8 +97,12 @@ sub extract_start_line {
return undef unless $$bufref =~ s/^(.*?)\x0d?\x0a//;
$self->error({message => 'Bad response start line'}) and return undef
unless $1 =~ m!^\s*HTTP/(\d\.\d)\s+(\d\d\d)\s*(.+)?$!;
$self->content->skip_body(1) if $self->code($2)->is_empty;
return !!$self->version($1)->message($3)->content->auto_relax(1);

my $content = $self->content;
$content->skip_body(1) if $self->code($2)->is_empty;
$content->auto_relax(1) unless defined $content->auto_relax;
$content->expect_close(1) if $1 eq '1.0';
return !!$self->version($1)->message($3);
}

sub fix_headers {
Expand Down
3 changes: 2 additions & 1 deletion lib/Mojo/UserAgent/Transactor.pm
Expand Up @@ -58,9 +58,10 @@ sub proxy_connect {
my $url = $req->url;
return undef unless $req->is_handshake || $url->protocol eq 'https';

# CONNECT request
# CONNECT request (expect a bad response)
my $new = $self->tx(CONNECT => $url->clone->userinfo(undef));
$new->req->proxy($proxy);
$new->res->content->auto_relax(0);

return $new;
}
Expand Down
16 changes: 15 additions & 1 deletion t/mojo/response.t
Expand Up @@ -196,6 +196,20 @@ is $res->headers->content_type, 'text/plain', 'right "Content-Type" value';
is $res->headers->content_length, 27, 'right "Content-Length" value';
is $res->body, "Hello World!\n1234\nlalalala\n", 'right content';

# Parse full HTTP 1.0 response (keep-alive)
$res = Mojo::Message::Response->new;
$res->parse("HTTP/1.0 500 Internal Server Error\x0d\x0a");
$res->parse("Connection: keep-alive\x0d\x0a\x0d\x0a");
$res->parse("HTTP/1.0 200 Internal Server Error\x0d\x0a\x0d\x0a");
ok $res->is_finished, 'response is finished';
is $res->code, 500, 'right status';
is $res->message, 'Internal Server Error', 'right message';
is $res->version, '1.0', 'right version';
is $res->body, '', 'no content';
is $res->content->leftovers,
"HTTP/1.0 200 Internal Server Error\x0d\x0a\x0d\x0a",
'next response in leftovers';

# Parse full HTTP 1.0 response (no limit)
{
local $ENV{MOJO_MAX_MESSAGE_SIZE} = 0;
Expand Down Expand Up @@ -1025,7 +1039,7 @@ is_deeply [$res->dom->find('p > a')->pluck('text')->each], [qw(test test)],

# Build DOM from response with charset
$res = Mojo::Message::Response->new;
$res->parse("HTTP/1.1 200 OK\x0a");
$res->parse("HTTP/1.0 200 OK\x0a");
$res->parse(
"Content-Type: application/atom+xml; charset=UTF-8; type=feed\x0a");
$res->parse("\x0a");
Expand Down
2 changes: 1 addition & 1 deletion t/mojo/websocket_proxy.t
Expand Up @@ -48,7 +48,7 @@ my $nf
= "HTTP/1.1 404 NOT FOUND\x0d\x0a"
. "Content-Length: 0\x0d\x0a"
. "Connection: close\x0d\x0a\x0d\x0a";
my $ok = "HTTP/1.1 200 OK\x0d\x0aConnection: keep-alive\x0d\x0a\x0d\x0a";
my $ok = "HTTP/1.0 201 BAR\x0d\x0aX-Something: unimportant\x0d\x0a\x0d\x0a";
my $id = Mojo::IOLoop->server(
{address => '127.0.0.1'} => sub {
my ($loop, $stream, $client) = @_;
Expand Down
2 changes: 1 addition & 1 deletion t/mojo/websocket_proxy_tls.t
Expand Up @@ -67,7 +67,7 @@ my $nf
= "HTTP/1.1 501 FOO\x0d\x0a"
. "Content-Length: 0\x0d\x0a"
. "Connection: close\x0d\x0a\x0d\x0a";
my $ok = "HTTP/1.0 201 BAR\x0d\x0aX-Something: unimportant\x0d\x0a\x0d\x0a";
my $ok = "HTTP/1.1 200 OK\x0d\x0aConnection: keep-alive\x0d\x0a\x0d\x0a";
my $id = Mojo::IOLoop->server(
{address => '127.0.0.1'} => sub {
my ($loop, $stream, $client) = @_;
Expand Down

1 comment on commit 079514f

@korjavin
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah. that save me with my problem.

Please sign in to comment.