Skip to content

Commit b1bb15e

Browse files
committedJul 13, 2012
Merge branch 'plebgui' into plebgui-7.10
Conflicts: lib/WebGUI.pm
2 parents 9ba3022 + eb24698 commit b1bb15e

12 files changed

+468
-13
lines changed
 

‎apache.conf

+27
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
<VirtualHost *:80>
2+
PerlOptions +Parent
3+
PerlSwitches -I/data/WebGUI/lib
4+
5+
# CGI
6+
#AddHandler cgi-script cgi
7+
#ScriptAlias / /data/WebGUI/etc/dev.localhost.localdomain.cgi/
8+
#<Directory /data/WebGUI/etc>
9+
# Options +ExecCGI
10+
#</Directory>
11+
12+
# Apache2
13+
#SetHandler perl-script
14+
#PerlHandler Plack::Server::Apache2
15+
#PerlSetVar psgi_app /data/WebGUI/etc/dev.localhost.localdomain.psgi
16+
17+
# FastCGI
18+
FastCgiServer /data/WebGUI/etc/dev.localhost.localdomain.fcgi
19+
ScriptAlias / /data/WebGUI/etc/dev.localhost.localdomain.fcgi/
20+
21+
# mod_psgi
22+
#<Location />
23+
# SetHandler psgi
24+
# PSGIApp /data/WebGUI/etc/dev.localhost.localdomain.psgi
25+
#</Location>
26+
27+
</VirtualHost>

‎etc/dev.localhost.localdomain.cgi

+5
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
#!/usr/bin/perl
2+
use Plack::Server::CGI;
3+
4+
my $app = Plack::Util::load_psgi("/data/WebGUI/etc/dev.localhost.localdomain.psgi");
5+
Plack::Server::CGI->new->run($app);

‎etc/dev.localhost.localdomain.fcgi

+5
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
#!/usr/bin/perl
2+
use Plack::Server::FCGI;
3+
4+
my $app = Plack::Util::load_psgi("/data/WebGUI/etc/dev.localhost.localdomain.psgi");
5+
Plack::Server::FCGI->new->run($app);

‎etc/dev.localhost.localdomain.perlbal

+7
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
LOAD PSGI
2+
CREATE SERVICE psgi
3+
SET role = web_server
4+
SET listen = 127.0.0.1:80
5+
SET plugins = psgi
6+
PSGI_APP = dev.localhost.localdomain.psgi
7+
ENABLE psgi

‎etc/dev.localhost.localdomain.psgi

+25
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
use Plack::Builder;
2+
use lib '/data/WebGUI/lib';
3+
use WebGUI;
4+
WebGUI->init( root => '/data/WebGUI', config => 'dev.localhost.localdomain.conf' );
5+
6+
builder {
7+
8+
# Handle /extras via Plack::Middleware::Static
9+
# (or Plack::Middleware::WebGUI could do this for us by looking up extrasPath and extrasURL in site.conf)
10+
enable 'Plack::Middleware::Static',
11+
path => qr{^/extras/},
12+
root => '/data/WebGUI/www';
13+
14+
# Handle /uploads via Plack::Middleware::WGAccess (including .wgaccess)
15+
# (or Plack::Middleware::WebGUI could do this for us by looking up uploadsPath and uploadsURL in site.conf)
16+
#enable 'Plack::Middleware::WGAccess',
17+
# path => qr{^/uploads/},
18+
# root => '/data/domains/dev.localhost.localdomain/public';
19+
20+
enable 'Plack::Middleware::Static',
21+
path => qr{^/uploads/},
22+
root => '/data/domains/dev.localhost.localdomain/public';
23+
24+
sub { WebGUI::handle_psgi(shift) };
25+
}

‎lib/Plack/Middleware/WGAccess.pm

