biblesearch / mojo / lib / Mojo / Transaction.pm /
Newer Older
297 lines | 6.139kb
add files
Yuki Kimoto authored on 2014-03-26
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