Skip to content

Commit

Permalink
fixed a serious design flaw in Mojo::Message and made long poll much …
Browse files Browse the repository at this point in the history
…easier
  • Loading branch information
kraih committed Aug 20, 2010
1 parent fce6507 commit 343e489
Show file tree
Hide file tree
Showing 15 changed files with 299 additions and 140 deletions.
2 changes: 2 additions & 0 deletions Changes
Expand Up @@ -4,6 +4,8 @@ This file documents the revision history for Perl extension Mojolicious.
- Added EXPERIMENTAL support for --mode and --home options to all
Mojolicious commands.
- Added while and until methods for Mojo::DOM collections. (vti)
- Fixed a serious design flaw in Mojo::Message and made long poll
much easier.
- Fixed a bug where Mojo::IOLoop connections could be closed too
early.
- Fixed HTTPS support for CGI environments.
Expand Down
107 changes: 70 additions & 37 deletions lib/Mojo/Content.pm
Expand Up @@ -12,7 +12,7 @@ use Mojo::Headers;

use constant CHUNK_SIZE => $ENV{MOJO_CHUNK_SIZE} || 262144;

__PACKAGE__->attr([qw/body_cb filter/]);
__PACKAGE__->attr([qw/filter read_cb/]);
__PACKAGE__->attr([qw/buffer filter_buffer/] => sub { Mojo::ByteStream->new }
);
__PACKAGE__->attr(headers => sub { Mojo::Headers->new });
Expand Down Expand Up @@ -70,32 +70,21 @@ sub build_headers {
return $headers;
}

sub finish { shift->{_eof} = 1 }