+96
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,96 @@
1+
package Plack::Middleware::WGAccess;
2+
use strict;
3+
use warnings;
4+
use base qw/Plack::Middleware::Static/;
5+
use Path::Class 'dir';
6+
7+
=head1 NAME
8+
9+
Plack::Middleware::WGAccess
10+
11+
=head1 DESCRIPTION
12+
13+
Plack Middleware that delivers static files with .wgaccess awareness
14+
15+
=cut
16+
17+
sub _handle_static {
18+
my($self, $env) = @_;
19+
20+
#######################################
21+
# Copied from Plack::Middleware::Static::_handle_static
22+
23+
my $path_match = $self->path or return;
24+
25+
if ($env->{PATH_INFO} =~ m!\.\.[/\\]!) {
26+
return $self->return_403;
27+
}
28+
29+
my $path = do {
30+
my $matched;
31+
local $_ = $env->{PATH_INFO};
32+
if (ref $path_match eq 'CODE') {
33+
$matched = $path_match->($_);
34+
} else {
35+
$matched = $_ =~ $path_match;
36+
}
37+
return unless $matched;
38+
$_;
39+
} or return;
40+
41+
my $docroot = dir($self->root || ".");
42+
my $file = $docroot->file(File::Spec::Unix->splitpath($path));
43+
my $realpath = Cwd::realpath($file->absolute->stringify);
44+
45+
# Is the requested path within the root?
46+
if ($realpath && !$docroot->subsumes($realpath)) {
47+
return $self->return_403;
48+
}
49+
50+
# Does the file actually exist?
51+
if (!$realpath || !-f $file) {
52+
return $self->return_404;
53+
}
54+
55+
# If the requested file present but lacking the permission to read it?
56+
if (!-r $file) {
57+
return $self->return_403;
58+
}
59+
60+
###############################
61+
# Copied from WebGUI::URL::Uploads
62+
my $wgaccess = File::Spec::Unix->catfile($file->dir, '.wgaccess');
63+
if (-e $wgaccess) {
64+
my $fileContents;
65+
open(my $FILE, "<", $wgaccess);
66+
while (my $line = <$FILE>) {
67+
$fileContents .= $line;
68+
}
69+
close($FILE);
70+
my @privs = split("\n", $fileContents);
71+
unless ($privs[1] eq "7" || $privs[1] eq "1") {
72+
73+
# Construct request,server,config in the usual way
74+
require WebGUI::Session::Plack;
75+
my $request = WebGUI::Session::Plack->new( env => $env );
76+
my $server = $request->server;
77+
78+
my $session = $request->pnotes('wgSession');
79+
unless (defined $session) {
80+
$session = WebGUI::Session->open($server->dir_config('WebguiRoot'), $request->dir_config('WebguiConfig'), $request, $server);
81+
}
82+
my $hasPrivs = ($session->var->get("userId") eq $privs[0] || $session->user->isInGroup($privs[1]) || $session->user->isInGroup($privs[2]));
83+
$session->close();
84+
if ($hasPrivs) {
85+
return $self->SUPER::_handle_static($env); # serve statically
86+
}
87+
else {
88+
return $self->return_403;
89+
}
90+
}
91+
} else {
92+
return $self->SUPER::_handle_static($env); # serve statically
93+
}
94+
}
95+
96+
1;

‎lib/Plack/Middleware/WebGUI.pm

+28
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
package Plack::Middleware::WebGUI;
2+
use strict;
3+
use warnings;
4+
use base qw/Plack::Middleware/;
5+
6+
__PACKAGE__->mk_accessors('root', 'config');
7+
8+
=head1 NAME
9+
10+
Plack::Middleware::WebGUI
11+
12+
=head1 DESCRIPTION
13+
14+
Plack Middleware that populates $env
15+
16+
=cut
17+
18+
sub call {
19+
my $self = shift;
20+
my $env = shift;
21+
22+
$env->{'wg.WEBGUI_ROOT'} = $self->root;
23+
$env->{'wg.WEBGUI_CONFIG'} = $self->config;
24+
25+
$self->app->($env);
26+
}
27+
28+
1;

‎lib/WebGUI.pm

+48-11
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@ our $STATUS = 'stable';
2020
=cut
2121

2222
use strict;
23-
use Apache2::Access ();
23+
use Apache2::Access ();
2424
use Apache2::Const -compile => qw(OK DECLINED HTTP_UNAUTHORIZED SERVER_ERROR);
2525
use Apache2::Request;
2626
use Apache2::RequestIO;
@@ -83,9 +83,14 @@ A reference to a WebGUI::Session object.
8383

