Skip to content

Commit

Permalink
small optimizations
Browse files Browse the repository at this point in the history
  • Loading branch information
kraih committed Jul 26, 2012
1 parent fb9a1e2 commit d773b22
Show file tree
Hide file tree
Showing 4 changed files with 52 additions and 72 deletions.
114 changes: 47 additions & 67 deletions lib/Mojo/Content.pm
Expand Up @@ -15,20 +15,18 @@ sub body_contains {
sub body_size { croak 'Method "body_size" not implemented by subclass' }

sub boundary {
(shift->headers->content_type || '')
=~ m!multipart.*boundary="*([a-zA-Z0-9'(),.:?\-_+/]+)!i
and return $1;
my $type = shift->headers->content_type || '';
$type =~ m!multipart.*boundary="*([a-zA-Z0-9'(),.:?\-_+/]+)!i and return $1;
return;
}

# "Operator! Give me the number for 911!"
sub build_body { shift->_build('body') }
sub build_headers { shift->_build('header') }
sub build_body { shift->_build('get_body_chunk') }
sub build_headers { shift->_build('get_header_chunk') }

sub charset {
(shift->headers->content_type || '') =~ /charset="?([^"\s;]+)"?/i
and return $1;
return;
my $type = shift->headers->content_type || '';
return $type =~ /charset="?([^"\s;]+)"?/i ? $1 : undef;
}

