Work in progress engine for HTTP::Engine
[catagits/Catalyst-Runtime.git] / lib / Catalyst / Engine / HTTPEngine.pm
CommitLineData
919492ab 1package Catalyst::Engine::HTTPEngine;
2
3# Experimental HTTP::Engine engine
4
5# TODO:
6# * Lots of copying/reference going on between HTTP::Engine req/res and Catalyst req/res
7# * Body support
8# * Proxy checks
9# * Lots of test failures
10
11use Moose;
12
13use Data::Dump qw(dump);
14use HTTP::Engine;
15use Socket;
16
17use constant DEBUG => $ENV{CATALYST_HTTP_DEBUG} || 0;
18
19sub run {
20 my ( $self, $class, $port, $host, $options ) = @_;
21
22 $options ||= {};
23
24 $self->{appclass} = $class;
25 $self->{options} = $options;
26
27 my $addr = $host ? inet_aton($host) : INADDR_ANY;
28 if ( $addr eq INADDR_ANY ) {
29 require Sys::Hostname;
30 $host = lc Sys::Hostname::hostname();
31 }
32 else {
33 $host = gethostbyaddr( $addr, AF_INET ) || inet_ntoa($addr);
34 }
35
36 my $engine = HTTP::Engine->new(
37 interface => {
38 module => 'Standalone',
39 args => {
40 host => inet_ntoa($addr),
41 port => $port,
42 },
43 request_handler => sub {
44 $self->handler( $_[0] );
45 },
46 },
47 );
48
49 my $url = "http://$host";
50 $url .= ":$port" unless $port == 80;
51
52 print "You can connect to your server at $url\n";
53
54 $engine->run;
55}
56
57sub handler {
58 my ( $self, $req ) = @_;
59
60 my $res = HTTP::Engine::Response->new;
61
62 # Pass control to Catalyst
63 $self->{appclass}->handle_request(
64 req => $req,
65 res => $res,
66 );
67
68 return $res;
69}
70
71sub prepare_request {
72 my ( $self, $c, %args ) = @_;
73
74 $c->{_ereq} = $args{req};
75 $c->{_eres} = $args{res};
76}
77
78sub prepare_connection {
79 my ( $self, $c ) = @_;
80
81 my $ci = $c->{_ereq}->connection_info;
82 my $request = $c->request;
83
84 $request->address( $ci->{address} );
85
86 # XXX proxy check
87
88 $request->hostname( $ci->{address} );
89 $request->protocol( $ci->{protocol} );
90 $request->user( $ci->{user} );
91 $request->method( $ci->{method} );
92
93 # XXX $request->secure
94}
95
96sub prepare_query_parameters {
97 my ( $self, $c ) = @_;
98
99 my $ereq = $c->{_ereq};
100
101 return unless defined $ereq->uri->query;
102
103 # Check for keywords (no = signs)
104 # (yes, index() is faster than a regex :))
105 if ( index( $ereq->uri->query, '=' ) < 0 ) {
106 $c->request->query_keywords(
107 $self->unescape_uri( $ereq->uri->query )
108 );
109 return;
110 }
111
112 $c->request->query_parameters( $ereq->query_parameters );
113}
114
115sub prepare_headers {
116 my ( $self, $c ) = @_;
117
118 $c->request->headers( $c->{_ereq}->headers );
119}
120
121sub prepare_cookies {
122 my ( $self, $c ) = @_;
123
124 $c->request->cookies( $c->{_ereq}->cookies );
125}
126
127sub prepare_path {
128 my ( $self, $c ) = @_;
129
130 # XXX: proxy check
131
132 # XXX: cleaner way to get the main URI object?
133 $c->request->uri( $c->{_ereq}->uri->[0] );
134
135 $c->request->base( $c->{_ereq}->uri->base );
136}
137
138sub prepare_read { }
139
140sub prepare_body {
141 my ( $self, $c ) = @_;
142
143 if ( $c->request->content_length ) {
144 $c->request->{_body} = $c->{_ereq}->http_body;
145 }
146 else {
147 $c->request->{_body} = 0;
148 }
149}
150
151sub prepare_body_parameters {
152 my ( $self, $c ) = @_;
153
154 return unless $c->request->{_body};
155
156 $c->request->body_parameters( $c->{_ereq}->body_parameters );
157}
158
159sub prepare_parameters {
160 my ( $self, $c ) = @_;
161
162 # XXX: HTTP::Engine loads HTTP::Body object when you call this,
163 # even if no Content-Length
164 $c->request->parameters( $c->{_ereq}->parameters );
165}
166
167sub prepare_uploads {
168 my ( $self, $c ) = @_;
169
170 return unless $c->request->{_body};
171
172 $c->request->uploads( $c->{_ereq}->uploads );
173}
174
175sub finalize_uploads {
176 my ( $self, $c ) = @_;
177
178 my $request = $c->request;
179 foreach my $key (keys %{ $request->uploads }) {
180 my $upload = $request->uploads->{$key};
181 unlink grep { -e $_ } map { $_->tempname }
182 (ref $upload eq 'ARRAY' ? @{$upload} : ($upload));
183 }
184}
185
186sub finalize_cookies {
187 my ( $self, $c ) = @_;
188
189 $c->{_eres}->cookies( $c->response->cookies );
190}
191
192sub finalize_headers {
193 my ( $self, $c ) = @_;
194
195 $c->{_eres}->status( $c->response->status );
196 $c->{_eres}->headers( $c->response->headers );
197}
198
199sub finalize_body {
200 my ( $self, $c ) = @_;
201
202 $c->{_eres}->body( $c->response->body );
203}
204
205sub unescape_uri {
206 my ( $self, $str ) = @_;
207
208 $str =~ s/(?:%([0-9A-Fa-f]{2})|\+)/defined $1 ? chr(hex($1)) : ' '/eg;
209
210 return $str;
211}
212
2131;