Changeset 13439
- Timestamp:
- 06/08/08 06:23:24 (5 years ago)
- Location:
- lang/perl/HTTP-Engine/branches/lazy_request/lib/HTTP/Engine
- Files:
-
- 2 added
- 7 modified
-
Interface/Standalone (added)
-
Interface/Standalone.pm (modified) (9 diffs)
-
Interface/Standalone/RequestBuilder.pm (added)
-
Request.pm (modified) (2 diffs)
-
RequestBuilder.pm (modified) (10 diffs)
-
RequestProcessor.pm (modified) (2 diffs)
-
ResponseWriter.pm (modified) (1 diff)
-
Role/Interface.pm (modified) (5 diffs)
-
Role/RequestBuilder/ReadBody.pm (modified) (5 diffs)
Legend:
- Unmodified
- Added
- Removed
-
lang/perl/HTTP-Engine/branches/lazy_request/lib/HTTP/Engine/Interface/Standalone.pm
r11845 r13439 3 3 with 'HTTP::Engine::Role::Interface'; 4 4 5 use Errno 'EWOULDBLOCK';6 5 use Socket qw(:all); 7 6 use IO::Socket::INET (); … … 46 45 ); 47 46 48 49 use HTTP::Engine::ResponseWriter;50 HTTP::Engine::RequestBuilder->meta->add_method( _read_chunk => sub {51 shift;52 # support for non-blocking IO53 my $rin = '';54 vec($rin, *STDIN->fileno, 1) = 1;55 56 READ:57 {58 select($rin, undef, undef, undef); ## no critic.59 my $rc = *STDIN->sysread(@_);60 if (defined $rc) {61 return $rc;62 } else {63 next READ if $! == EWOULDBLOCK;64 return;65 }66 }67 });68 69 HTTP::Engine::RequestBuilder->meta->add_before_method_modifier( _prepare_read => sub {70 my $self = shift;71 # Set the input handle to non-blocking72 *STDIN->blocking(0);73 });74 75 use HTTP::Engine::ResponseWriter;76 my $is_keepalive;77 HTTP::Engine::ResponseWriter->meta->add_before_method_modifier( finalize => sub {78 my($self, $c) = @_;79 80 $c->res->headers->date(time);81 $c->res->headers->header(82 Connection => $is_keepalive ? 'keep-alive' : 'close'83 );84 });85 86 47 sub run { 87 my ($self,) = @_;88 89 $ is_keepalive = sub { $self->keepalive };48 my ( $self ) = @_; 49 50 $self->response_writer->keepalive( $self->keepalive ); 90 51 91 52 my $host = $self->host; … … 119 80 my $pid = undef; 120 81 local $SIG{CHLD} = 'IGNORE'; 121 while (accept(Remote, $daemon)) { 82 83 while (my $remote = $daemon->accept) { 122 84 # TODO (Catalyst): get while ( my $remote = $daemon->accept ) to work 123 85 delete $self->{_sigpipe}; 124 select Remote; 125 126 # Request data 127 Remote->blocking(1); 128 129 next unless my($method, $uri, $protocol) = $self->_parse_request_line(\*Remote); 86 87 next unless my($method, $uri, $protocol) = $self->_parse_request_line($remote); 130 88 unless (uc $method eq 'RESTART') { 131 89 # Fork 132 90 next if $self->fork && ($pid = fork); 133 $self->_handler($ port, $method, $uri, $protocol);91 $self->_handler($remote, $port, $method, $uri, $protocol); 134 92 $daemon->close if defined $pid; 135 93 } else { 136 my $sockdata = $self->_socket_data( \*Remote);94 my $sockdata = $self->_socket_data($remote); 137 95 my $ipaddr = _inet_addr($sockdata->{peeraddr}); 138 96 my $ready = 0; … … 149 107 exit if defined $pid; 150 108 } continue { 151 close Remote;109 close $remote; 152 110 } 153 111 $daemon->close; … … 163 121 164 122 sub _handler { 165 my($self, $ port, $method, $uri, $protocol) = @_;123 my($self, $remote, $port, $method, $uri, $protocol) = @_; 166 124 167 125 # Ignore broken pipes as an HTTP server should 168 local $SIG{PIPE} = sub { $self->{_sigpipe} = 1; close Remote }; 169 170 local *STDIN = \*Remote; 171 local *STDOUT = \*Remote; 126 local $SIG{PIPE} = sub { $self->{_sigpipe} = 1; close $remote }; 172 127 173 128 # We better be careful and just use 1.0 174 129 $protocol = '1.0'; 175 130 176 my $sockdata = $self->_socket_data( \*Remote);131 my $sockdata = $self->_socket_data($remote); 177 132 my %copy_of_env = %ENV; 178 133 179 134 my $sel = IO::Select->new; 180 $sel->add(\*STDIN); 135 $sel->add($remote); 136 137 $remote->autoflush(1); 181 138 182 139 while (1) { 140 # FIXME refactor an HTTP push parser 183 141 my($path, $query_string) = split /\?/, $uri, 2; 184 142 185 # Initialize CGI environment 186 local %ENV = ( 143 my %env = ( 187 144 PATH_INFO => $path || '', 188 145 QUERY_STRING => $query_string || '', … … 193 150 SERVER_PORT => $port, 194 151 SERVER_PROTOCOL => "HTTP/$protocol", 195 %copy_of_env,196 152 ); 197 153 154 my $headers; 155 198 156 # Parse headers 157 # taken from HTTP::Message, which is unfortunately not really reusable 199 158 if ($protocol >= 1) { 200 while (1) { 201 my $line = $self->_get_line(\*STDIN); 202 last if $line eq ''; 203 next unless my ( $name, $value ) = $line =~ m/\A(\w(?:-?\w+)*):\s(.+)\z/; 204 205 $name = uc $name; 206 $name = 'COOKIE' if $name eq 'COOKIES'; 207 $name =~ tr/-/_/; 208 $name = 'HTTP_' . $name unless $name =~ m/\A(?:CONTENT_(?:LENGTH|TYPE)|COOKIE)\z/; 209 if (exists $ENV{$name}) { 210 $ENV{$name} .= "; $value"; 159 my @hdr; 160 while ( length(my $line = $self->_get_line($remote)) ) { 161 if ($line =~ s/^([^\s:]+)[ \t]*: ?(.*)//) { 162 push(@hdr, $1, $2); 163 } 164 elsif (@hdr && $line =~ s/^([ \t].*)//) { 165 $hdr[-1] .= "\n$1"; 211 166 } else { 212 $ENV{$name} = $value;167 last; 213 168 } 214 169 } 170 $headers = HTTP::Headers->new(@hdr); 171 } else { 172 $headers = HTTP::Headers->new; 215 173 } 174 216 175 # Pass flow control to HTTP::Engine 217 $self->handle_request; 218 219 my $connection = lc $ENV{HTTP_CONNECTION}; 176 $self->handle_request( 177 uri => URI::WithBase->new($uri), 178 headers => $headers, 179 method => $method, 180 address => $sockdata->{peeraddr}, 181 port => $port, 182 protocol => "HTTP/$protocol", 183 user => undef, 184 https_info => undef, 185 _connection => { 186 handle => $remote, 187 env => {}, # no more env than what we provide 188 }, 189 ); 190 191 my $connection = $headers->header("Connection"); 192 220 193 last 221 194 unless $self->keepalive … … 224 197 && $sel->can_read(5); 225 198 226 last unless ($method, $uri, $protocol) = $self->_parse_request_line( \*STDIN, 1);227 } 228 229 sysread(Remote, my $buf, 4096) if $sel->can_read(0); # IE bk230 close Remote;199 last unless ($method, $uri, $protocol) = $self->_parse_request_line($remote, 1); 200 } 201 202 $self->request_builder->_io_read($remote, my $buf, 4096) if $sel->can_read(0); # IE bk 203 close $remote; 231 204 } 232 205 … … 254 227 255 228 my $data = { 256 peername => gethostbyaddr($iaddr, AF_INET) || "localhost",257 229 peeraddr => inet_ntoa($iaddr) || "127.0.0.1", 258 localname => gethostbyaddr($localiaddr, AF_INET) || "localhost",259 230 localaddr => inet_ntoa($localiaddr) || "127.0.0.1", 260 231 }; … … 266 237 my($self, $handle) = @_; 267 238 239 # FIXME use bufferred but nonblocking IO? this is a lot of calls =( 268 240 my $line = ''; 269 while ( sysread($handle, my $byte, 1)) {241 while ($self->request_builder->_io_read($handle, my $byte, 1)) { 270 242 last if $byte eq "\012"; # eol 271 243 $line .= $byte; 272 244 } 273 1 while $line =~ s/\s\z//; 245 246 # strip \r, \n was already stripped 247 $line =~ s/\015$//s; 274 248 275 249 $line; -
lang/perl/HTTP-Engine/branches/lazy_request/lib/HTTP/Engine/Request.pm
r13418 r13439 17 17 } 18 18 } 19 20 has _connection => ( 21 is => "ro", 22 lazy_build => 1, 23 ); 24 25 sub _build__request_state { 26 my $self = shift; 27 $self->request_builder->_build_request_state($self); 28 } 29 30 has "_read_state" => ( 31 is => "rw", 32 lazy_build => 1, 33 ); 34 35 sub _build__read_state { 36 my $self = shift; 37 $self->request_builder->_build_read_state($self); 38 } 39 40 19 41 has request_builder => ( 20 42 does => "HTTP::Engine::Role::RequestBuilder", … … 143 165 my $self = shift; 144 166 $self->request_builder->_build_hostname; 145 }146 147 has "_read_state" => (148 is => "rw",149 lazy_build => 1,150 );151 152 sub _build__read_state {153 my $self = shift;154 $self->request_builder->_build_read_state($self);155 167 } 156 168 -
lang/perl/HTTP-Engine/branches/lazy_request/lib/HTTP/Engine/RequestBuilder.pm
r13418 r13439 19 19 ); 20 20 21 has read_length => (22 is => 'rw',23 isa => 'Int',24 );25 26 has read_position => (27 is => 'rw',28 isa => 'Int',29 );30 31 21 no Moose; 22 23 sub _build_connection { 24 warn "Building default request state"; 25 26 return { 27 env => \%ENV, 28 handle => \*STDIN, 29 } 30 } 32 31 33 32 sub _build_connection_info { 34 33 my($self, $req) = @_; 35 34 35 warn "building connection info"; 36 37 my $env = $self->_connection->{env}; 38 36 39 return { 37 address => $ ENV{REMOTE_ADDR},38 protocol => $ ENV{SERVER_PROTOCOL},39 method => $ ENV{REQUEST_METHOD},40 port => $ ENV{SERVER_PORT},41 user => $ ENV{REMOTE_USER},42 https_info => $ ENV{HTTPS},40 address => $env->{REMOTE_ADDR}, 41 protocol => $env->{SERVER_PROTOCOL}, 42 method => $env->{REQUEST_METHOD}, 43 port => $env->{SERVER_PORT}, 44 user => $env->{REMOTE_USER}, 45 https_info => $env->{HTTPS}, 43 46 } 44 47 } … … 46 49 sub _build_headers { 47 50 my ($self, $req) = @_; 51 52 my $env = $req->_connection->{env}; 48 53 49 54 HTTP::Headers->new( 50 55 map { 51 56 (my $field = $_) =~ s/^HTTPS?_//; 52 ( $field => $ ENV{$_} );57 ( $field => $env->{$_} ); 53 58 } 54 grep { /^(?:HTTP|CONTENT|COOKIE)/i } keys % ENV59 grep { /^(?:HTTP|CONTENT|COOKIE)/i } keys %$env 55 60 ); 56 61 } … … 58 63 sub _build_hostname { 59 64 my ( $self, $req ) = @_; 60 $ ENV{REMOTE_HOST} || $self->_resolve_hostname($req);65 $req->_connection->{env}{REMOTE_HOST} || $self->_resolve_hostname($req); 61 66 } 62 67 … … 64 69 my($self, $req) = @_; 65 70 71 my $env = $req->_connection->{env}; 72 66 73 my $scheme = $req->secure ? 'https' : 'http'; 67 my $host = $ ENV{HTTP_HOST} || $ENV{SERVER_NAME};68 my $port = $ ENV{SERVER_PORT} || ( $req->secure ? 443 : 80 );74 my $host = $env->{HTTP_HOST} || $env->{SERVER_NAME}; 75 my $port = $env->{SERVER_PORT} || ( $req->secure ? 443 : 80 ); 69 76 70 77 my $base_path; 71 if (exists $ ENV{REDIRECT_URL}) {72 $base_path = $ ENV{REDIRECT_URL};73 $base_path =~ s/$ ENV{PATH_INFO}$//;78 if (exists $env->{REDIRECT_URL}) { 79 $base_path = $env->{REDIRECT_URL}; 80 $base_path =~ s/$env->{PATH_INFO}$//; 74 81 } else { 75 $base_path = $ ENV{SCRIPT_NAME} || '/';76 } 77 78 my $path = $base_path . ($ ENV{PATH_INFO} || '');82 $base_path = $env->{SCRIPT_NAME} || '/'; 83 } 84 85 my $path = $base_path . ($env->{PATH_INFO} || ''); 79 86 $path =~ s{^/+}{}; 80 87 … … 84 91 $uri->port($port); 85 92 $uri->path($path); 86 $uri->query($ ENV{QUERY_STRING}) if $ENV{QUERY_STRING};93 $uri->query($env->{QUERY_STRING}) if $env->{QUERY_STRING}; 87 94 88 95 # sanitize the URI … … 101 108 my($self, $req) = @_; 102 109 110 use Data::Dumper; 111 warn Dumper($req->headers); 112 103 113 my $length = $req->header('Content-Length') || 0; 104 114 my $type = $req->header('Content-Type'); … … 107 117 $body->{tmpdir} = $self->upload_tmp if $self->upload_tmp; 108 118 109 return {110 handle => *STDIN,119 return $self->_read_init({ 120 handle => $req->_connection->{handle}, 111 121 content_length => $length, 112 122 read_position => 0, … … 115 125 http_body => $body, 116 126 }, 117 } ;127 }); 118 128 } 119 129 … … 121 131 my ( $self, $req ) = @_; 122 132 133 warn "constructing body"; 123 134 $self->_read_to_end($req->_read_state); 124 135 … … 129 140 my ( $self, $req ) = @_; 130 141 142 warn "constructing raw"; 131 143 $self->_read_to_end($req->_read_state); 132 144 -
lang/perl/HTTP-Engine/branches/lazy_request/lib/HTTP/Engine/RequestProcessor.pm
r13420 r13439 57 57 my $rp; 58 58 sub handle_request { 59 my $self = shift;59 my ( $self, @args ) = @_; 60 60 61 61 my $context = $self->context_class->new( 62 req => $self->request_class->new( request_builder => $self->request_builder ), 63 res => $self->response_class->new(), 62 req => $self->request_class->new( 63 request_builder => $self->request_builder, 64 @args, 65 ), 66 res => $self->response_class->new(@args), 67 @args, 64 68 ); 65 69 … … 73 77 print STDERR $e; 74 78 } 79 75 80 $self->response_writer->finalize($context); 76 81 -
lang/perl/HTTP-Engine/branches/lazy_request/lib/HTTP/Engine/ResponseWriter.pm
r11743 r13439 23 23 sub finalize { 24 24 my($self, $c) = @_; 25 26 local *STDOUT = $c->req->_connection->{handle}; 25 27 croak "argument missing" unless $c; 26 28 -
lang/perl/HTTP-Engine/branches/lazy_request/lib/HTTP/Engine/Role/Interface.pm
r13420 r13439 19 19 20 20 sub request_processor_traits { 21 return; 21 my $self = shift; 22 $self->_default_trait("RequestProcessor"); 22 23 } 23 24 … … 45 46 46 47 sub request_builder_traits { 47 return; 48 my $self = shift; 49 $self->_default_trait("RequestBuilder"); 48 50 } 49 51 … … 66 68 67 69 sub response_writer_traits { 68 return; 70 my $self = shift; 71 $self->_default_trait("ResponseWriter"); 69 72 } 70 73 … … 84 87 85 88 89 sub _default_trait { 90 my ( $self, $category ) = @_; 86 91 92 my $name = join( "::", $self->meta->name, $category ); 93 94 my $e; 95 96 # don't overwrite external $@ 97 { 98 local $@; 99 if ( eval { Class::MOP::load_class($name) } ) { 100 return $name; 101 } else { 102 ( my $file = "$name.pm" ) =~ s{::}{/}g; 103 if ( $@ =~ /Can't locate \Q$file\E in \@INC/ ) { 104 return; 105 } else { 106 $e = $@; 107 } 108 } 109 } 110 111 die $e; 112 } 87 113 88 114 my %anon_classes; … … 117 143 Moose::Util::apply_all_roles( $anon->name, @roles ); 118 144 119 return $anon ->name;145 return $anon; 120 146 } 121 147 -
lang/perl/HTTP-Engine/branches/lazy_request/lib/HTTP/Engine/Role/RequestBuilder/ReadBody.pm
r13418 r13439 7 7 8 8 sub _read_init { 9 my ( $self, $read_state ) = @_; 10 warn "read init"; 11 return $read_state; 12 } 13 14 sub _read_start { 9 15 my ( $self, $state ) = @_; 10 $state->{initialized} = 1; 16 warn "read start"; 17 $state->{started} = 1; 11 18 } 12 19 … … 15 22 16 23 my $content_length = $state->{content_length}; 24 25 warn "reading to end ($content_length)"; 17 26 18 27 if ($content_length > 0) { … … 30 39 } 31 40 } 41 42 warn "finished reading"; 32 43 } 33 44 … … 42 53 sub _read { 43 54 my ($self, $state, $maxlength) = @_; 55 56 warn "reading"; 44 57 45 $self->_read_ init($state) unless $state->{initialized};58 $self->_read_start($state) unless $state->{started}; 46 59 47 60 my ( $length, $pos ) = @{$state}{qw(content_length read_position)}; … … 73 86 my $handle = $state->{handle}; 74 87 88 $self->_io_read( $handle, @_ ); 89 } 90 91 sub _io_read { 92 my ( $self, $handle ) = ( shift, shift ); 93 75 94 if (blessed($handle)) { 76 return $handle-> sysread(@_);95 return $handle->read(@_); 77 96 } else { 78 return sysread $handle, $_[0], $_[1], $_[2];97 return read $handle, $_[0], $_[1], $_[2]; 79 98 } 80 99 }
![(please configure the [header_logo] section in trac.ini)](/share/chrome/site/your_project_logo.png)