From 717333d3aabc8cb730ff2bc4ace117fc956dc697 Mon Sep 17 00:00:00 2001 From: Sebastian Riedel Date: Mon, 2 Nov 2009 19:44:40 +0100 Subject: [PATCH] added input streaming support to Mojo::Content --- Changes | 1 + lib/Mojo/Command/Cgi.pm | 2 +- lib/Mojo/Command/Get.pm | 84 +++++++++++++++++++++++++++++++++++ lib/Mojo/Content.pm | 39 ++++++++++++++++ lib/Mojo/Content/MultiPart.pm | 10 +++-- lib/Mojo/Content/Single.pm | 10 +---- 6 files changed, 134 insertions(+), 12 deletions(-) create mode 100644 lib/Mojo/Command/Get.pm diff --git a/Changes b/Changes index 51ba6f790e..867be671fe 100644 --- a/Changes +++ b/Changes @@ -20,6 +20,7 @@ This file documents the revision history for Perl extension Mojo. - Added callback tests. (melo) - Added support for MOJO_CHUNK_SIZE=1. (melo) - Added not_found.html.* templates. + - Added input streaming support to Mojo::Content. - Updated Mojolicious lite_app generator to use .ep templates. - Fixed param to be CGI.pm compatible. - Fixed a few cases where exceptions and not found events would diff --git a/lib/Mojo/Command/Cgi.pm b/lib/Mojo/Command/Cgi.pm index 25e105e494..7b2859db7a 100644 --- a/lib/Mojo/Command/Cgi.pm +++ b/lib/Mojo/Command/Cgi.pm @@ -33,7 +33,7 @@ sub run { # Run $cgi->run; - return shift; + return $self; } 1; diff --git a/lib/Mojo/Command/Get.pm b/lib/Mojo/Command/Get.pm new file mode 100644 index 0000000000..c2b2218f01 --- /dev/null +++ b/lib/Mojo/Command/Get.pm @@ -0,0 +1,84 @@ +# Copyright (C) 2008-2009, Sebastian Riedel. + +package Mojo::Command::Get; + +use strict; +use warnings; + +use base 'Mojo::Command'; + +use Mojo::Client; +use Mojo::Transaction::Single; + +__PACKAGE__->attr(description => <<'EOF'); +Get file from URL. +EOF +__PACKAGE__->attr(usage => <<"EOF"); +usage: $0 get [URL] +EOF + +# I hope this has taught you kids a lesson: kids never learn. +sub run { + my ($self, $url) = @_; + + # URL + die $self->usage unless $url; + + # Client + my $client = Mojo::Client->new; + + # Transaction + my $tx = Mojo::Transaction::Single->new; + $tx->req->method('GET'); + $tx->req->url->parse($url); + $tx->res->body(sub { print $_[1] }); + + # Request + $client->process($tx); + + return $self; +} + +1; +__END__ + +=head1 NAME + +Mojo::Command::Get - Get Command + +=head1 SYNOPSIS + + use Mojo::Command::Get; + + my $get = Mojo::Command::Get->new; + $get->run(@ARGV); + +=head1 DESCRIPTION + +L is a command interface to L. + +=head1 ATTRIBUTES + +L inherits all attributes from L and +implements the following new ones. + +=head2 C + + my $description = $get->description; + $get = $get->description('Foo!'); + +=head2 C + + my $usage = $get->usage; + $get = $get->usage('Foo!'); + +=head1 METHODS + +L inherits all methods from L and implements +the following new ones. + +=head2 C + + $get = $get->run(@ARGV); + +=cut diff --git a/lib/Mojo/Content.pm b/lib/Mojo/Content.pm index 6dfcfe2f0e..68a2d9af6d 100644 --- a/lib/Mojo/Content.pm +++ b/lib/Mojo/Content.pm @@ -19,7 +19,9 @@ __PACKAGE__->attr([qw/body_cb filter progress_cb/]); __PACKAGE__->attr([qw/buffer filter_buffer/] => sub { Mojo::Buffer->new }); __PACKAGE__->attr(headers => sub { Mojo::Headers->new }); __PACKAGE__->attr(raw_header_size => 0); +__PACKAGE__->attr(relaxed => 0); +__PACKAGE__->attr(_body_size => 0); __PACKAGE__->attr('_eof'); sub body_contains { @@ -180,6 +182,38 @@ sub parse { # Not chunked, pass through else { $self->buffer($self->filter_buffer) } + # Custom body parser + if (my $cb = $self->body_cb) { + + # Chunked or relaxed content + if ($self->is_chunked || $self->relaxed) { + $self->$cb($self->buffer->empty); + } + + # Normal content + else { + + # Need + my $length = $self->headers->content_length || 0; + my $need = $length - $self->_body_size; + + # Slurp + if ($need > 0) { + my $chunk = $self->buffer->remove($need); + $self->_body_size($self->_body_size + length $chunk); + $self->$cb($chunk); + } + + # Done + $self->done if $length <= $self->raw_body_size; + } + } + + # Leftovers + if ($self->is_done) { + $self->state('done_with_leftovers') if $self->has_leftovers; + } + return $self; } @@ -294,6 +328,11 @@ implements the following new ones. print '+'; }); +=head2 C + + my $relaxed = $content->relaxed; + $content = $content->relaxed(1); + =head2 C my $size = $content->raw_header_size; diff --git a/lib/Mojo/Content/MultiPart.pm b/lib/Mojo/Content/MultiPart.pm index 87de487411..7e7a0c4c4b 100644 --- a/lib/Mojo/Content/MultiPart.pm +++ b/lib/Mojo/Content/MultiPart.pm @@ -128,12 +128,16 @@ sub get_body_chunk { sub parse { my $self = shift; - # Upgrade state - $self->state('multipart_preamble') if $self->is_state('body'); - # Parse headers and filter body $self->SUPER::parse(@_); + # Custom body parser + return $self if $self->body_cb; + + # Upgrade state + $self->state('multipart_preamble') if $self->is_state('body'); + + # Parse multipart content $self->_parse_multipart; return $self; diff --git a/lib/Mojo/Content/Single.pm b/lib/Mojo/Content/Single.pm index f5e2d0cb5a..082374e258 100644 --- a/lib/Mojo/Content/Single.pm +++ b/lib/Mojo/Content/Single.pm @@ -15,7 +15,6 @@ use Mojo::Content::MultiPart; use constant MAX_MEMORY_SIZE => $ENV{MOJO_MAX_MEMORY_SIZE} || 10240; __PACKAGE__->attr(asset => sub { Mojo::Asset::Memory->new }); -__PACKAGE__->attr(relaxed => 0); sub body_contains { my ($self, $chunk) = @_; @@ -48,8 +47,8 @@ sub parse { # Parse headers and filter body $self->SUPER::parse(@_); - # Still parsing headers - return $self if $self->is_state('headers'); + # Still parsing headers or using a custom body parser + return $self if $self->is_state('headers') || $self->body_cb; # Make sure we don't waste memory if ($self->asset->isa('Mojo::Asset::Memory')) { @@ -121,11 +120,6 @@ implements the following new ones. my $asset = $content->asset; $content = $content->asset(Mojo::Asset::Memory->new); -=head2 C - - my $relaxed = $content->relaxed; - $content = $content->relaxed(1); - =head1 METHODS L inherits all methods from L and