sub clone {
Expand Down Expand Up @@ -111,7 +109,7 @@ sub parse {
$self->{real_size} = 0 unless exists $self->{real_size};
if ($self->is_chunked && !($self->{state} ~~ 'headers')) {
$self->_parse_chunked;
$self->{state} = 'finished' if $self->{chunked} ~~ 'finished';
$self->{state} = 'finished' if $self->{chunked_state} ~~ 'finished';
}

# Not chunked, pass through to second buffer
Expand Down Expand Up @@ -224,10 +222,9 @@ sub _body {
}

sub _build {
my ($self, $part) = @_;
my ($self, $method) = @_;

# Build part from chunks
my $method = "get_${part}_chunk";
my $buffer = '';
my $offset = 0;
while (1) {
Expand All @@ -251,62 +248,48 @@ sub _build_chunk {
my ($self, $chunk) = @_;

# End
my $formatted = '';
if (length $chunk == 0) { $formatted = "\x0d\x0a0\x0d\x0a\x0d\x0a" }

# Separator
else {

# First chunk has no leading CRLF
$formatted = "\x0d\x0a" if $self->{chunks};
$self->{chunks} = 1;
return "\x0d\x0a0\x0d\x0a\x0d\x0a" if length $chunk == 0;

# Chunk
$formatted .= sprintf('%x', length $chunk) . "\x0d\x0a$chunk";
}

return $formatted;
# First chunk has no leading CRLF
my $crlf = $self->{chunks}++ ? '' : "\x0d\x0a";
return $crlf . sprintf('%x', length $chunk) . "\x0d\x0a$chunk";
}

sub _parse_chunked {
my $self = shift;

# Trailing headers
return $self->_parse_chunked_trailing_headers
if $self->{chunked} ~~ 'trailing_headers';
if $self->{chunked_state} ~~ 'trailing_headers';

# New chunk (ignore the chunk extension)
while ($self->{pre_buffer} =~ /^((?:\x0d?\x0a)?([\da-fA-F]+).*\x0d?\x0a)/) {
my $header = $1;
my $len = hex($2);

# Whole chunk
if (length($self->{pre_buffer}) >= (length($header) + $len)) {

# Remove header
substr $self->{pre_buffer}, 0, length $header, '';

# Last chunk
if ($len == 0) {
$self->{chunked} = 'trailing_headers';
last;
}
# Check if we have a whole chunk yet
last unless length($self->{pre_buffer}) >= (length($header) + $len);

# Remove payload
$self->{real_size} += $len;
$self->{buffer} .= substr $self->{pre_buffer}, 0, $len, '';
# Remove header
substr $self->{pre_buffer}, 0, length $header, '';

# Remove newline at end of chunk
$self->{pre_buffer} =~ s/^(\x0d?\x0a)//;
# Last chunk
if ($len == 0) {
$self->{chunked_state} = 'trailing_headers';
last;
}

# Not a whole chunk, wait for more data
else {last}
# Remove payload
$self->{real_size} += $len;
$self->{buffer} .= substr $self->{pre_buffer}, 0, $len, '';

# Remove newline at end of chunk
$self->{pre_buffer} =~ s/^(\x0d?\x0a)//;
}

# Trailing headers
$self->_parse_chunked_trailing_headers
if $self->{chunked} ~~ 'trailing_headers';
if $self->{chunked_state} ~~ 'trailing_headers';
}

sub _parse_chunked_trailing_headers {
Expand All @@ -317,20 +300,17 @@ sub _parse_chunked_trailing_headers {
$headers->parse($self->{pre_buffer});
$self->{pre_buffer} = '';

# Finished
if ($headers->is_finished) {

# Remove Transfer-Encoding
my $headers = $self->headers;
my $encoding = $headers->transfer_encoding;
$encoding =~ s/,?\s*chunked//ig;
$encoding
? $headers->transfer_encoding($encoding)
: $headers->remove('Transfer-Encoding');
$headers->content_length($self->{real_size});

$self->{chunked} = 'finished';
}
# Check if we are finished
return unless $headers->is_finished;
$self->{chunked_state} = 'finished';

# Replace Transfer-Encoding with Content-Length
my $encoding = $headers->transfer_encoding;
$encoding =~ s/,?\s*chunked//ig;
$encoding
? $headers->transfer_encoding($encoding)
: $headers->remove('Transfer-Encoding');
$headers->content_length($self->{real_size});
}

sub _parse_headers {
Expand All @@ -341,14 +321,14 @@ sub _parse_headers {
$headers->parse($self->{pre_buffer});
$self->{pre_buffer} = '';

# Finished
if ($headers->is_finished) {
my $leftovers = $headers->leftovers;
$self->{header_size} = $self->{raw_size} - length $leftovers;
$self->{pre_buffer} = $leftovers;
$self->{state} = 'body';
$self->_body;
}
# Check if we are finished
return unless $headers->is_finished;
$self->{state} = 'body';

# Take care of leftovers
my $leftovers = $self->{pre_buffer} = $headers->leftovers;
$self->{header_size} = $self->{raw_size} - length $leftovers;
$self->_body;
}

1;
Expand Down
4 changes: 2 additions & 2 deletions lib/Mojo/Transaction.pm
Expand Up @@ -49,8 +49,8 @@ sub remote_address {
# Reverse proxy
if ($ENV{MOJO_REVERSE_PROXY}) {
return $self->{forwarded_for} if $self->{forwarded_for};
($self->req->headers->header('X-Forwarded-For') || '') =~ /([^,\s]+)$/
and return $self->{forwarded_for} = $1;
my $forwarded = $self->req->headers->header('X-Forwarded-For') || '';
$forwarded =~ /([^,\s]+)$/ and return $self->{forwarded_for} = $1;
}

return $self->{remote_address};
Expand Down
4 changes: 2 additions & 2 deletions lib/Mojo/Transaction/WebSocket.pm
Expand Up @@ -223,8 +223,8 @@ sub server_handshake {
my $res_headers = $self->res->code(101)->headers;
$res_headers->upgrade('websocket')->connection('Upgrade');
my $req_headers = $self->req->headers;
($req_headers->sec_websocket_protocol || '') =~ /^\s*([^,]+)/;
$res_headers->sec_websocket_protocol($1) if $1;
($req_headers->sec_websocket_protocol || '') =~ /^\s*([^,]+)/
and $res_headers->sec_websocket_protocol($1);
$res_headers->sec_websocket_accept(
$self->_challenge($req_headers->sec_websocket_key));
}
Expand Down
2 changes: 1 addition & 1 deletion lib/Mojolicious/Plugin/DefaultHelpers.pm
@@ -1,7 +1,7 @@
package Mojolicious::Plugin::DefaultHelpers;
use Mojo::Base 'Mojolicious::Plugin';

require Data::Dumper;
use Data::Dumper ();

# "You're watching Futurama,
# the show that doesn't condone the cool crime of robbery."
Expand Down

0 comments on commit d773b22

Please sign in to comment.