| 112 | | my $tree_parser = XML::Parser::Lite::Tree::instance(); |
| 113 | | my $tree = $tree_parser->parse( $server->request_content ); |
| 114 | | my $items = $tree->{children}->[0]->{children}; |
| 115 | | |
| 116 | | $atom = XML::Atom::Entry->new; |
| 117 | | foreach my $item (@{$items}) { |
| 118 | | if ($item->{name} eq 'title') { |
| 119 | | $atom->title($item->{children}->[0]->{content}); |
| 120 | | } |
| 121 | | if ($item->{name} eq 'content') { |
| 122 | | my $content = XML::Atom::Content->new; |
| 123 | | my $data = to_xml(get_content_node($item)); |
| 124 | | $content->mode($item->{children}->[0]->{mode}); |
| 125 | | $content->type($item->{children}->[0]->{type}); |
| 126 | | $content->body($data); |
| 127 | | $atom->content($content); |
| 128 | | } |
| 129 | | if ($item->{name} eq 'category') { |
| 130 | | my $category = XML::Atom::Category->new; |
| 131 | | $category->term($item->{attributes}->{term}); |
| 132 | | $category->label($item->{attributes}->{label}); |
| 133 | | $atom->category($category); |
| 134 | | } |
| 135 | | if ($item->{name} eq 'link') { |
| 136 | | my $link = XML::Atom::Link->new; |
| 137 | | $link->rel($item->{attributes}->{type}); |
| 138 | | $link->type($item->{attributes}->{type}); |
| 139 | | $link->href($item->{attributes}->{href}); |
| 140 | | $atom->add_link( $link ); |
| 141 | | } |
| 142 | | if ($item->{name} eq 'category') { |
| 143 | | my $category = XML::Atom::Category->new; |
| 144 | | $category->term($item->{attributes}->{term}); |
| 145 | | $category->label($item->{attributes}->{label}); |
| 146 | | $atom->category($category); |
| 147 | | } |
| 148 | | if ($item->{name} eq 'subject') { |
| 149 | | my $dc = XML::Atom::Namespace->new(dc => 'http://purl.org/dc/elements/1.1/'); |
| 150 | | for my $sub (@{$item->{children}}) { |
| 151 | | $atom->add($dc, 'subject', $sub->{content}); |
| 152 | | } |
| 153 | | } |
| | 131 | my $tree_parser = XML::Parser::Lite::Tree::instance(); |
| | 132 | my $tree = $tree_parser->parse( $server->request_content ); |
| | 133 | my $items = $tree->{children}->[0]->{children}; |
| | 134 | |
| | 135 | $atom = XML::Atom::Server::Lite::Entry->new; |
| | 136 | foreach my $item (@{$items}) { |
| | 137 | if ($item->{name} eq 'title') { |
| | 138 | $atom->title($item->{children}->[0]->{content}); |
| | 139 | } |
| | 140 | if ($item->{name} eq 'content') { |
| | 141 | my $content = {}; |
| | 142 | my $data = to_xml(get_content_node($item)); |
| | 143 | $content->{mode} = $item->{children}->[0]->{mode}; |
| | 144 | $content->{type} = $item->{children}->[0]->{type}; |
| | 145 | $content->{body} = $data; |
| | 146 | $atom->content($content); |
| | 147 | } |
| | 148 | if ($item->{name} eq 'category') { |
| | 149 | my $category = {}; |
| | 150 | $category->{term} = $item->{attributes}->{term}; |
| | 151 | $category->{label} = $item->{attributes}->{label}; |
| | 152 | $atom->category($category); |
| | 153 | } |
| | 154 | if ($item->{name} eq 'link') { |
| | 155 | my $link = {}; |
| | 156 | $link->{rel} = $item->{attributes}->{type}; |
| | 157 | $link->{type} = $item->{attributes}->{type}; |
| | 158 | $link->{href} = $item->{attributes}->{href}; |
| | 159 | $atom->link($link); |
| | 160 | } |
| | 161 | if ($item->{name} eq 'dc:subject') { |
| | 162 | for my $sub (@{$item->{children}}) { |
| | 163 | $atom->subject($sub->{content}); |
| | 164 | } |
| | 165 | } |
| | 168 | } |
| | 169 | |
| | 170 | sub run { |
| | 171 | my $server = shift; |
| | 172 | (my $pi = $server->path_info) =~ s!^/!!; |
| | 173 | my @args = split /\//, $pi; |
| | 174 | for my $arg (@args) { |
| | 175 | my($k, $v) = split /=/, $arg, 2; |
| | 176 | $server->request_param($k, $v); |
| | 177 | } |
| | 178 | my $out; |
| | 179 | eval { |
| | 180 | defined($out = $server->handle_request) or die $server->errstr; |
| | 181 | }; |
| | 182 | if ($@) { |
| | 183 | $out = $server->show_error($@); |
| | 184 | } |
| | 185 | $server->send_http_header; |
| | 186 | $server->print($out); |
| | 187 | 1; |
| | 188 | } |
| | 189 | |
| | 190 | sub request_param { |
| | 191 | my $server = shift; |
| | 192 | my $k = shift; |
| | 193 | $server->{param}{$k} = shift if @_; |
| | 194 | $server->{param}{$k}; |
| | 195 | } |
| | 196 | |
| | 197 | sub request_header { |
| | 198 | my $server = shift; |
| | 199 | my($key) = @_; |
| | 200 | if ($ENV{MOD_PERL}) { |
| | 201 | return $server->{apache}->header_in($key); |
| | 202 | } else { |
| | 203 | ($key = uc($key)) =~ tr/-/_/; |
| | 204 | return $ENV{'HTTP_' . $key}; |
| | 205 | } |
| | 206 | } |
| | 207 | |
| | 208 | sub request_method { |
| | 209 | my $server = shift; |
| | 210 | if (@_) { |
| | 211 | $server->{request_method} = shift; |
| | 212 | } elsif (!exists $server->{request_method}) { |
| | 213 | $server->{request_method} = |
| | 214 | $ENV{MOD_PERL} ? $server->{apache}->method : $ENV{REQUEST_METHOD}; |
| | 215 | } |
| | 216 | $server->{request_method}; |
| | 217 | } |
| | 218 | |
| | 219 | sub request_content { |
| | 220 | my $server = shift; |
| | 221 | unless (exists $server->{request_content}) { |
| | 222 | if ($ENV{MOD_PERL}) { |
| | 223 | ## Read from $server->{apache} |
| | 224 | my $r = $server->{apache}; |
| | 225 | my $len = $server->request_header('Content-length'); |
| | 226 | $r->read($server->{request_content}, $len); |
| | 227 | } else { |
| | 228 | ## Read from STDIN |
| | 229 | my $len = $ENV{CONTENT_LENGTH} || 0; |
| | 230 | read STDIN, $server->{request_content}, $len; |
| | 231 | } |
| | 232 | } |
| | 233 | $server->{request_content}; |
| | 234 | } |
| | 235 | |
| | 236 | sub path_info { |
| | 237 | my $server = shift; |
| | 238 | return $server->{__path_info} if exists $server->{__path_info}; |
| | 239 | my $path_info; |
| | 240 | if ($ENV{MOD_PERL}) { |
| | 241 | ## mod_perl often leaves part of the script name (Location) |
| | 242 | ## in the path info, for some reason. This should remove it. |
| | 243 | $path_info = $server->{apache}->path_info; |
| | 244 | if ($path_info) { |
| | 245 | my($script_last) = $server->{apache}->location =~ m/\/([^\/]+)$/; |
| | 246 | $path_info =~ s/^\/$script_last//; |
| | 247 | } |
| | 248 | } else { |
| | 249 | $path_info = $server->{cgi}->path_info; |
| | 250 | } |
| | 251 | $server->{__path_info} = $path_info; |
| | 252 | } |
| | 253 | |
| | 254 | sub get_auth_info { |
| | 255 | my $server = shift; |
| | 256 | my %param; |
| | 257 | my $req = $server->request_header('X-WSSE') |
| | 258 | or return $server->auth_failure(401, 'X-WSSE authentication required'); |
| | 259 | $req =~ s/^(?:WSSE|UsernameToken) //; |
| | 260 | for my $i (split /,\s*/, $req) { |
| | 261 | my($k, $v) = split /=/, $i, 2; |
| | 262 | $v =~ s/^"//; |
| | 263 | $v =~ s/"$//; |
| | 264 | $param{$k} = $v; |
| | 265 | } |
| | 266 | \%param; |
| | 267 | } |
| | 268 | |
| | 269 | sub authenticate { |
| | 270 | my $server = shift; |
| | 271 | my $auth = $server->get_auth_info or return; |
| | 272 | for my $f (qw( Username PasswordDigest Nonce Created )) { |
| | 273 | return $server->auth_failure(400, "X-WSSE requires $f") |
| | 274 | unless $auth->{$f}; |
| | 275 | } |
| | 276 | my $password = $server->password_for_user($auth->{Username}); |
| | 277 | defined($password) or return $server->auth_failure(403, 'Invalid login'); |
| | 278 | my $expected = encode_base64(sha1( |
| | 279 | decode_base64($auth->{Nonce}) . $auth->{Created} . $password |
| | 280 | ), ''); |
| | 281 | return $server->auth_failure(403, 'Invalid login') |
| | 282 | unless $expected eq $auth->{PasswordDigest}; |
| | 283 | return 1; |
| | 284 | } |
| | 285 | |
| | 286 | sub auth_failure { |
| | 287 | my $server = shift; |
| | 288 | $server->response_header('WWW-Authenticate', 'WSSE profile="UsernameToken"'); |
| | 289 | return $server->error(@_); |
| | 290 | } |
| | 291 | |
| | 292 | my %Map = ('&' => '&', '"' => '"', '<' => '<', '>' => '>', |
| | 293 | '\'' => '''); |
| | 294 | my $RE = join '|', keys %Map; |
| | 295 | sub encode_xml { |
| | 296 | my($str) = @_; |
| | 297 | $str =~ s!($RE)!$Map{$1}!g; |
| | 298 | $str; |
| | 299 | } |
| | 300 | |
| | 301 | sub error { |
| | 302 | my $server = shift; |
| | 303 | my($code, $msg) = @_; |
| | 304 | $server->response_code($code) if ref($server); |
| | 305 | return $server->_error($msg); |
| | 306 | } |
| | 307 | |
| | 308 | use vars qw( $ERROR ); |
| | 309 | sub _error { |
| | 310 | my $msg = $_[1] || ''; |
| | 311 | $msg .= "\n" unless $msg =~ /\n$/; |
| | 312 | if (ref($_[0])) { |
| | 313 | $_[0]->{_errstr} = $msg; |
| | 314 | } else { |
| | 315 | $ERROR = $msg; |
| | 316 | } |
| | 317 | return; |
| | 318 | } |
| | 319 | |
| | 320 | sub errstr { ref($_[0]) ? $_[0]->{_errstr} : $ERROR } |
| | 321 | |
| | 322 | sub show_error { |
| | 323 | my $server = shift; |
| | 324 | my($err) = @_; |
| | 325 | chomp($err = encode_xml($err)); |
| | 326 | return <<ERR; |
| | 327 | <?xml version="1.0" encoding="utf-8"?> |
| | 328 | <error>$err</error> |
| | 329 | ERR |
| | 330 | } |
| | 331 | |
| | 332 | sub response_header { |
| | 333 | my $server = shift; |
| | 334 | my($key, $val) = @_; |
| | 335 | if ($ENV{MOD_PERL}) { |
| | 336 | $server->{apache}->header_out($key, $val); |
| | 337 | } else { |
| | 338 | unless ($key =~ /^-/) { |
| | 339 | ($key = lc($key)) =~ tr/-/_/; |
| | 340 | $key = '-' . $key; |
| | 341 | } |
| | 342 | $server->{cgi_headers}{$key} = $val; |
| | 343 | } |
| | 344 | } |
| | 345 | |
| | 346 | sub response_code { |
| | 347 | my $server = shift; |
| | 348 | $server->{response_code} = shift if @_; |
| | 349 | $server->{response_code}; |
| | 350 | } |
| | 351 | |
| | 352 | sub response_content_type { |
| | 353 | my $server = shift; |
| | 354 | $server->{response_content_type} = shift if @_; |
| | 355 | $server->{response_content_type}; |
| | 356 | } |
| | 357 | sub send_http_header { |
| | 358 | my $server = shift; |
| | 359 | my $type = $server->response_content_type || 'application/x.atom+xml'; |
| | 360 | if ($ENV{MOD_PERL}) { |
| | 361 | $server->{apache}->status($server->response_code || 200); |
| | 362 | $server->{apache}->send_http_header($type); |
| | 363 | } else { |
| | 364 | $server->{cgi_headers}{-status} = $server->response_code || 200; |
| | 365 | $server->{cgi_headers}{-type} = $type; |
| | 366 | print $server->{cgi}->header(%{ $server->{cgi_headers} }); |
| | 367 | } |
| | 368 | } |
| | 369 | |
| | 370 | sub print { |
| | 371 | my $server = shift; |
| | 372 | if ($ENV{MOD_PERL}) { |
| | 373 | $server->{apache}->print(@_); |
| | 374 | } else { |
| | 375 | CORE::print(@_); |
| | 376 | } |