8484
sub authen {
8585
my ($request, $username, $password, $session) = @_;
86-
$request = Apache2::Request->new($request);
8786
my $log = $session->log;
88-
my $server = Apache2::ServerUtil->server;
87+
my $server;
88+
if ($request->isa('WebGUI::Session::Plack')) {
89+
$server = $request->server;
90+
} else {
91+
$request = Apache2::Request->new($request);
92+
$server = Apache2::ServerUtil->server; #instantiate the server api
93+
}
8994
my $status = Apache2::Const::OK;
9095

9196
# set username and password if it's an auth handler
@@ -148,11 +153,18 @@ The Apache2::RequestRec object passed in by Apache's mod_perl.
148153
=cut
149154

150155
sub handler {
151-
my $request = shift; #start with apache request object
152-
$request = Apache2::Request->new($request);
153-
my $configFile = shift || $request->dir_config('WebguiConfig'); #either we got a config file, or we'll build it from the request object's settings
154-
my $server = Apache2::ServerUtil->server; #instantiate the server api
155-
my $config = WebGUI::Config->new($server->dir_config('WebguiRoot'), $configFile); #instantiate the config object
156+
my $request = shift; # either apache request object or PSGI env hash
157+
my ($server, $config);
158+
if ($request->isa('WebGUI::Session::Plack')) {
159+
$server = $request->server;
160+
$config = WebGUI->config; # use our cached version
161+
} else {
162+
$request = Apache2::Request->new($request);
163+
$server = Apache2::ServerUtil->server; #instantiate the server api
164+
my $configFile = shift || $request->dir_config('WebguiConfig'); #either we got a config file, or we'll build it from the request object's settings
165+
$config = WebGUI::Config->new($server->dir_config('WebguiRoot'), $configFile); #instantiate the config object
166+
}
167+
156168
my $error = "";
157169
my $matchUri = $request->uri;
158170
my $gateway = $config->get("gateway");
@@ -177,18 +189,43 @@ sub handler {
177189
}
178190
}
179191
return Apache2::Const::DECLINED if ($gotMatch);
180-
192+
181193
# can't handle the url due to error or misconfiguration
182-
$request->push_handlers(PerlResponseHandler => sub {
194+
$request->push_handlers(PerlResponseHandler => sub {
183195
print "This server is unable to handle the url '".$request->uri."' that you requested. ".$error;
184196
return Apache2::Const::OK;
185197
} );
186198
$request->push_handlers(PerlTransHandler => sub { return Apache2::Const::OK });
187-
return Apache2::Const::DECLINED;
199+
return Apache2::Const::DECLINED;
188200
}
189201

190202

191203

204+
sub handle_psgi {
205+
my $env = shift;
206+
require WebGUI::Session::Plack;
207+
my $plack = WebGUI::Session::Plack->new( env => $env );
208+
209+
# returns something like Apache2::Const::OK, which we ignore
210+
my $ret = handler($plack);
211+
212+
# let Plack::Response do its thing
213+
return $plack->finalize;
214+
}
215+
216+
# Experimental speed boost
217+
my ($root, $config_file, $config);
218+
sub init {
219+
my $class = shift;
220+
my %opts = @_;
221+
$root = $opts{root};
222+
$config_file = $opts{config};
223+
$config = WebGUI::Config->new($root, $config_file);
224+
warn 'INIT';
225+
}
226+
sub config { $config }
227+
sub root { $root }
228+
sub config_file { $config_file }
192229

193230
1;
194231

‎lib/WebGUI/Session.pm

+14-2
Original file line numberDiff line numberDiff line change
@@ -452,10 +452,22 @@ sub open {
452452
my $configFile = shift;
453453
my $request = shift;
454454
my $server = shift;
455-
my $config = WebGUI::Config->new($webguiRoot,$configFile);
455+
my $config = WebGUI->config || WebGUI::Config->new($webguiRoot,$configFile);
456456
my $self = {_config=>$config, _server=>$server};
457457
bless $self , $class;
458-
$self->{_request} = $request if (defined $request);
458+
459+
# $self->{_request} = $request if (defined $request);
460+
if ($request) {
461+
if ($request->isa('WebGUI::Session::Plack')) {
462+
# Use our WebGUI::Session::Plack object that is supposed to do everything Apache2::* can
463+
$self->{_request} = $request;
464+
} else {
465+
# Use WebGUI::Session::Request to wrap Apache2::* calls
466+
require WebGUI::Session::Request;
467+
$self->{_request} = WebGUI::Session::Request->new( r => $request, session => $self );
468+
}
469+
}
470+
459471
my $sessionId = shift || $self->http->getCookies->{$config->getCookieName} || $self->id->generate;
460472
$sessionId = $self->id->generate unless $self->id->valid($sessionId);
461473
my $noFuss = shift;

‎lib/WebGUI/Session/Http.pm

+14
Original file line numberDiff line numberDiff line change
@@ -93,6 +93,10 @@ Retrieves the cookies from the HTTP header and returns a hash reference containi
9393
sub getCookies {
9494
my $self = shift;
9595
if ($self->session->request) {
96+
if ($self->session->request->isa('WebGUI::Session::Plack')) {
97+
return $self->session->request->{request}->cookies;
98+
}
99+
96100
# Have to require this instead of using it otherwise it causes problems for command-line scripts on some platforms (namely Windows)
97101
require APR::Request::Apache2;
98102
my $jarHashRef = eval { APR::Request::Apache2->handle($self->session->request)->jar(); };
@@ -414,6 +418,16 @@ sub setCookie {
414418
$ttl = (defined $ttl ? $ttl : '+10y');
415419

416420
if ($self->session->request) {
421+
if ( $self->session->request->isa('WebGUI::Session::Plack') ) {
422+
$self->session->request->{response}->cookies->{$name} = {
423+
value => $value,
424+
path => '/',
425+
expires => $ttl ne 'session' ? $ttl : undef,
426+
domain => $domain,
427+
};
428+
}
429+
return;
430+
417431
require Apache2::Cookie;
418432
my $cookie = Apache2::Cookie->new($self->session->request,
419433
-name=>$name,

‎lib/WebGUI/Session/Plack.pm

+159
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,159 @@
1+
package WebGUI::Session::Plack;
2+
3+
use strict;
4+
use warnings;
5+
use Carp;
6+
7+
=head1 DESCRIPTION
8+
9+
This class is used instead of WebGUI::Session::Request when wg is started via plackup
10+
11+
=cut
12+
13+
sub new {
14+
my ( $class, %p ) = @_;
15+
16+
# 'require' rather than 'use' so that non-plebgui doesn't freak out
17+
require Plack::Request;
18+
my $request = Plack::Request->new( $p{env} );
19+
my $response = $request->new_response(200);
20+
21+
bless {
22+
%p,
23+
pnotes => {},
24+
request => $request,
25+
response => $response,
26+
server => WebGUI::Session::Plack::Server->new( env => $p{env} ),
27+
headers_out => Plack::Util::headers( [] ), # use Plack::Util to manage response headers
28+
body => [],
29+
sendfile => undef,
30+
}, $class;
31+
}
32+
33+
our $AUTOLOAD;
34+
35+
sub AUTOLOAD {
36+
my $what = $AUTOLOAD;
37+
$what =~ s/.*:://;
38+
carp "!!plack->$what(@_)" unless $what eq 'DESTROY';
39+
}
40+
41+
# Emulate/delegate/fake Apache2::* subs
42+
sub uri { shift->{request}->path_info }
43+
sub param { shift->{request}->param(@_) }
44+
sub params { shift->{request}->prameters->mixed(@_) }
45+
sub headers_in { shift->{request}->headers(@_) }
46+
sub headers_out { shift->{headers_out} }
47+
sub protocol { shift->{request}->protocol(@_) }
48+
sub status { shift->{response}->status(@_) }
49+
sub sendfile { $_[0]->{sendfile} = $_[1] }
50+
sub server { shift->{server} }
51+
sub method { shift->{request}->method }
52+
sub upload { shift->{request}->upload(@_) }
53+
sub dir_config { shift->{server}->dir_config(@_) }
54+
sub status_line { }
55+
sub auth_type { } # should we support this?
56+
sub handler {'perl-script'} # or not..?
57+
58+
sub content_type {
59+
my ( $self, $ct ) = @_;
60+
$self->{headers_out}->set( 'Content-Type' => $ct );
61+
}
62+
63+
# TODO: I suppose this should do some sort of IO::Handle thing
64+
sub print {
65+
my $self = shift;
66+
push @{ $self->{body} }, @_;
67+
}
68+
69+
sub pnotes {
70+
my ( $self, $key ) = ( shift, shift );
71+
return wantarray ? %{ $self->{pnotes} } : $self->{pnotes} unless defined $key;
72+
return $self->{pnotes}{$key} = $_[0] if @_;
73+
return $self->{pnotes}{$key};
74+
}
75+
76+
sub user {
77+
my ( $self, $user ) = @_;
78+
if ( defined $user ) {
79+
$self->{user} = $user;
80+
}
81+
$self->{user};
82+
}
83+
84+
sub push_handlers {
85+
my $self = shift;
86+
my ( $x, $sub ) = @_;
87+
88+
# log it
89+
# carp "push_handlers($x)";
90+
91+
# run it
92+
# returns something like Apache2::Const::OK, which we just ignore because we're not modperl
93+
my $ret = $sub->($self);
94+
95+
return;
96+
}
97+
98+
sub finalize {
99+
my $self = shift;
100+
my $response = $self->{response};
101+
if ( $self->{sendfile} && open my $fh, '<', $self->{sendfile} ) {
102+
$response->body($fh);
103+
}
104+
else {
105+
$response->body( $self->{body} );
106+
}
107+
$response->headers( $self->{headers_out}->headers );
108+
return $response->finalize;
109+
}
110+
111+
sub no_cache {
112+
my ( $self, $doit ) = @_;
113+
if ($doit) {
114+
$self->{headers_out}->set( 'Pragma' => 'no-cache', 'Cache-control' => 'no-cache' );
115+
}
116+
else {
117+
$self->{headers_out}->remove( 'Pragma', 'Cache-control' );
118+
}
119+
}
120+
121+
################################################
122+
123+
package WebGUI::Session::Plack::Server;
124+
125+
use strict;
126+
use warnings;
127+
use Carp;
128+
129+
sub new {
130+
my $class = shift;
131+
bless {@_}, $class;
132+
}
133+
134+
our $AUTOLOAD;
135+
136+
sub AUTOLOAD {
137+
my $what = $AUTOLOAD;
138+
$what =~ s/.*:://;
139+
carp "!!server->$what(@_)" unless $what eq 'DESTROY';
140+
}
141+
142+
sub dir_config {
143+
my ( $self, $c ) = @_;
144+
145+
# Translate the legacy WebguiRoot and WebguiConfig PerlSetVar's into known values
146+
return WebGUI->root if $c eq 'WebguiRoot';
147+
return WebGUI->config_file if $c eq 'WebguiConfig';
148+
149+
# Otherwise, we might want to provide some sort of support (which Apache is still around)
150+
return $self->{env}->{"wg.DIR_CONFIG.$c"};
151+
}
152+
153+
################################################
154+
155+
package Plack::Request::Upload;
156+
157+
sub link { shift->link_to(@_) }
158+
159+
1;

‎lib/WebGUI/Session/Request.pm

+40
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
package WebGUI::Session::Request;
2+
3+
use strict;
4+
use warnings;
5+
6+
=head1 DESCRIPTION
7+
8+
This class wraps calls to $session->request and logs them as a cute way of seeing
9+
what Apache2::* methods webgui is calling
10+
11+
=cut
12+
13+
sub new {
14+
my $class = shift;
15+
bless { @_ }, $class;
16+
}
17+
18+
our $AUTOLOAD;
19+
sub AUTOLOAD {
20+
my $self = shift;
21+
my $what = $AUTOLOAD;
22+
$what =~ s/.*:://;
23+
my $r = $self->{r};
24+
my $session = $self->{session};
25+
26+
if ( !$r ) {
27+
$session->log->error("!!request->$what(@_) but r not defined");
28+
return;
29+
}
30+
31+
if ( $what eq 'print' ) {
32+
$session->log->error("!!request->$what(print--chomped)");
33+
}
34+
else {
35+
$session->log->error("!!request->$what(@_)");
36+
}
37+
return $r->$what(@_);
38+
}
39+
40+
1;

0 commit comments

Comments
 (0)
Please sign in to comment.