add files
|
1 |
package Mojo::Transaction; |
2 |
use Mojo::Base 'Mojo::EventEmitter'; |
|
3 | ||
4 |
use Carp 'croak'; |
|
5 |
use Mojo::Message::Request; |
|
6 |
use Mojo::Message::Response; |
|
7 | ||
8 |
has [qw(kept_alive local_address local_port remote_port)]; |
|
9 |
has req => sub { Mojo::Message::Request->new }; |
|
10 |
has res => sub { Mojo::Message::Response->new }; |
|
11 | ||
12 |
sub client_close { |
|
13 |
my ($self, $close) = @_; |
|
14 | ||
15 |
# Remove code from parser errors |
|
16 |
my $res = $self->res->finish; |
|
17 |
if (my $err = $res->error) { $res->error($err) } |
|
18 | ||
19 |
# Premature connection close |
|
20 |
elsif ($close && !$res->code) { $res->error('Premature connection close') } |
|
21 | ||
22 |
# 400/500 |
|
23 |
elsif ($res->is_status_class(400) || $res->is_status_class(500)) { |
|
24 |
$res->error($res->message, $res->code); |
|
25 |
} |
|
26 | ||
27 |
return $self->server_close; |
|
28 |
} |
|
29 | ||
30 |
sub client_read { croak 'Method "client_read" not implemented by subclass' } |
|
31 |
sub client_write { croak 'Method "client_write" not implemented by subclass' } |
|
32 | ||
33 |
sub connection { |
|
34 |
my $self = shift; |
|
35 |
return $self->emit(connection => $self->{connection} = shift) if @_; |
|
36 |
return $self->{connection}; |
|
37 |
} |
|
38 | ||
39 |
sub error { |
|
40 |
my $self = shift; |
|
41 |
my $req = $self->req; |
|
42 |
return $req->error if $req->error; |
|
43 |
my $res = $self->res; |
|
44 |
return $res->error ? $res->error : undef; |
|
45 |
} |
|
46 | ||
47 |
sub is_finished { (shift->{state} // '') eq 'finished' } |
|
48 | ||
49 |
sub is_websocket {undef} |
|
50 | ||
51 |
sub is_writing { (shift->{state} // 'write') eq 'write' } |
|
52 | ||
53 |
sub remote_address { |
|
54 |
my $self = shift; |
|
55 | ||
56 |
# New address |
|
57 |
if (@_) { |
|
58 |
$self->{remote_address} = shift; |
|
59 |
return $self; |
|
60 |
} |
|
61 | ||
62 |
# Reverse proxy |
|
63 |
if ($ENV{MOJO_REVERSE_PROXY}) { |
|
64 |
return $self->{forwarded_for} if $self->{forwarded_for}; |
|
65 |
my $forwarded = $self->req->headers->header('X-Forwarded-For') // ''; |
|
66 |
$forwarded =~ /([^,\s]+)$/ and return $self->{forwarded_for} = $1; |
|
67 |
} |
|
68 | ||
69 |
return $self->{remote_address}; |
|
70 |
} |
|
71 | ||
72 |
sub resume { shift->_state(qw(write resume)) } |
|
73 |
sub server_close { shift->_state(qw(finished finish)) } |
|
74 | ||
75 |
sub server_read { croak 'Method "server_read" not implemented by subclass' } |
|
76 |
sub server_write { croak 'Method "server_write" not implemented by subclass' } |
|
77 | ||
78 |
sub success { $_[0]->error ? undef : $_[0]->res } |
|
79 | ||
80 |
sub _state { |
|
81 |
my ($self, $state, $event) = @_; |
|
82 |
$self->{state} = $state; |
|
83 |
return $self->emit($event); |
|
84 |
} |
|
85 | ||
86 |
1; |
|
87 | ||
88 |
=encoding utf8 |
|
89 | ||
90 |
=head1 NAME |
|
91 | ||
92 |
Mojo::Transaction - Transaction base class |
|
93 | ||
94 |
=head1 SYNOPSIS |
|
95 | ||
96 |
package Mojo::Transaction::MyTransaction; |
|
97 |
use Mojo::Base 'Mojo::Transaction'; |
|
98 | ||
99 |
sub client_read {...} |
|
100 |
sub client_write {...} |
|
101 |
sub server_read {...} |
|
102 |
sub server_write {...} |
|
103 | ||
104 |
=head1 DESCRIPTION |
|
105 | ||
106 |
L<Mojo::Transaction> is an abstract base class for transactions. |
|
107 | ||
108 |
=head1 EVENTS |
|
109 | ||
110 |
L<Mojo::Transaction> inherits all events from L<Mojo::EventEmitter> and can |
|
111 |
emit the following new ones. |
|
112 | ||
113 |
=head2 connection |
|
114 | ||
115 |
$tx->on(connection => sub { |
|
116 |
my ($tx, $connection) = @_; |
|
117 |
... |
|
118 |
}); |
|
119 | ||
120 |
Emitted when a connection has been assigned to transaction. |
|
121 | ||
122 |
=head2 finish |
|
123 | ||
124 |
$tx->on(finish => sub { |
|
125 |
my $tx = shift; |
|
126 |
... |
|
127 |
}); |
|
128 | ||
129 |
Emitted when transaction is finished. |
|
130 | ||
131 |
=head2 resume |
|
132 | ||
133 |
$tx->on(resume => sub { |
|
134 |
my $tx = shift; |
|
135 |
... |
|
136 |
}); |
|
137 | ||
138 |
Emitted when transaction is resumed. |
|
139 | ||
140 |
=head1 ATTRIBUTES |
|
141 | ||
142 |
L<Mojo::Transaction> implements the following attributes. |
|
143 | ||
144 |
=head2 kept_alive |
|
145 | ||
146 |
my $kept_alive = $tx->kept_alive; |
|
147 |
$tx = $tx->kept_alive(1); |
|
148 | ||
149 |
Connection has been kept alive. |
|
150 | ||
151 |
=head2 local_address |
|
152 | ||
153 |
my $address = $tx->local_address; |
|
154 |
$tx = $tx->local_address('127.0.0.1'); |
|
155 | ||
156 |
Local interface address. |
|
157 | ||
158 |
=head2 local_port |
|
159 | ||
160 |
my $port = $tx->local_port; |
|
161 |
$tx = $tx->local_port(8080); |
|
162 | ||
163 |
Local interface port. |
|
164 | ||
165 |
=head2 remote_port |
|
166 | ||
167 |
my $port = $tx->remote_port; |
|
168 |
$tx = $tx->remote_port(8081); |
|
169 | ||
170 |
Remote interface port. |
|
171 | ||
172 |
=head2 req |
|
173 | ||
174 |
my $req = $tx->req; |
|
175 |
$tx = $tx->req(Mojo::Message::Request->new); |
|
176 | ||
177 |
HTTP request, defaults to a L<Mojo::Message::Request> object. |
|
178 | ||
179 |
=head2 res |
|
180 | ||
181 |
my $res = $tx->res; |
|
182 |
$tx = $tx->res(Mojo::Message::Response->new); |
|
183 | ||
184 |
HTTP response, defaults to a L<Mojo::Message::Response> object. |
|
185 | ||
186 |
=head1 METHODS |
|
187 | ||
188 |
L<Mojo::Transaction> inherits all methods from L<Mojo::EventEmitter> and |
|
189 |
implements the following new ones. |
|
190 | ||
191 |
=head2 client_close |
|
192 | ||
193 |
$tx->client_close; |
|
194 |
$tx->client_close(1); |
|
195 | ||
196 |
Transaction closed client-side, no actual connection close is assumed by |
|
197 |
default, used to implement user agents. |
|
198 | ||
199 |
=head2 client_read |
|
200 | ||
201 |
$tx->client_read($bytes); |
|
202 | ||
203 |
Read data client-side, used to implement user agents. Meant to be overloaded |
|
204 |
in a subclass. |
|
205 | ||
206 |
=head2 client_write |
|
207 | ||
208 |
my $bytes = $tx->client_write; |
|
209 | ||
210 |
Write data client-side, used to implement user agents. Meant to be overloaded |
|
211 |
in a subclass. |
|
212 | ||
213 |
=head2 connection |
|
214 | ||
215 |
my $connection = $tx->connection; |
|
216 |
$tx = $tx->connection($connection); |
|
217 | ||
218 |
Connection identifier or socket. |
|
219 | ||
220 |
=head2 error |
|
221 | ||
222 |
my $err = $tx->error; |
|
223 |
my ($err, $code) = $tx->error; |
|
224 | ||
225 |
Error and code. |
|
226 | ||
227 |
=head2 is_finished |
|
228 | ||
229 |
my $bool = $tx->is_finished; |
|
230 | ||
231 |
Check if transaction is finished. |
|
232 | ||
233 |
=head2 is_websocket |
|
234 | ||
235 |
my $false = $tx->is_websocket; |
|
236 | ||
237 |
False. |
|
238 | ||
239 |
=head2 is_writing |
|
240 | ||
241 |
my $bool = $tx->is_writing; |
|
242 | ||
243 |
Check if transaction is writing. |
|
244 | ||
245 |
=head2 resume |
|
246 | ||
247 |
$tx = $tx->resume; |
|
248 | ||
249 |
Resume transaction. |
|
250 | ||
251 |
=head2 remote_address |
|
252 | ||
253 |
my $address = $tx->remote_address; |
|
254 |
$tx = $tx->remote_address('127.0.0.1'); |
|
255 | ||
256 |
Remote interface address. |
|
257 | ||
258 |
=head2 server_close |
|
259 | ||
260 |
$tx->server_close; |
|
261 | ||
262 |
Transaction closed server-side, used to implement web servers. |
|
263 | ||
264 |
=head2 server_read |
|
265 | ||
266 |
$tx->server_read($bytes); |
|
267 | ||
268 |
Read data server-side, used to implement web servers. Meant to be overloaded |
|
269 |
in a subclass. |
|
270 | ||
271 |
=head2 server_write |
|
272 | ||
273 |
my $bytes = $tx->server_write; |
|
274 | ||
275 |
Write data server-side, used to implement web servers. Meant to be overloaded |
|
276 |
in a subclass. |
|
277 | ||
278 |
=head2 success |
|
279 | ||
280 |
my $res = $tx->success; |
|
281 | ||
282 |
Returns the L<Mojo::Message::Response> object from L</"res"> if transaction |
|
283 |
was successful or C<undef> otherwise. Connection and parser errors have only a |
|
284 |
message in L</"error">, 400 and 500 responses also a code. |
|
285 | ||
286 |
# Sensible exception handling |
|
287 |
if (my $res = $tx->success) { say $res->body } |
|
288 |
else { |
|
289 |
my ($err, $code) = $tx->error; |
|
290 |
say $code ? "$code response: $err" : "Connection error: $err"; |
|
291 |
} |
|
292 | ||
293 |
=head1 SEE ALSO |
|
294 | ||
295 |
L<Mojolicious>, L<Mojolicious::Guides>, L<http://mojolicio.us>. |
|
296 | ||
297 |
=cut |