Mercurial > pub > Impl
comparison Lib/IMPL/Web/Response.pm @ 58:a35b60b16a99
Configuration, late activation
author | wizard |
---|---|
date | Fri, 05 Mar 2010 20:14:45 +0300 |
parents | bf59ee1cd506 |
children |
comparison
equal
deleted
inserted
replaced
57:bf59ee1cd506 | 58:a35b60b16a99 |
---|---|
5 | 5 |
6 require IMPL::Exception; | 6 require IMPL::Exception; |
7 require CGI; | 7 require CGI; |
8 require CGI::Cookie; | 8 require CGI::Cookie; |
9 | 9 |
10 use Carp; | |
10 use IMPL::Class::Property; | 11 use IMPL::Class::Property; |
11 | |
12 use HTTP::Response; | |
13 | 12 |
14 BEGIN { | 13 BEGIN { |
15 public property query => prop_get | owner_set; # cgi query | 14 public property query => prop_get | owner_set; # cgi query |
16 public property status => prop_all, { validator => \&_checkHeaderPrinted }; | 15 public property status => prop_all, { validator => \&_checkHeaderPrinted }; |
17 public property contentType => prop_all, { validator => \&_checkHeaderPrinted }; # String | 16 public property contentType => prop_all, { validator => \&_checkHeaderPrinted }; # String |
18 public property charset => prop_all, { validator => \&_checkHeaderPrinted }; | 17 public property charset => { get => \&_charset, set => \&_charset }, { validator => \&_checkHeaderPrinted }; |
19 public property expires => prop_all, { validator => \&_checkHeaderPrinted }; | 18 public property expires => prop_all, { validator => \&_checkHeaderPrinted }; |
20 public property cookies => prop_all, { validator => \&_checkHeaderPrinted }; # Hash | 19 public property cookies => prop_all, { validator => \&_checkHeaderPrinted }; # Hash |
21 | 20 |
22 public property buffered => prop_get | owner_set; # Boolean | 21 public property buffered => prop_all, { validator => \&_canChangeBuffer }; # Boolean |
23 public property streamOut => prop_get | owner_set; # stream | 22 public property streamOut => prop_get | owner_set; # stream |
24 public property streamBody => {get => \&getStreamBody }; # stream | 23 public property streamBody => {get => \&getStreamBody }; # stream |
25 public property isHeaderPrinted => prop_all; # Boolean | 24 public property isHeaderPrinted => prop_get | owner_set; # Boolean |
26 | 25 |
27 private property _bufferBody => prop_all; | 26 private property _bufferBody => prop_all; |
28 private property _streamBody => prop_all; | 27 private property _streamBody => prop_all; |
29 } | 28 } |
30 | 29 |
31 __PACKAGE__->PassThroughArgs; | 30 __PACKAGE__->PassThroughArgs; |
32 | 31 |
33 sub CTOR { | 32 sub CTOR { |
34 my ($this,%args) = @_; | 33 my ($this,%args) = @_; |
35 | 34 |
36 $this->query(CGI->new({})) unless $this->query; | 35 $this->query(CGI->new($this->query() | {})) unless $this->query; |
37 | 36 $this->charset($this->query->charset) unless $this->charset; |
38 if ($this->buffered) { | 37 |
39 my $buffer = ""; | 38 $this->streamOut(*STDOUT) unless $this->streamOut; |
40 $this->_bufferBody(\$buffer); | |
41 | |
42 open my $hBody, ">", \$buffer or die new IMPL::Exception("Failed to create buffer",$!); | |
43 | |
44 $this->_streamBody($hBody); | |
45 } else { | |
46 $this->_streamBody($this->streamOut); | |
47 } | |
48 } | 39 } |
49 | 40 |
50 sub _checkHeaderPrinted { | 41 sub _checkHeaderPrinted { |
51 my ($this,$value) = @_; | 42 my ($this,$value) = @_; |
52 | 43 |
53 die new IMPL::InvalidOperationException() if $this->isHeaderPrinted; | 44 die new IMPL::InvalidOperationException() if $this->isHeaderPrinted; |
54 } | 45 } |
55 | 46 |
47 sub _canChangeBuffer { | |
48 my ($this,$value) = @_; | |
49 | |
50 die new IMPL::InvalidOperationException() if $this->isHeaderPrinted or $this->_streamBody; | |
51 } | |
52 | |
53 sub _charset { | |
54 my $this = shift; | |
55 | |
56 return $this->query->charset(@_); | |
57 } | |
58 | |
56 sub _PrintHeader { | 59 sub _PrintHeader { |
57 my ($this) = @_; | 60 my ($this) = @_; |
58 | 61 |
59 unless ($this->isHeaderPrinted) { | 62 unless ($this->isHeaderPrinted) { |
60 $this->isHeaderPrinted(1); | 63 $this->isHeaderPrinted(1); |
61 | 64 |
62 my %opt; | 65 my %opt; |
63 | 66 |
64 $opt{-type} = $this->contentType if $this->contentType; | 67 $opt{-type} = $this->contentType if $this->contentType; |
65 $opt{-charset} = $this->charset if $this->charset; | |
66 $opt{-status} = $this->status if $this->status; | 68 $opt{-status} = $this->status if $this->status; |
67 $opt{-expires} = $this->expires if $this->expires; | 69 $opt{-expires} = $this->expires if $this->expires; |
68 | 70 |
69 my $refCookies = $this->cookies; | 71 my $refCookies = $this->cookies; |
70 $opt{-cookie} = [map CGI::Cookie->new(-name => $_, $refCookies->{$_} ), keys %$refCookies] if $refCookies; | 72 $opt{-cookie} = [map CGI::Cookie->new(-name => $_, $refCookies->{$_} ), keys %$refCookies] if $refCookies; |
78 } | 80 } |
79 | 81 |
80 sub getStreamBody { | 82 sub getStreamBody { |
81 my ($this) = @_; | 83 my ($this) = @_; |
82 | 84 |
83 return undef unless $this->_bodyStream; | 85 return undef unless $this->streamOut; |
84 | 86 |
85 if ($this->buffered) { | 87 unless ($this->_streamBody) { |
86 return $this->_bodyStream; | 88 if ($this->buffered) { |
87 } else { | 89 my $buffer = ""; |
88 $this->_PrintHeader(); | 90 $this->_bufferBody(\$buffer); |
89 return $this->_bodyStream; | 91 |
92 open my $hBody, ">", \$buffer or die new IMPL::Exception("Failed to create buffer",$!); | |
93 | |
94 $this->_streamBody($hBody); | |
95 } else { | |
96 $this->_PrintHeader(); | |
97 $this->_streamBody($this->streamOut); | |
98 } | |
90 } | 99 } |
100 | |
101 return $this->_streamBody; | |
91 } | 102 } |
92 | 103 |
93 sub Complete { | 104 sub Complete { |
94 my ($this) = @_; | 105 my ($this) = @_; |
95 | 106 |
111 } | 122 } |
112 | 123 |
113 sub Discard { | 124 sub Discard { |
114 my ($this) = @_; | 125 my ($this) = @_; |
115 | 126 |
127 carp "Discarding sent response" if $this->isHeaderPrinted; | |
128 | |
116 $this->_streamBody(undef); | 129 $this->_streamBody(undef); |
117 $this->_bufferBody(undef); | 130 $this->_bufferBody(undef); |
118 $this->streamOut(undef); | 131 $this->streamOut(undef); |
119 } | 132 } |
120 | 133 |
122 | 135 |
123 __END__ | 136 __END__ |
124 | 137 |
125 =pod | 138 =pod |
126 | 139 |
127 | 140 =head1 DESCRIPTION |
141 | |
142 Ответ сервера на CGI запрос, позволяет сформировать основные свойства заголовка и тело запроса. | |
143 | |
144 Объект позволяет буфферизировать вывод в тело ответа, что позволяет отменить или изменить | |
145 ответ в последний момент. | |
146 | |
147 Свойство C< isHeaderPrinted > можно использовать для определения были ли отправлены какие-нибудь | |
148 данные клиенту. | |
149 | |
150 =head1 PROPERTIES | |
151 | |
152 =head2 HTTP Header | |
153 | |
154 Свойства отвечающие за заголовок HTTP ответа. Эти своства могут быть изменены до тех пор пока | |
155 не будет отправлен заголовок. В противном случае выдается исключение C< IMPL::InvalidOperationException >. | |
156 | |
157 =over | |
158 | |
159 =item C< query > | |
160 | |
161 CGI запрос, который используется для вывода данных, заголовка и пр. Существует всегда. | |
162 | |
163 =item C< status > | |
164 | |
165 Код ошибки HTTP. Например, '200 OK'. По умолчанию не установлен, при отправке клиенту бедт отправлен '200 ОК'. | |
166 | |
167 =item C< contentType > | |
168 | |
169 Тип MIME. По умолчанию не установлен, подразумивается 'text/html'. | |
170 | |
171 =item C< charset > | |
172 | |
173 Кодировка, синоним свойства query->charset. | |
174 | |
175 =item C< expires > | |
176 | |
177 Определяет время жизни контента, например '+10m'. По умолчанию не задано и не передается. | |
178 | |
179 =item C< cookies > | |
180 | |
181 Хеш массив с cookies, например C< { cart => ['foo','bar'], display => 'list' } >. | |
182 | |
183 =back | |
184 | |
185 =head2 Response behaviour | |
186 | |
187 Свойства отвечающие за поведение ответа. | |
188 | |
189 =over | |
190 | |
191 =item C< buffered > | |
192 | |
193 C< True > - то тело ответа пишется в буффер и будет отправлено при вызове метода C< Complete >, | |
194 заголовок также будет отправлен после вызова метода C< Complete >. | |
195 | |
196 C< False > - тело ответа пишется непосредственно в поток к клиенту, при этом заголовок | |
197 будет отправлен при первом обращении к свойству C< streamBody > | |
198 | |
199 Это свойство можно менять до первого обращения к потоку для записи в тело ответа. | |
200 | |
201 =item C< streamOut > | |
202 | |
203 Стандартный вывод CGI приложения. | |
204 | |
205 =item C< streamBody > | |
206 | |
207 Поток для записи в тело ответа. | |
208 | |
209 =item C< isHeadPrinted > | |
210 | |
211 Признак того, что заголовок уже был отправлен клиенту. | |
212 | |
213 =back | |
214 | |
215 =head1 METHODS | |
216 | |
217 =over | |
218 | |
219 =item C< Complete > | |
220 | |
221 Завершает отправку ответа. | |
222 | |
223 =item C< Discard > | |
224 | |
225 Отменяет отправку ответа, при этом если часть данных (например, заголовок) | |
226 уже была отправлена, выдает предупреждение в STDERR. | |
227 | |
228 =back | |
128 | 229 |
129 =cut | 230 =cut |