add files
|
1 |
package Mojo::Message::Response; |
2 |
use Mojo::Base 'Mojo::Message'; |
|
3 | ||
4 |
use Mojo::Cookie::Response; |
|
5 |
use Mojo::Date; |
|
6 |
use Mojo::Util 'get_line'; |
|
7 | ||
8 |
has [qw(code message)]; |
|
9 | ||
10 |
# Umarked codes are from RFC 2616 |
|
11 |
my %MESSAGES = ( |
|
12 |
100 => 'Continue', |
|
13 |
101 => 'Switching Protocols', |
|
14 |
102 => 'Processing', # RFC 2518 (WebDAV) |
|
15 |
200 => 'OK', |
|
16 |
201 => 'Created', |
|
17 |
202 => 'Accepted', |
|
18 |
203 => 'Non-Authoritative Information', |
|
19 |
204 => 'No Content', |
|
20 |
205 => 'Reset Content', |
|
21 |
206 => 'Partial Content', |
|
22 |
207 => 'Multi-Status', # RFC 2518 (WebDAV) |
|
23 |
208 => 'Already Reported', # RFC 5842 |
|
24 |
226 => 'IM Used', # RFC 3229 |
|
25 |
300 => 'Multiple Choices', |
|
26 |
301 => 'Moved Permanently', |
|
27 |
302 => 'Found', |
|
28 |
303 => 'See Other', |
|
29 |
304 => 'Not Modified', |
|
30 |
305 => 'Use Proxy', |
|
31 |
307 => 'Temporary Redirect', |
|
32 |
308 => 'Permanent Redirect', # Draft |
|
33 |
400 => 'Bad Request', |
|
34 |
401 => 'Unauthorized', |
|
35 |
402 => 'Payment Required', |
|
36 |
403 => 'Forbidden', |
|
37 |
404 => 'Not Found', |
|
38 |
405 => 'Method Not Allowed', |
|
39 |
406 => 'Not Acceptable', |
|
40 |
407 => 'Proxy Authentication Required', |
|
41 |
408 => 'Request Timeout', |
|
42 |
409 => 'Conflict', |
|
43 |
410 => 'Gone', |
|
44 |
411 => 'Length Required', |
|
45 |
412 => 'Precondition Failed', |
|
46 |
413 => 'Request Entity Too Large', |
|
47 |
414 => 'Request-URI Too Long', |
|
48 |
415 => 'Unsupported Media Type', |
|
49 |
416 => 'Request Range Not Satisfiable', |
|
50 |
417 => 'Expectation Failed', |
|
51 |
418 => "I'm a teapot", # :) |
|
52 |
422 => 'Unprocessable Entity', # RFC 2518 (WebDAV) |
|
53 |
423 => 'Locked', # RFC 2518 (WebDAV) |
|
54 |
424 => 'Failed Dependency', # RFC 2518 (WebDAV) |
|
55 |
425 => 'Unordered Colection', # RFC 3648 (WebDAV) |
|
56 |
426 => 'Upgrade Required', # RFC 2817 |
|
57 |
428 => 'Precondition Required', # RFC 6585 |
|
58 |
429 => 'Too Many Requests', # RFC 6585 |
|
59 |
431 => 'Request Header Fields Too Large', # RFC 6585 |
|
60 |
451 => 'Unavailable For Legal Reasons', # Draft |
|
61 |
500 => 'Internal Server Error', |
|
62 |
501 => 'Not Implemented', |
|
63 |
502 => 'Bad Gateway', |
|
64 |
503 => 'Service Unavailable', |
|
65 |
504 => 'Gateway Timeout', |
|
66 |
505 => 'HTTP Version Not Supported', |
|
67 |
506 => 'Variant Also Negotiates', # RFC 2295 |
|
68 |
507 => 'Insufficient Storage', # RFC 2518 (WebDAV) |
|
69 |
508 => 'Loop Detected', # RFC 5842 |
|
70 |
509 => 'Bandwidth Limit Exceeded', # Unofficial |
|
71 |
510 => 'Not Extended', # RFC 2774 |
|
72 |
511 => 'Network Authentication Required' # RFC 6585 |
|
73 |
); |
|
74 | ||
75 |
sub cookies { |
|
76 |
my $self = shift; |
|
77 | ||
78 |
# Parse cookies |
|
79 |
my $headers = $self->headers; |
|
80 |
return [map { @{Mojo::Cookie::Response->parse($_)} } $headers->set_cookie] |
|
81 |
unless @_; |
|
82 | ||
83 |
# Add cookies |
|
84 |
for my $cookie (@_) { |
|
85 |
$cookie = Mojo::Cookie::Response->new($cookie) if ref $cookie eq 'HASH'; |
|
86 |
$headers->add('Set-Cookie' => "$cookie"); |
|
87 |
} |
|
88 | ||
89 |
return $self; |
|
90 |
} |
|
91 | ||
92 |
sub default_message { $MESSAGES{$_[1] || $_[0]->code || 404} || '' } |
|
93 | ||
94 |
sub extract_start_line { |
|
95 |
my ($self, $bufref) = @_; |
|
96 | ||
97 |
# We have a full response line |
|
98 |
return undef unless defined(my $line = get_line $bufref); |
|
99 |
$self->error('Bad response start line') and return undef |
|
100 |
unless $line =~ m!^\s*HTTP/(\d\.\d)\s+(\d\d\d)\s*(.+)?$!; |
|
101 |
$self->content->skip_body(1) if $self->code($2)->is_empty; |
|
102 |
return !!$self->version($1)->message($3)->content->auto_relax(1); |
|
103 |
} |
|
104 | ||
105 |
sub fix_headers { |
|
106 |
my $self = shift; |
|
107 |
$self->{fix} ? return $self : $self->SUPER::fix_headers(@_); |
|
108 | ||
109 |
# Date |
|
110 |
my $headers = $self->headers; |
|
111 |
$headers->date(Mojo::Date->new->to_string) unless $headers->date; |
|
112 | ||
113 |
return $self; |
|
114 |
} |
|
115 | ||
116 |
sub get_start_line_chunk { |
|
117 |
my ($self, $offset) = @_; |
|
118 | ||
119 |
unless (defined $self->{start_buffer}) { |
|
120 |
my $code = $self->code || 404; |
|
121 |
my $msg = $self->message || $self->default_message; |
|
122 |
$self->{start_buffer} = "HTTP/@{[$self->version]} $code $msg\x0d\x0a"; |
|
123 |
} |
|
124 | ||
125 |
$self->emit(progress => 'start_line', $offset); |
|
126 |
return substr $self->{start_buffer}, $offset, 131072; |
|
127 |
} |
|
128 | ||
129 |
sub is_empty { |
|
130 |
my $self = shift; |
|
131 |
return undef unless my $code = $self->code; |
|
132 |
return $self->is_status_class(100) || $code eq 204 || $code eq 304; |
|
133 |
} |
|
134 | ||
135 |
sub is_status_class { |
|
136 |
my ($self, $class) = @_; |
|
137 |
return undef unless my $code = $self->code; |
|
138 |
return $code >= $class && $code < ($class + 100); |
|
139 |
} |
|
140 | ||
141 |
1; |
|
142 | ||
143 |
=encoding utf8 |
|
144 | ||
145 |
=head1 NAME |
|
146 | ||
147 |
Mojo::Message::Response - HTTP response |
|
148 | ||
149 |
=head1 SYNOPSIS |
|
150 | ||
151 |
use Mojo::Message::Response; |
|
152 | ||
153 |
# Parse |
|
154 |
my $res = Mojo::Message::Response->new; |
|
155 |
$res->parse("HTTP/1.0 200 OK\x0d\x0a"); |
|
156 |
$res->parse("Content-Length: 12\x0d\x0a"); |
|
157 |
$res->parse("Content-Type: text/plain\x0d\x0a\x0d\x0a"); |
|
158 |
$res->parse('Hello World!'); |
|
159 |
say $res->code; |
|
160 |
say $res->headers->content_type; |
|
161 |
say $res->body; |
|
162 | ||
163 |
# Build |
|
164 |
my $res = Mojo::Message::Response->new; |
|
165 |
$res->code(200); |
|
166 |
$res->headers->content_type('text/plain'); |
|
167 |
$res->body('Hello World!'); |
|
168 |
say $res->to_string; |
|
169 | ||
170 |
=head1 DESCRIPTION |
|
171 | ||
172 |
L<Mojo::Message::Response> is a container for HTTP responses as described in |
|
173 |
RFC 2616. |
|
174 | ||
175 |
=head1 EVENTS |
|
176 | ||
177 |
L<Mojo::Message::Response> inherits all events from L<Mojo::Message>. |
|
178 | ||
179 |
=head1 ATTRIBUTES |
|
180 | ||
181 |
L<Mojo::Message::Response> inherits all attributes from L<Mojo::Message> and |
|
182 |
implements the following new ones. |
|
183 | ||
184 |
=head2 code |
|
185 | ||
186 |
my $code = $res->code; |
|
187 |
$res = $res->code(200); |
|
188 | ||
189 |
HTTP response code. |
|
190 | ||
191 |
=head2 message |
|
192 | ||
193 |
my $msg = $res->message; |
|
194 |
$res = $res->message('OK'); |
|
195 | ||
196 |
HTTP response message. |
|
197 | ||
198 |
=head1 METHODS |
|
199 | ||
200 |
L<Mojo::Message::Response> inherits all methods from L<Mojo::Message> and |
|
201 |
implements the following new ones. |
|
202 | ||
203 |
=head2 cookies |
|
204 | ||
205 |
my $cookies = $res->cookies; |
|
206 |
$res = $res->cookies(Mojo::Cookie::Response->new); |
|
207 |
$res = $res->cookies({name => 'foo', value => 'bar'}); |
|
208 | ||
209 |
Access response cookies, usually L<Mojo::Cookie::Response> objects. |
|
210 | ||
211 |
=head2 default_message |
|
212 | ||
213 |
my $msg = $res->default_message; |
|
214 | ||
215 |
Generate default response message for code. |
|
216 | ||
217 |
=head2 extract_start_line |
|
218 | ||
219 |
my $bool = $res->extract_start_line(\$str); |
|
220 | ||
221 |
Extract status line from string. |
|
222 | ||
223 |
=head2 fix_headers |
|
224 | ||
225 |
$res = $res->fix_headers; |
|
226 | ||
227 |
Make sure response has all required headers. |
|
228 | ||
229 |
=head2 get_start_line_chunk |
|
230 | ||
231 |
my $bytes = $res->get_start_line_chunk($offset); |
|
232 | ||
233 |
Get a chunk of status line data starting from a specific position. |
|
234 | ||
235 |
=head2 is_empty |
|
236 | ||
237 |
my $bool = $res->is_empty; |
|
238 | ||
239 |
Check if this is a C<1xx>, C<204> or C<304> response. |
|
240 | ||
241 |
=head2 is_status_class |
|
242 | ||
243 |
my $bool = $res->is_status_class(200); |
|
244 | ||
245 |
Check response status class. |
|
246 | ||
247 |
=head1 SEE ALSO |
|
248 | ||
249 |
L<Mojolicious>, L<Mojolicious::Guides>, L<http://mojolicio.us>. |
|
250 | ||
251 |
=cut |