| File: | lib/OpenAPI/Dispatcher.pm |
| Coverage: | 83.6% |
| line | stmt | bran | cond | sub | pod | time | code |
|---|---|---|---|---|---|---|---|
| 1 | package OpenAPI::Dispatcher; | ||||||
| 2 | |||||||
| 3 | 22 22 22 | 190 66 177 | use strict; | ||||
| 4 | 22 22 22 | 241 74 169 | use warnings; | ||||
| 5 | |||||||
| 6 | #use Smart::Comments; | ||||||
| 7 | 22 22 22 | 299 88 280 | use Data::UUID; | ||||
| 8 | 22 22 22 | 324 81 263 | use OpenAPI::Limits; | ||||
| 9 | 22 22 22 | 306 109 343 | use OpenAPI::Cache; | ||||
| 10 | 22 22 22 | 345 112 246 | use OpenAPI; | ||||
| 11 | 22 22 22 | 291 74 299 | use OpenAPI::Config; | ||||
| 12 | |||||||
| 13 | our $InitFatal; | ||||||
| 14 | |||||||
| 15 | # XXX Excpetion not caputred...when database 'test' not created. | ||||||
| 16 | my %Dispatcher = ( | ||||||
| 17 | model => [ | ||||||
| 18 | qw< model_list model model_column model_row > | ||||||
| 19 | ], | ||||||
| 20 | view => [ | ||||||
| 21 | qw< view_list view view_param view_exec > | ||||||
| 22 | ], | ||||||
| 23 | action => [ | ||||||
| 24 | qw< action_list action action_param action_exec > | ||||||
| 25 | ], | ||||||
| 26 | admin => [ | ||||||
| 27 | qw< admin admin_op > | ||||||
| 28 | ], | ||||||
| 29 | role => [ | ||||||
| 30 | qw< role_list role access_rule_column access_rule > | ||||||
| 31 | ], | ||||||
| 32 | login => [ | ||||||
| 33 | qw< login login_user login_user_password > | ||||||
| 34 | ], | ||||||
| 35 | captcha => [ | ||||||
| 36 | qw< captcha_list captcha_column captcha_value > | ||||||
| 37 | ], | ||||||
| 38 | version => [ qw< version > ], | ||||||
| 39 | ); | ||||||
| 40 | |||||||
| 41 | my $url_prefix = $ENV{OPENAPI_URL_PREFIX}; | ||||||
| 42 | if ($url_prefix) { | ||||||
| 43 | $url_prefix =~ s{^/+|/+$}{}g; | ||||||
| 44 | } | ||||||
| 45 | |||||||
| 46 | sub init { | ||||||
| 47 | 22 | 0 | 133 | $CGI::POST_MAX = $POST_LEN_LIMIT; # max 100 K posts | |||
| 48 | 22 | 96 | $CGI::DISABLE_UPLOADS = 1; # no uploads | ||||
| 49 | 22 | 206 | OpenAPI::Config->init; | ||||
| 50 | 22 | 406 | my $backend = $OpenAPI::Config{'backend.type'}; | ||||
| 51 | 22 | 95 | eval { | ||||
| 52 | 22 | 316 | $OpenAPI::Cache = OpenAPI::Cache->new; | ||||
| 53 | 22 | 227 | OpenAPI->connect($backend); | ||||
| 54 | }; | ||||||
| 55 | 22 | 247 | if ($@) { | ||||
| 56 | 0 | 0 | $InitFatal = $@; | ||||
| 57 | } | ||||||
| 58 | } | ||||||
| 59 | |||||||
| 60 | sub process_request { | ||||||
| 61 | 602 | 0 | 4114 | my ($class, $cgi) = @_; | |||
| 62 | 602 | 4459 | my $url = $ENV{REQUEST_URI}; | ||||
| 63 | ### $url | ||||||
| 64 | 602 | 3752 | $url =~ s/\?.*//g; | ||||
| 65 | #my $url = $cgi->url(-absolute=>1,-path_info=>1); | ||||||
| 66 | 602 | 5389 | $url =~ s{^/+}{}g; | ||||
| 67 | ### Old URL: $url | ||||||
| 68 | ### URL Prefox: $url_prefix | ||||||
| 69 | |||||||
| 70 | 602 | 3538 | $url =~ s{^\Q$url_prefix\E/+}{}g if $url_prefix; ### New URL: $url | ||||
| 71 | |||||||
| 72 | 602 | 5644 | my $openapi = OpenAPI->new($cgi); | ||||
| 73 | 602 | 3795 | if ($InitFatal) { | ||||
| 74 | 0 | 0 | $openapi->fatal($InitFatal); | ||||
| 75 | 0 | 0 | return; | ||||
| 76 | } | ||||||
| 77 | |||||||
| 78 | 602 | 2431 | eval { | ||||
| 79 | 602 | 4720 | $openapi->init(\$url); | ||||
| 80 | }; | ||||||
| 81 | 602 | 3708 | if ($@) { | ||||
| 82 | ### Exception in new: $@ | ||||||
| 83 | 5 | 40 | $openapi->fatal($@); | ||||
| 84 | 5 | 236 | return; | ||||
| 85 | } | ||||||
| 86 | |||||||
| 87 | #$url =~ s/\/+$//g; | ||||||
| 88 | #print "page: ", url_param("page"), "\n"; | ||||||
| 89 | #warn "Hello!"; | ||||||
| 90 | #print "charset: ", url_param("charset"), "\n"; | ||||||
| 91 | |||||||
| 92 | 597 | 7143 | my @bits = split /\//, $url, 5; | ||||
| 93 | |||||||
| 94 | 597 | 3947 | if (!@bits) { | ||||
| 95 | ### Unknown URL: $url | ||||||
| 96 | 0 | 0 | $openapi->fatal("Unknown URL: $url"); | ||||
| 97 | 0 | 0 | return; | ||||
| 98 | } | ||||||
| 99 | |||||||
| 100 | 597 2234 6 | 2941 10022 52 | map { s/%([0-9A-Fa-f]{2})/chr(hex($1))/eg; } @bits; | ||||
| 101 | ## @bits | ||||||
| 102 | |||||||
| 103 | 597 | 3897 | my $fst = shift @bits; | ||||
| 104 | 597 | 4054 | if ($fst ne '=') { | ||||
| 105 | 0 | 0 | $openapi->fatal("URLs must be led by '=': $url"); | ||||
| 106 | 0 | 0 | return; | ||||
| 107 | } | ||||||
| 108 | |||||||
| 109 | 597 | 3755 | my $http_meth = $openapi->{'_http_method'}; | ||||
| 110 | 597 | 3024 | if (!$http_meth) { | ||||
| 111 | 0 | 0 | $openapi->fatal("HTTP method not detected."); | ||||
| 112 | 0 | 0 | return; | ||||
| 113 | } | ||||||
| 114 | ### $http_meth | ||||||
| 115 | |||||||
| 116 | # XXX hacks... | ||||||
| 117 | 597 | 5679 | my $cookies = CGI::Cookie->fetch; | ||||
| 118 | 597 | 5548 | my ($session_from_cookie, $captcha_from_cookie, $response_from_cookie); | ||||
| 119 | 597 | 1764 | my $session; | ||||
| 120 | 597 | 3489 | if ($cookies) { | ||||
| 121 | 558 | 3125 | my $cookie = $cookies->{session}; | ||||
| 122 | 558 | 1419 | if ($cookie) { | ||||
| 123 | 548 | 11059 | $openapi->{_session_from_cookie} = | ||||
| 124 | $session_from_cookie = $cookie->value; | ||||||
| 125 | } | ||||||
| 126 | 558 | 23014 | $cookie = $cookies->{captcha}; | ||||
| 127 | 558 | 2875 | if ($cookie) { | ||||
| 128 | 41 | 860 | $openapi->{_captcha_from_cookie} = | ||||
| 129 | $captcha_from_cookie = $cookie->value; | ||||||
| 130 | #$OpenAPI::Cache->remove($captcha_from_cookie); | ||||||
| 131 | } | ||||||
| 132 | 558 | 2132 | if ($cookie = $cookies->{last_response}) { | ||||
| 133 | 503 | 10847 | $response_from_cookie = $cookie->value; | ||||
| 134 | } | ||||||
| 135 | } | ||||||
| 136 | |||||||
| 137 | 597 | 28254 | if ($http_meth eq 'GET' and @bits >= 2 and $bits[0] eq 'last' and $bits[1] eq 'response') { | ||||
| 138 | 5 | 42 | $openapi->{_bin_data} = $response_from_cookie . "\n"; | ||||
| 139 | 5 | 37 | $openapi->response; | ||||
| 140 | 5 | 76 | return; | ||||
| 141 | } | ||||||
| 142 | |||||||
| 143 | 592 | 2930 | my ($account, $role); | ||||
| 144 | 592 | 10256 | if ($bits[0] and $bits[0] !~ /^(?:login|captcha|version)$/) { | ||||
| 145 | 539 | 2636 | eval { | ||||
| 146 | # XXX this part is lame... | ||||||
| 147 | 539 | 4166 | my $user = $cgi->url_param('user'); | ||||
| 148 | 539 | 3191 | if (defined $user) { | ||||
| 149 | #$OpenAPI::Cache->remove($uuid); | ||||||
| 150 | 43 | 309 | my $captcha = $cgi->url_param('captcha'); | ||||
| 151 | ### URL param capture: $captcha | ||||||
| 152 | 43 | 384 | my $res = $openapi->login($user, { | ||||
| 153 | password => scalar($cgi->url_param('password')), | ||||||
| 154 | captcha => $captcha, | ||||||
| 155 | }); | ||||||
| 156 | 30 | 280 | $account = $res->{account}; | ||||
| 157 | 30 | 243 | $role = $res->{role}; | ||||
| 158 | # XXX login as $account.$role... | ||||||
| 159 | # XXX if account is anonymous, then create a session | ||||||
| 160 | # XXX else check password, if correct, create a session | ||||||
| 161 | } else { | ||||||
| 162 | 496 | 6998 | my $session = $openapi->{_session} || $session_from_cookie; | ||||
| 163 | 496 | 2618 | if ($session) { | ||||
| 164 | 490 | 4533 | my $user = $OpenAPI::Cache->get($session); | ||||
| 165 | ### User from cookie: $user | ||||||
| 166 | 490 | 7892 | if ($user) { | ||||
| 167 | 490 | 4901 | ($account, $role) = split /\./, $user, 2; | ||||
| 168 | } | ||||||
| 169 | ### $account | ||||||
| 170 | ### $role | ||||||
| 171 | } | ||||||
| 172 | } | ||||||
| 173 | |||||||
| 174 | # this part is lame? | ||||||
| 175 | 526 | 3386 | if (!$account) { | ||||
| 176 | 6 | 22 | die "Login required.\n"; | ||||
| 177 | } | ||||||
| 178 | 520 | 4280 | if (!$openapi->has_user($account)) { | ||||
| 179 | ### Found user: $user | ||||||
| 180 | 0 | 0 | die "Account \"$account\" does not exist.\n"; | ||||
| 181 | } | ||||||
| 182 | 520 | 14018 | $openapi->set_user($account); | ||||
| 183 | |||||||
| 184 | 520 | 3362 | $role ||= 'Admin'; | ||||
| 185 | 520 | 5093 | if (!$openapi->has_role($role)) { | ||||
| 186 | ### Found user: $user | ||||||
| 187 | 0 | 0 | die "Role \"$role\" does not exist.\n"; | ||||
| 188 | } | ||||||
| 189 | 520 | 27620 | $openapi->set_role($role); | ||||
| 190 | }; | ||||||
| 191 | 539 | 3918 | if ($@) { | ||||
| 192 | 19 | 170 | $openapi->fatal($@); | ||||
| 193 | 19 | 1229 | return; | ||||
| 194 | } | ||||||
| 195 | } | ||||||
| 196 | |||||||
| 197 | # XXX check ACL rules... | ||||||
| 198 | 573 | 11804 | if ($bits[0] and $bits[0] !~ /^(?:login|captcha|version)$/) { | ||||
| 199 | 520 | 5792 | my $res = $openapi->current_user_can($http_meth => \@bits); | ||||
| 200 | 520 | 4546 | if (!$res) { | ||||
| 201 | 22 | 291 | $openapi->fatal("Permission denied for the \"$role\" role."); | ||||
| 202 | 22 | 1298 | return; | ||||
| 203 | } | ||||||
| 204 | } else { | ||||||
| 205 | } | ||||||
| 206 | |||||||
| 207 | 551 | 5514 | my $category = $Dispatcher{$bits[0]}; | ||||
| 208 | 551 | 3082 | if ($category) { | ||||
| 209 | 551 | 4801 | my $object = $category->[$#bits]; | ||||
| 210 | ### $object | ||||||
| 211 | 551 | 3532 | if (!defined $object) { | ||||
| 212 | 0 | 0 | $openapi->fatal("Unknown URL level: $url"); | ||||
| 213 | 0 | 0 | return; | ||||
| 214 | } | ||||||
| 215 | 551 | 3894 | my $meth = $http_meth . '_' . $object; | ||||
| 216 | 551 | 2998 | $meth =~ s/\./_/g; | ||||
| 217 | 551 | 8795 | if (!$openapi->can($meth)) { | ||||
| 218 | 0 | 0 | $object =~ s/_/ /g; | ||||
| 219 | 0 | 0 | $openapi->fatal("HTTP $http_meth method not supported for $object."); | ||||
| 220 | 0 | 0 | return; | ||||
| 221 | } | ||||||
| 222 | 551 | 2108 | my $data; | ||||
| 223 | 551 | 2138 | eval { | ||||
| 224 | 551 | 3778 | if ($bits[0] eq 'model') { | ||||
| 225 | 311 | 3451 | $openapi->global_model_check(\@bits, $http_meth); | ||||
| 226 | } | ||||||
| 227 | |||||||
| 228 | 529 | 7395 | $data = $openapi->$meth(\@bits); | ||||
| 229 | }; | ||||||
| 230 | 551 | 9545 | if ($@) { | ||||
| 231 | 113 | 1075 | $openapi->fatal($@); | ||||
| 232 | 113 | 7245 | return; | ||||
| 233 | } | ||||||
| 234 | 438 | 4434 | $openapi->data($data); | ||||
| 235 | 438 | 3370 | $openapi->response(); | ||||
| 236 | } else { | ||||||
| 237 | 0 | $openapi->fatal("Unknown URL catagory: $bits[0]"); | |||||
| 238 | } | ||||||
| 239 | } | ||||||
| 240 | |||||||
| 241 | 1; | ||||||