Skip to content

Commit

Permalink
added xor_encode function to Mojo::Util
Browse files Browse the repository at this point in the history
  • Loading branch information
kraih committed Sep 5, 2012
1 parent 47b1fac commit 755b885
Show file tree
Hide file tree
Showing 10 changed files with 48 additions and 37 deletions.
2 changes: 2 additions & 0 deletions Changes
@@ -1,5 +1,7 @@

3.38 2012-09-05
- Added xor_encode method to Mojo::ByteStream.
- Added xor_encode function to Mojo::Util.
- Improved documentation.

3.37 2012-09-04
Expand Down
10 changes: 8 additions & 2 deletions lib/Mojo/ByteStream.pm
Expand Up @@ -13,7 +13,7 @@ my @UTILS = (
qw(b64_decode b64_encode camelize decamelize hmac_md5_sum hmac_sha1_sum),
qw(html_escape html_unescape md5_bytes md5_sum punycode_decode),
qw(punycode_encode quote sha1_bytes sha1_sum slurp spurt squish trim),
qw(unquote url_escape url_unescape xml_escape)
qw(unquote url_escape url_unescape xml_escape xor_encode)
);
{
no strict 'refs';
Expand Down Expand Up @@ -337,7 +337,13 @@ L<Mojo::Util/"url_unescape">.
$stream = $stream->xml_escape;
Escape only the characters C<&>, C<E<lt>>, C<E<gt>>, C<"> and C<'> in
bytestream, this is a much faster version of C<html_escape>.
bytestream with L<Mojo::Util/"xml_escape">.
=head2 C<xor_encode>
$stream = $stream->xor_encode($key);
XOR encode bytestream with L<Mojo::Util/"xor_encode">.
=head1 SEE ALSO
Expand Down
17 changes: 4 additions & 13 deletions lib/Mojo/Content.pm
Expand Up @@ -8,8 +8,6 @@ has [qw(auto_relax relaxed skip_body)];
has headers => sub { Mojo::Headers->new };
has max_leftover_size => sub { $ENV{MOJO_MAX_LEFTOVER_SIZE} || 262144 };

my $CHUNK_RE = qr/^((?:\x0d?\x0a)?([[:xdigit:]]+).*\x0d?\x0a)/;

sub body_contains {
croak 'Method "body_contains" not implemented by subclass';
}
Expand Down Expand Up @@ -44,8 +42,7 @@ sub generate_body_chunk {
if !delete $self->{delay} && !length $self->{body_buffer};

# Get chunk
my $chunk = $self->{body_buffer} // '';
$self->{body_buffer} = '';
my $chunk = delete $self->{body_buffer} // '';

# EOF or delay
return $self->{eof} ? '' : undef unless length $chunk;
Expand Down Expand Up @@ -244,7 +241,7 @@ sub _parse_chunked {
if ($self->{chunk_state} // '') eq 'trailing_headers';

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

Expand Down Expand Up @@ -277,10 +274,7 @@ sub _parse_chunked_trailing_headers {
my $self = shift;

# Parse
my $headers = $self->headers->parse($self->{pre_buffer});
$self->{pre_buffer} = '';

# Check if we are finished
my $headers = $self->headers->parse(delete $self->{pre_buffer});
return unless $headers->is_finished;
$self->{chunk_state} = 'finished';

Expand All @@ -297,10 +291,7 @@ sub _parse_headers {
my $self = shift;

# Parse
my $headers = $self->headers->parse($self->{pre_buffer});
$self->{pre_buffer} = '';

# Check if we are finished
my $headers = $self->headers->parse(delete $self->{pre_buffer});
return unless $headers->is_finished;
$self->{state} = 'body';

Expand Down
2 changes: 1 addition & 1 deletion lib/Mojo/Content/Single.pm
Expand Up @@ -45,7 +45,7 @@ sub parse {

# Parse body
return $self->SUPER::parse
unless $self->auto_upgrade && defined($self->boundary);
unless $self->auto_upgrade && defined $self->boundary;

# Content needs to be upgraded to multipart
$self->unsubscribe(read => $self->{read});
Expand Down
4 changes: 2 additions & 2 deletions lib/Mojo/Exception.pm
Expand Up @@ -62,7 +62,7 @@ sub _context {
# Before
for my $i (2 .. 6) {
last if ((my $previous = $line - $i) < 0);
if (defined($lines->[0][$previous])) {
if (defined $lines->[0][$previous]) {
unshift @{$self->lines_before}, [$previous + 1];
for my $l (@$lines) {
chomp(my $code = $l->[$previous]);
Expand All @@ -74,7 +74,7 @@ sub _context {
# After
for my $i (0 .. 4) {
next if ((my $next = $line + $i) < 0);
if (defined($lines->[0][$next])) {
if (defined $lines->[0][$next]) {
push @{$self->lines_after}, [$next + 1];
for my $l (@$lines) {
next unless defined(my $code = $l->[$next]);
Expand Down
4 changes: 2 additions & 2 deletions lib/Mojo/Headers.pm
Expand Up @@ -296,8 +296,8 @@ Shortcut for the C<Content-Encoding> header.
=head2 C<content_length>
my $length = $headers->content_length;
$headers = $headers->content_length(4000);
my $len = $headers->content_length;
$headers = $headers->content_length(4000);
Shortcut for the C<Content-Length> header.
Expand Down
16 changes: 3 additions & 13 deletions lib/Mojo/Transaction/WebSocket.pm
Expand Up @@ -3,7 +3,7 @@ use Mojo::Base 'Mojo::Transaction';

use Config;
use Mojo::Transaction::HTTP;
use Mojo::Util qw(b64_encode decode encode sha1_bytes);
use Mojo::Util qw(b64_encode decode encode sha1_bytes xor_encode);

use constant DEBUG => $ENV{MOJO_WEBSOCKET_DEBUG} || 0;

Expand Down Expand Up @@ -73,7 +73,7 @@ sub build_frame {
# Mask payload
if ($masked) {
my $mask = pack 'N', int(rand 9999999);
$payload = $mask . _xor_mask($payload, $mask);
$payload = $mask . xor_encode($payload, $mask x 128);
}

return $frame . $payload;
Expand Down Expand Up @@ -173,7 +173,7 @@ sub parse_frame {
my $payload = $len ? substr($clone, 0, $len, '') : '';

# Unmask payload
$payload = _xor_mask($payload, substr($payload, 0, 4, '')) if $masked;
$payload = xor_encode($payload, substr($payload, 0, 4, '') x 128) if $masked;
warn "$payload\n" if DEBUG;
$$buffer = $clone;

Expand Down Expand Up @@ -283,16 +283,6 @@ sub _message {
$self->emit(message => $msg);
}

sub _xor_mask {
my ($input, $mask) = @_;

# 512 byte mask
$mask = $mask x 128;
my $output = '';
$output .= $_ ^ $mask while length($_ = substr($input, 0, 512, '')) == 512;
return $output .= $_ ^ substr($mask, 0, length, '');
}

1;

=head1 NAME
Expand Down
16 changes: 15 additions & 1 deletion lib/Mojo/Util.pm
Expand Up @@ -40,7 +40,7 @@ our @EXPORT_OK = (
qw(decode encode get_line hmac_md5_sum hmac_sha1_sum html_escape),
qw(html_unescape md5_bytes md5_sum punycode_decode punycode_encode quote),
qw(secure_compare sha1_bytes sha1_sum slurp spurt squish trim unquote),
qw(url_escape url_unescape xml_escape)
qw(url_escape url_unescape xml_escape xor_encode)
);

sub b64_decode { decode_base64(shift) }
Expand Down Expand Up @@ -322,6 +322,14 @@ sub xml_escape {
return $string;
}

sub xor_encode {
my ($input, $key) = @_;
my $len = length $key;
my $output = '';
$output .= $_ ^ $key while length($_ = substr($input, 0, $len, '')) == $len;
return $output .= $_ ^ substr($key, 0, length, '');
}

sub _adapt {
my ($delta, $numpoints, $firsttime) = @_;

Expand Down Expand Up @@ -600,6 +608,12 @@ Decode percent encoded characters in string.
Escape only the characters C<&>, C<E<lt>>, C<E<gt>>, C<"> and C<'> in string,
this is a much faster version of C<html_escape>.
=head2 C<xor_encode>
my $encoded = xor_encode $string, $key;
XOR encode string.
=head1 SEE ALSO
L<Mojolicious>, L<Mojolicious::Guides>, L<http://mojolicio.us>.
Expand Down
6 changes: 5 additions & 1 deletion t/mojo/bytestream.t
Expand Up @@ -2,7 +2,7 @@ use Mojo::Base -strict;

use utf8;

use Test::More tests => 45;
use Test::More tests => 47;

use File::Spec::Functions qw(catfile splitdir);
use File::Temp 'tempdir';
Expand Down Expand Up @@ -93,6 +93,10 @@ is b('Hi there')->hmac_sha1_sum(1234567890),
ok b('hello')->secure_compare('hello'), 'values are equal';
ok !b('hell')->secure_compare('hello'), 'values are not equal';

# xor_encode
is b('hello')->xor_encode('foo'), "\x0e\x0a\x03\x0a\x00", 'right result';
is b("\x0e\x0a\x03\x0a\x00")->xor_encode('foo'), 'hello', 'right result';

# Nested bytestreams
my $stream = b(b('test'));
ok !ref $stream->to_string, 'nested bytestream stringified';
Expand Down
8 changes: 6 additions & 2 deletions t/mojo/util.t
Expand Up @@ -2,7 +2,7 @@ use Mojo::Base -strict;

use utf8;

use Test::More tests => 148;
use Test::More tests => 150;

use File::Spec::Functions qw(catfile splitdir);
use File::Temp 'tempdir';
Expand All @@ -13,7 +13,7 @@ use Mojo::Util
qw(decode encode get_line hmac_md5_sum hmac_sha1_sum html_escape),
qw(html_unescape md5_bytes md5_sum punycode_decode punycode_encode quote),
qw(squish trim unquote secure_compare sha1_bytes sha1_sum slurp spurt),
qw(url_escape url_unescape xml_escape);
qw(url_escape url_unescape xml_escape xor_encode);

# camelize
is camelize('foo_bar_baz'), 'FooBarBaz', 'right camelized result';
Expand Down Expand Up @@ -366,6 +366,10 @@ ok !secure_compare('♥', '♥0'), 'values are not equal';
ok !secure_compare('0♥', ''), 'values are not equal';
ok !secure_compare('0♥1', '1♥0'), 'values are not equal';

# xor_encode
is xor_encode('hello', 'foo'), "\x0e\x0a\x03\x0a\x00", 'right result';
is xor_encode("\x0e\x0a\x03\x0a\x00", 'foo'), 'hello', 'right result';

# slurp
is slurp(catfile(splitdir($FindBin::Bin), qw(templates exception.mt))),
"test\n% die;\n123\n", 'right content';
Expand Down

0 comments on commit 755b885

Please sign in to comment.