sub generate_body_chunk {
my ($self, $offset) = @_;

# Shortcut
return '' unless $self->body_cb;

# Remove written
# Buffer
my $buffer = $self->buffer;
my $written = $offset - ($buffer->raw_size - $buffer->size);
$buffer->remove($written);

# Fill buffer
if (!$self->{_eof} && $buffer->size < CHUNK_SIZE) {

# Generate
my $chunk = $self->body_cb->($self, $buffer->raw_size);

# EOF
if (defined $chunk && !length $chunk) { $self->{_eof} = 1 }

# Buffer chunk
else { $buffer->add_chunk($chunk) }
# Callback
if (!$buffer->size && (my $cb = delete $self->{_drain})) {
$self->$cb($offset);
}

# Get chunk
my $chunk = $buffer->to_string;
my $chunk = $buffer->empty;

# Pause or EOF
return $self->{_eof} ? '' : undef unless length $chunk;
Expand Down Expand Up @@ -198,7 +187,7 @@ sub parse {
else { $self->buffer($fbuffer) }

# Custom body parser
if (my $cb = $self->body_cb) {
if (my $cb = $self->read_cb) {

# Chunked or relaxed content
if ($self->is_chunked || $self->relaxed) {
Expand Down Expand Up @@ -276,6 +265,32 @@ sub raw_body_size {
return $length - $header_length;
}

sub write {
my ($self, $chunk, $cb) = @_;

# Dynamic content
$self->read_cb(sub { });

# Buffer
$self->buffer->add_chunk($chunk);

# Drain callback
$self->{_drain} = $cb if $cb;
}

sub write_chunk {
my ($self, $chunk, $cb) = @_;

# Filter
$self->filter(Mojo::Filter::Chunked->new) unless $self->filter;

# Chunked transfer encoding
$self->headers->transfer_encoding('chunked') unless $self->is_chunked;

# Write
$self->write(defined $chunk ? $self->filter->build($chunk) : '', $cb);
}

sub _build_headers {
my $self = shift;

Expand Down Expand Up @@ -327,22 +342,6 @@ in RFC 2616.
L<Mojo::Content> implements the following attributes.
=head2 C<body_cb>
my $cb = $content->body_cb;
$counter = 1;
$content = $content->body_cb(sub {
my $self = shift;
my $chunk = '';
$chunk = "hello world!" if $counter == 1;
$chunk = "hello world2!\n\n" if $counter == 2;
$counter++;
return $chunk;
});
Content generator callback.
=head2 C<buffer>
my $buffer = $content->buffer;
Expand Down Expand Up @@ -371,6 +370,18 @@ Input buffer for filtering.
The headers.
=head2 C<read_cb>
my $cb = $content->read_cb;
$content = $content->read_cb(sub {...});
Content parser callback.
$content = $content->read_cb(sub {
my ($self, $chunk) = @_;
print $chunk;
});
=head2 C<relaxed>
my $relaxed = $content->relaxed;
Expand Down Expand Up @@ -413,11 +424,17 @@ Render whole body.
Render all headers.
=head2 C<finish>
$content->finish;
Finish dynamic content generation.
=head2 C<generate_body_chunk>
my $chunk = $content->generate_body_chunk(0);
Generate content from C<body_cb>.
Generate dynamic content.
=head2 C<get_body_chunk>
Expand Down Expand Up @@ -505,6 +522,22 @@ Parse and stop after headers.
Raw size of body in bytes.
=head2 C<write>
$content->write('Hello!');
$content->write('Hello!', sub {...});
Write dynamic content, the optional drain callback will be invoked once all
data has been written.
=head2 C<write_chunk>
$content->write_chunk('Hello!');
$content->write_chunk('Hello!', sub {...});
Write chunked content, the optional drain callback will be invoked once all
data has been written.
=head1 SEE ALSO
L<Mojolicious>, L<Mojolicious::Guides>, L<http://mojolicious.org>.
Expand Down
4 changes: 2 additions & 2 deletions lib/Mojo/Content/MultiPart.pm
Expand Up @@ -90,7 +90,7 @@ sub get_body_chunk {
my ($self, $offset) = @_;

# Body generator
return $self->generate_body_chunk($offset) if $self->body_cb;
return $self->generate_body_chunk($offset) if $self->read_cb;

# Multipart
my $boundary = $self->build_boundary;
Expand Down Expand Up @@ -138,7 +138,7 @@ sub parse {
$self->SUPER::parse(@_);

# Custom body parser
return $self if $self->body_cb;
return $self if $self->read_cb;

# Upgrade state
$self->{_state} = 'multipart_preamble'
Expand Down
4 changes: 2 additions & 2 deletions lib/Mojo/Content/Single.pm
Expand Up @@ -27,7 +27,7 @@ sub get_body_chunk {
my ($self, $offset) = @_;

# Body generator
return $self->generate_body_chunk($offset) if $self->body_cb;
return $self->generate_body_chunk($offset) if $self->read_cb;

# Normal content
return $self->asset->get_chunk($offset);
Expand All @@ -40,7 +40,7 @@ sub parse {
$self->SUPER::parse(@_);

# Still parsing headers or using a custom body parser
return $self if ($self->{_state} || '') eq 'headers' || $self->body_cb;
return $self if ($self->{_state} || '') eq 'headers' || $self->read_cb;

# Headers
my $headers = $self->headers;
Expand Down
19 changes: 8 additions & 11 deletions lib/Mojo/HelloWorld.pm
Expand Up @@ -5,7 +5,6 @@ use warnings;

use base 'Mojo';

use Mojo::Filter::Chunked;
use Mojo::JSON;

# How is education supposed to make me feel smarter? Besides,
Expand Down Expand Up @@ -49,16 +48,14 @@ sub _chunked_params {
}

# Callback
my $counter = 0;
my $chunked = Mojo::Filter::Chunked->new;
$tx->res->body(
sub {
my $self = shift;
my $chunk = $chunks->[$counter] || '';
$counter++;
return $chunked->build($chunk);
}
);
my $cb;
$cb = sub {
my $self = shift;
my $chunk = shift @$chunks || '';
$self->write_chunk($chunk, $chunk ? $cb : undef);
$self->finish unless $chunk;
};
$cb->($tx->res);
}

sub _diag {
Expand Down

0 comments on commit 343e489

Please sign in to comment.