Changeset 4993
- Timestamp:
- 01/20/08 00:51:09 (5 years ago)
- Location:
- lang/perl/Moxy/trunk
- Files:
-
- 1 removed
- 4 modified
-
Makefile.PL (modified) (2 diffs)
-
config.yaml (modified) (2 diffs)
-
lib/Moxy/Plugin/Application.pm (deleted)
-
lib/Moxy/Plugin/XMLisHTML.pm (modified) (1 diff)
-
lib/Moxy/Server/HTTPProxy.pm (modified) (3 diffs)
Legend:
- Unmodified
- Added
- Removed
-
lang/perl/Moxy/trunk/Makefile.PL
r4942 r4993 7 7 8 8 requires('HTTP::MobileAgent'); 9 requires('HTTP::Proxy');10 9 requires('CGI'); 11 10 requires('FindBin'); … … 21 20 requires('Encode::JP::Mobile' => 0.22); 22 21 requires 'HTML::ReplacePictogramMobileJp' => 0.01; 22 requires 'POE::Component::Server::HTTP' => 0.09; 23 23 24 24 build_requires('Test::More'); -
lang/perl/Moxy/trunk/config.yaml
r4857 r4993 1 1 --- 2 2 global: 3 application:4 host: localhost5 port: 100006 3 storage: 7 4 module: DBM_File … … 28 25 29 26 plugins: 30 - module: Application31 27 - module: Pictogram 32 28 - module: HTMLWidth -
lang/perl/Moxy/trunk/lib/Moxy/Plugin/XMLisHTML.pm
r3983 r4993 7 7 8 8 $context->register_hook( 9 response_filter _header=> sub {9 response_filter => sub { 10 10 my ($context, $args) = @_; 11 11 -
lang/perl/Moxy/trunk/lib/Moxy/Server/HTTPProxy.pm
r4971 r4993 5 5 use Encode; 6 6 use HTTP::Proxy ':log'; 7 use HTTP::Proxy::BodyFilter::simple;8 7 use HTTP::Proxy::HeaderFilter::simple; 9 8 use HTTP::Proxy::BodyFilter::complete; 10 9 use Scalar::Util qw/blessed/; 10 use LWP::UserAgent; 11 use URI; 12 use HTML::Parser; 13 use HTML::Entities; 14 use URI::Escape; 15 use MIME::Base64; 16 17 our $TIMEOUT = 10; # TODO: configurable 11 18 12 19 sub new { … … 23 30 24 31 if ($config->{logmask}) { 25 my $ mask = 0; # this is bitmask.32 my $bitmask = 0; 26 33 for my $const ( @{$config->{logmask}} ) { 27 $mask |= HTTP::Proxy->$const; 28 } 29 $proxy->logmask($mask); 30 } 34 $bitmask |= HTTP::Proxy->$const; 35 } 36 $proxy->logmask($bitmask); 37 } 38 39 $context->register_hook( 40 control_panel => sub { 41 my ($context, $args) = @_; 42 43 my $base = URI->new($args->{response}->request->uri); 44 $base->query_form({}); 45 return $class->_render_control_panel($base, $args->{response}->request->uri); 46 }, 47 ); 31 48 32 49 $proxy->push_filter( 33 50 mime => undef, 51 response => HTTP::Proxy::BodyFilter::complete->new, 34 52 request => HTTP::Proxy::HeaderFilter::simple->new( 35 53 sub { 36 54 my ($filter, $x, $request) = @_; 37 55 38 my $response = $context->run_hook_and_get_response( 39 'request_filter_before_auth', 40 +{ 41 request => $request, # HTTP::Request object 42 } 43 ); 44 if ($response) { 56 my $uri = URI->new($request->uri); 57 $context->log(debug => "Request URI: $uri"); 58 59 my $base = $uri->clone; 60 $base->query_form({}); 61 62 my $auth_header = $request->header('Authorization'); 63 $context->log(debug => "Authorization header: $auth_header"); 64 if ($auth_header =~ /^Basic (.+)$/) { 65 my $auth = decode_base64($1); 66 $context->log(debug => "auth: $auth"); 67 my $url = +{$uri->query_form}->{q}; 68 $context->log(info => "REQUEST $auth, @{[ $url || '' ]}"); 69 my $response = 70 $class->_make_response( $context, $url, $request, $base, 71 $auth ); 45 72 return $filter->proxy->response($response); # finished 46 }47 48 # password is ignored by Moxy.49 my ($user, $pass) = $filter->proxy->hop_headers->proxy_authorization_basic();50 if ($user) {51 $filter->proxy->stash(user => $user);52 73 } else { 53 my $response = HTTP::Response->new( 407, 'Moxy Authentication required' ); 54 $response->header('Proxy-Authenticate' => 'Basic realm="Moxy(password is dummy)"'); 55 return $filter->proxy->response($response); 56 } 57 58 $context->run_hook( 59 'request_filter_process_agent', 60 { request => $request, # HTTP::Request object 61 user => $user, 62 } 63 ); 64 65 my $agent = $context->get_ua_info($_[1]->header('User-Agent')); 66 my $carrier = $agent->{agent} ? HTTP::MobileAgent->new($agent->{agent})->carrier : 'N'; 67 68 for my $hook ('request_filter', "request_filter_$carrier") { 69 my $response = $context->run_hook_and_get_response( 70 $hook, 71 +{ 72 request => $request, # HTTP::Request object 73 agent => $agent, 74 user => $user, 75 } 74 my $response = HTTP::Response->new(401, 'Moxy needs authentication'); 75 $response->header( 'WWW-Authenticate' => 76 qq{Basic realm="Moxy needs basic auth.Only for identification.Password is dummy."} 76 77 ); 77 if ($response) { 78 return $filter->proxy->response($response); # finished 79 } 80 } 81 } 82 ), 83 response => HTTP::Proxy::BodyFilter::complete->new, 84 response => HTTP::Proxy::BodyFilter::simple->new( 85 make_response_filter($context, 'response_filter') 86 ), 87 response => HTTP::Proxy::HeaderFilter::simple->new( 88 make_response_filter($context, 'response_filter_header') 78 $response->content('authentication required'); 79 return $filter->proxy->response($response); # finished 80 } 81 } 89 82 ), 90 83 ); … … 105 98 } 106 99 107 sub make_response_filter { 108 my ($context, $key) = @_; 109 110 return sub { 111 my ($filter, $bodyref, $response) = @_; 112 113 my $agent = $context->get_ua_info($response->request->header('User-Agent')); 114 my $carrier = $agent->{agent} ? HTTP::MobileAgent->new($agent->{agent})->carrier : 'N'; 115 116 for my $hook ($key, "${key}_$carrier") { 117 $context->run_hook( 118 $hook, 119 { response => $response, 120 content_ref => $bodyref, 121 agent => $agent, 122 user => $filter->proxy->stash('user'), 123 } 124 ); 125 } 126 }; 100 sub _render_control_panel { 101 my ($class, $base, $current_url) = @_; 102 103 return sprintf(<<"...", encode_entities($current_url)); 104 <form method="get" action="$base"> 105 <input type="text" name="q" value="\%s" size="40" /> 106 <input type="submit" value="go" /> 107 </form> 108 ... 109 } 110 111 sub _ua { 112 my ($class, $proxy_url) = @_; 113 114 my $ua = LWP::UserAgent->new( 115 timeout => $TIMEOUT, 116 max_redirects => 0, 117 ); 118 $ua; 119 } 120 121 sub _make_response { 122 my ($class, $context, $url, $src_req, $base, $auth) = @_; 123 124 if ($url) { 125 # do proxy 126 my $res = $class->_do_request($context, $src_req, $url, $auth); 127 $context->log(debug => '-- response status: ' . $res->code); 128 129 if ($res->code == 302) { 130 # rewrite redirect 131 $res->header( 'Location' => $base . '?q=' 132 . uri_escape( $res->header('Location') ) ); 133 } else { 134 my $content_type = $res->header('Content-Type'); 135 if ($content_type =~ /html/i) { 136 $res->content( _rewrite($base, $res->content, $url) ); 137 } 138 } 139 return $res; 140 } else { 141 # please input url. 142 my $res = HTTP::Response->new(200, 'about:blank'); 143 $res->header('Content-Type' => 'text/html; charset=utf8'); 144 my $panel = $class->_render_control_panel($base, ''); 145 $res->content(qq{<html><head></head><body>$panel</body></html>}); 146 return $res; 147 } 148 } 149 150 sub _do_request { 151 my ($class, $context, $src_req, $url, $auth) = @_; 152 153 # make request 154 my $req = $src_req->clone; 155 $req->uri($url); 156 $req->header('Host' => URI->new($url)->host); 157 158 $context->run_hook( 159 'request_filter_process_agent', 160 { request => $req, # HTTP::Request object 161 user => $auth, 162 } 163 ); 164 my $agent = $context->get_ua_info($req->header('User-Agent')); 165 my $carrier = $agent->{agent} ? HTTP::MobileAgent->new($agent->{agent})->carrier : 'N'; 166 for my $hook ('request_filter', "request_filter_$carrier") { 167 my $response = $context->run_hook_and_get_response( 168 $hook, 169 +{ 170 request => $req, # HTTP::Request object 171 agent => $agent, 172 user => $auth, 173 } 174 ); 175 if ($response) { 176 return $response; # finished 177 } 178 } 179 180 # do request 181 my $ua = $class->_ua; 182 my $response = $ua->request($req); 183 my $bodyref = \($response->content); 184 for my $hook ('response_filter', "response_filter_$carrier") { 185 $context->run_hook( 186 $hook, 187 { response => $response, # HTTP::Response object 188 content_ref => $bodyref, # response body's scalarref. 189 agent => $agent, 190 user => $auth, 191 } 192 ); 193 } 194 $response->content($$bodyref); 195 $response; 196 } 197 198 sub _rewrite { 199 my ($base, $html, $url) = @_; 200 201 my $output = ''; 202 my $base_url = URI->new($url); 203 my $parser = HTML::Parser->new( 204 api_version => 3, 205 start_h => [ sub { 206 my ($tagname, $attr, $orig) = @_; 207 208 if ($tagname eq 'a' || $tagname eq 'A') { 209 $output .= "<$tagname"; 210 my @parts; 211 my $href = delete $attr->{href}; 212 if ($href) { 213 $output .= " "; 214 push @parts, 215 sprintf( qq{href="$base?q=%s"}, 216 uri_escape(URI->new($href)->abs($base_url)) ); 217 } 218 push @parts, map { sprintf qq{%s="%s"}, encode_entities($_), encode_entities($attr->{$_}) } keys %$attr; 219 $output .= join " ", @parts; 220 $output .= ">"; 221 } elsif ($tagname =~ /form/i) { 222 $output .= "<$tagname"; 223 my @parts; 224 my $action = delete $attr->{action}; 225 if ($action) { 226 $output .= " "; 227 push @parts, sprintf(qq{action="$base?q=%s"}, 228 uri_escape(URI->new($action)->abs($base_url)) 229 ); 230 } 231 push @parts, map { sprintf qq{$_="%s"}, encode_entities($attr->{$_}) } keys %$attr; 232 $output .= join " ", @parts; 233 $output .= ">"; 234 } elsif ($tagname =~ /img/i) { 235 $output .= "<$tagname"; 236 my @parts; 237 my $src = delete $attr->{src}; 238 if ($src) { 239 $output .= " "; 240 push @parts, sprintf(qq{src="$base?q=%s"}, 241 uri_escape(URI->new($src)->abs($base_url)) 242 ); 243 } 244 push @parts, map { sprintf qq{%s="%s"}, encode_entities($_), encode_entities($attr->{$_}) } grep !/^\/$/, keys %$attr; 245 $output .= join " ", @parts; 246 $output .= ">"; 247 } else { 248 $output .= $orig; 249 return; 250 } 251 }, "tagname, attr, text" ], 252 end_h => [ sub { $output .= shift }, "text"], 253 text_h => [ sub { $output .= shift }, "text"], 254 ); 255 256 $parser->boolean_attribute_value('__BOOLEAN__'); 257 $parser->parse($html); 258 $output; 127 259 } 128 260
![(please configure the [header_logo] section in trac.ini)](/share/chrome/site/your_project_logo.png)