Mercurial > pub > Impl
annotate Lib/IMPL/Web/Application/Response.pm @ 66:f47f93534005
Documentation
| author | wizard |
|---|---|
| date | Thu, 18 Mar 2010 17:58:33 +0300 |
| parents | 2840c4c85db8 |
| children | 9f5795a10939 |
| rev | line source |
|---|---|
|
59
0f3e369553bd
Rewritten property implementation (probably become slower but more flexible)
wizard
parents:
58
diff
changeset
|
1 package IMPL::Web::Application::Response; |
| 57 | 2 use strict; |
| 3 | |
| 4 use base qw(IMPL::Object IMPL::Object::Autofill); | |
| 5 | |
| 6 require IMPL::Exception; | |
| 7 require CGI; | |
| 8 require CGI::Cookie; | |
| 9 | |
| 58 | 10 use Carp; |
|
63
76b878ad6596
Added serialization support for the IMPL::Object::List
wizard
parents:
59
diff
changeset
|
11 use Encode; |
| 57 | 12 use IMPL::Class::Property; |
| 13 | |
|
63
76b878ad6596
Added serialization support for the IMPL::Object::List
wizard
parents:
59
diff
changeset
|
14 #todo: add binary method to set a binary encoding, set it automatic when type isn't a text |
|
76b878ad6596
Added serialization support for the IMPL::Object::List
wizard
parents:
59
diff
changeset
|
15 |
| 57 | 16 BEGIN { |
| 17 public property query => prop_get | owner_set; # cgi query | |
| 18 public property status => prop_all, { validator => \&_checkHeaderPrinted }; | |
| 19 public property contentType => prop_all, { validator => \&_checkHeaderPrinted }; # String | |
| 58 | 20 public property charset => { get => \&_charset, set => \&_charset }, { validator => \&_checkHeaderPrinted }; |
| 57 | 21 public property expires => prop_all, { validator => \&_checkHeaderPrinted }; |
| 22 public property cookies => prop_all, { validator => \&_checkHeaderPrinted }; # Hash | |
| 23 | |
| 58 | 24 public property buffered => prop_all, { validator => \&_canChangeBuffer }; # Boolean |
| 57 | 25 public property streamOut => prop_get | owner_set; # stream |
| 26 public property streamBody => {get => \&getStreamBody }; # stream | |
| 58 | 27 public property isHeaderPrinted => prop_get | owner_set; # Boolean |
| 57 | 28 |
| 29 private property _bufferBody => prop_all; | |
| 30 private property _streamBody => prop_all; | |
| 31 } | |
| 32 | |
| 33 __PACKAGE__->PassThroughArgs; | |
| 34 | |
| 35 sub CTOR { | |
| 36 my ($this,%args) = @_; | |
| 37 | |
| 58 | 38 $this->query(CGI->new($this->query() | {})) unless $this->query; |
| 57 | 39 |
| 65 | 40 if (lc $this->streamOut eq 'memory') { |
| 41 my $dummy = ''; | |
| 42 open my $hout, '>:encoding(utf8)', \$dummy or die new IMPL::Exception("Failed to create memory stream",$!); | |
| 43 $this->streamOut($hout); | |
| 44 } elsif (not $this->streamOut) { | |
| 45 $this->streamOut(*STDOUT); | |
| 46 } else { | |
| 47 die new IMPL::InvalidArgumentException("Invalid parameter value",$this->streamOut); | |
| 48 } | |
| 49 | |
|
63
76b878ad6596
Added serialization support for the IMPL::Object::List
wizard
parents:
59
diff
changeset
|
50 $this->buffered(1) unless defined $this->buffered; |
|
76b878ad6596
Added serialization support for the IMPL::Object::List
wizard
parents:
59
diff
changeset
|
51 binmode $this->streamOut, ":encoding(".$this->charset.")"; |
| 57 | 52 } |
| 53 | |
| 54 sub _checkHeaderPrinted { | |
| 55 my ($this,$value) = @_; | |
| 56 | |
| 57 die new IMPL::InvalidOperationException() if $this->isHeaderPrinted; | |
| 58 } | |
| 59 | |
| 58 | 60 sub _canChangeBuffer { |
| 61 my ($this,$value) = @_; | |
| 62 | |
| 63 die new IMPL::InvalidOperationException() if $this->isHeaderPrinted or $this->_streamBody; | |
| 64 } | |
| 65 | |
| 66 sub _charset { | |
| 67 my $this = shift; | |
| 68 | |
|
63
76b878ad6596
Added serialization support for the IMPL::Object::List
wizard
parents:
59
diff
changeset
|
69 if (@_) { |
|
76b878ad6596
Added serialization support for the IMPL::Object::List
wizard
parents:
59
diff
changeset
|
70 my $charset = $this->query->charset(@_); |
|
76b878ad6596
Added serialization support for the IMPL::Object::List
wizard
parents:
59
diff
changeset
|
71 |
|
76b878ad6596
Added serialization support for the IMPL::Object::List
wizard
parents:
59
diff
changeset
|
72 my $hout = $this->streamOut; |
|
76b878ad6596
Added serialization support for the IMPL::Object::List
wizard
parents:
59
diff
changeset
|
73 |
|
76b878ad6596
Added serialization support for the IMPL::Object::List
wizard
parents:
59
diff
changeset
|
74 binmode $hout; |
|
76b878ad6596
Added serialization support for the IMPL::Object::List
wizard
parents:
59
diff
changeset
|
75 binmode $hout, ":encoding($charset)"; |
|
76b878ad6596
Added serialization support for the IMPL::Object::List
wizard
parents:
59
diff
changeset
|
76 |
|
76b878ad6596
Added serialization support for the IMPL::Object::List
wizard
parents:
59
diff
changeset
|
77 return $charset; |
|
76b878ad6596
Added serialization support for the IMPL::Object::List
wizard
parents:
59
diff
changeset
|
78 } else { |
|
76b878ad6596
Added serialization support for the IMPL::Object::List
wizard
parents:
59
diff
changeset
|
79 return $this->query->charset; |
|
76b878ad6596
Added serialization support for the IMPL::Object::List
wizard
parents:
59
diff
changeset
|
80 } |
| 58 | 81 } |
| 82 | |
| 57 | 83 sub _PrintHeader { |
| 84 my ($this) = @_; | |
| 85 | |
| 86 unless ($this->isHeaderPrinted) { | |
| 87 $this->isHeaderPrinted(1); | |
| 88 | |
| 89 my %opt; | |
| 90 | |
| 91 $opt{-type} = $this->contentType if $this->contentType; | |
| 92 $opt{-status} = $this->status if $this->status; | |
| 93 $opt{-expires} = $this->expires if $this->expires; | |
| 94 | |
| 95 my $refCookies = $this->cookies; | |
| 96 $opt{-cookie} = [map CGI::Cookie->new(-name => $_, $refCookies->{$_} ), keys %$refCookies] if $refCookies; | |
| 97 | |
| 98 my $hOut = $this->streamOut; | |
| 99 | |
| 100 print $hOut $this->query->header( | |
| 101 %opt | |
| 102 ); | |
| 103 } | |
| 104 } | |
| 105 | |
| 106 sub getStreamBody { | |
| 107 my ($this) = @_; | |
| 108 | |
| 58 | 109 return undef unless $this->streamOut; |
| 57 | 110 |
| 58 | 111 unless ($this->_streamBody) { |
| 112 if ($this->buffered) { | |
| 113 my $buffer = ""; | |
|
63
76b878ad6596
Added serialization support for the IMPL::Object::List
wizard
parents:
59
diff
changeset
|
114 |
| 58 | 115 $this->_bufferBody(\$buffer); |
| 116 | |
|
63
76b878ad6596
Added serialization support for the IMPL::Object::List
wizard
parents:
59
diff
changeset
|
117 open my $hBody, ">:encoding(utf-8)", \$buffer or die new IMPL::Exception("Failed to create buffer",$!); |
|
76b878ad6596
Added serialization support for the IMPL::Object::List
wizard
parents:
59
diff
changeset
|
118 |
|
76b878ad6596
Added serialization support for the IMPL::Object::List
wizard
parents:
59
diff
changeset
|
119 Encode::_utf8_on($buffer); |
| 58 | 120 |
| 121 $this->_streamBody($hBody); | |
| 122 } else { | |
| 123 $this->_PrintHeader(); | |
| 124 $this->_streamBody($this->streamOut); | |
| 125 } | |
| 57 | 126 } |
| 58 | 127 |
| 128 return $this->_streamBody; | |
| 57 | 129 } |
| 130 | |
| 131 sub Complete { | |
| 132 my ($this) = @_; | |
| 133 | |
| 134 return 0 unless $this->streamOut; | |
| 135 | |
| 136 my $hOut = $this->streamOut; | |
| 137 | |
| 138 $this->_PrintHeader(); | |
| 139 | |
|
63
76b878ad6596
Added serialization support for the IMPL::Object::List
wizard
parents:
59
diff
changeset
|
140 $this->_streamBody(undef); |
|
76b878ad6596
Added serialization support for the IMPL::Object::List
wizard
parents:
59
diff
changeset
|
141 |
| 57 | 142 if ($this->buffered) { |
| 143 print $hOut ${$this->_bufferBody}; | |
|
63
76b878ad6596
Added serialization support for the IMPL::Object::List
wizard
parents:
59
diff
changeset
|
144 } |
| 57 | 145 |
| 146 $this->_bufferBody(undef); | |
| 147 $this->streamOut(undef); | |
| 148 | |
| 149 return 1; | |
| 150 } | |
| 151 | |
| 152 sub Discard { | |
| 153 my ($this) = @_; | |
| 154 | |
| 58 | 155 carp "Discarding sent response" if $this->isHeaderPrinted; |
| 156 | |
| 57 | 157 $this->_streamBody(undef); |
| 158 $this->_bufferBody(undef); | |
| 159 $this->streamOut(undef); | |
| 160 } | |
| 161 | |
| 162 1; | |
| 163 | |
| 164 __END__ | |
| 165 | |
| 166 =pod | |
| 167 | |
| 58 | 168 =head1 DESCRIPTION |
| 57 | 169 |
| 58 | 170 Ответ сервера на CGI запрос, позволяет сформировать основные свойства заголовка и тело запроса. |
| 171 | |
| 172 Объект позволяет буфферизировать вывод в тело ответа, что позволяет отменить или изменить | |
| 173 ответ в последний момент. | |
| 174 | |
| 175 Свойство C< isHeaderPrinted > можно использовать для определения были ли отправлены какие-нибудь | |
| 176 данные клиенту. | |
| 177 | |
| 178 =head1 PROPERTIES | |
| 179 | |
| 180 =head2 HTTP Header | |
| 181 | |
| 182 Свойства отвечающие за заголовок HTTP ответа. Эти своства могут быть изменены до тех пор пока | |
| 183 не будет отправлен заголовок. В противном случае выдается исключение C< IMPL::InvalidOperationException >. | |
| 184 | |
| 185 =over | |
| 186 | |
| 187 =item C< query > | |
| 188 | |
| 189 CGI запрос, который используется для вывода данных, заголовка и пр. Существует всегда. | |
| 190 | |
| 191 =item C< status > | |
| 192 | |
| 193 Код ошибки HTTP. Например, '200 OK'. По умолчанию не установлен, при отправке клиенту бедт отправлен '200 ОК'. | |
| 194 | |
| 195 =item C< contentType > | |
| 196 | |
| 197 Тип MIME. По умолчанию не установлен, подразумивается 'text/html'. | |
| 198 | |
| 199 =item C< charset > | |
| 200 | |
| 201 Кодировка, синоним свойства query->charset. | |
| 202 | |
| 203 =item C< expires > | |
| 204 | |
| 205 Определяет время жизни контента, например '+10m'. По умолчанию не задано и не передается. | |
| 206 | |
| 207 =item C< cookies > | |
| 208 | |
| 209 Хеш массив с cookies, например C< { cart => ['foo','bar'], display => 'list' } >. | |
| 210 | |
| 211 =back | |
| 212 | |
| 213 =head2 Response behaviour | |
| 214 | |
| 215 Свойства отвечающие за поведение ответа. | |
| 216 | |
| 217 =over | |
| 218 | |
| 219 =item C< buffered > | |
| 220 | |
| 221 C< True > - то тело ответа пишется в буффер и будет отправлено при вызове метода C< Complete >, | |
| 222 заголовок также будет отправлен после вызова метода C< Complete >. | |
| 223 | |
| 224 C< False > - тело ответа пишется непосредственно в поток к клиенту, при этом заголовок | |
| 225 будет отправлен при первом обращении к свойству C< streamBody > | |
| 226 | |
| 227 Это свойство можно менять до первого обращения к потоку для записи в тело ответа. | |
| 228 | |
| 229 =item C< streamOut > | |
| 230 | |
| 231 Стандартный вывод CGI приложения. | |
| 232 | |
| 233 =item C< streamBody > | |
| 234 | |
| 235 Поток для записи в тело ответа. | |
| 236 | |
| 237 =item C< isHeadPrinted > | |
| 238 | |
| 239 Признак того, что заголовок уже был отправлен клиенту. | |
| 240 | |
| 241 =back | |
| 242 | |
| 243 =head1 METHODS | |
| 244 | |
| 245 =over | |
| 246 | |
| 247 =item C< Complete > | |
| 248 | |
| 249 Завершает отправку ответа. | |
| 250 | |
| 251 =item C< Discard > | |
| 252 | |
| 253 Отменяет отправку ответа, при этом если часть данных (например, заголовок) | |
| 254 уже была отправлена, выдает предупреждение в STDERR. | |
| 255 | |
| 256 =back | |
| 57 | 257 |
| 258 =cut |
