taqua accountcode billing, part 2 of 2, RT12181
[freeside.git] / rt / bin / mason_handler.svc.in
1 #!@PERL@
2 # BEGIN BPS TAGGED BLOCK {{{
3 #
4 # COPYRIGHT:
5 #
6 # This software is Copyright (c) 1996-2011 Best Practical Solutions, LLC
7 #                                          <sales@bestpractical.com>
8 #
9 # (Except where explicitly superseded by other copyright notices)
10 #
11 #
12 # LICENSE:
13 #
14 # This work is made available to you under the terms of Version 2 of
15 # the GNU General Public License. A copy of that license should have
16 # been provided with this software, but in any event can be snarfed
17 # from www.gnu.org.
18 #
19 # This work is distributed in the hope that it will be useful, but
20 # WITHOUT ANY WARRANTY; without even the implied warranty of
21 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
22 # General Public License for more details.
23 #
24 # You should have received a copy of the GNU General Public License
25 # along with this program; if not, write to the Free Software
26 # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
27 # 02110-1301 or visit their web page on the internet at
28 # http://www.gnu.org/licenses/old-licenses/gpl-2.0.html.
29 #
30 #
31 # CONTRIBUTION SUBMISSION POLICY:
32 #
33 # (The following paragraph is not intended to limit the rights granted
34 # to you to modify and distribute this software under the terms of
35 # the GNU General Public License and is only of importance to you if
36 # you choose to contribute your changes and enhancements to the
37 # community by submitting them to Best Practical Solutions, LLC.)
38 #
39 # By intentionally submitting any modifications, corrections or
40 # derivatives to this work, or any other work intended for use with
41 # Request Tracker, to Best Practical Solutions, LLC, you confirm that
42 # you are the copyright holder for those contributions and you grant
43 # Best Practical Solutions,  LLC a nonexclusive, worldwide, irrevocable,
44 # royalty-free, perpetual, license to use, copy, create derivative
45 # works based on those contributions, and sublicense and distribute
46 # those contributions and any derivatives thereof.
47 #
48 # END BPS TAGGED BLOCK }}}
49 =head1 NAME
50
51 mason_handler.svc - Win32 IIS Service handler for RT
52
53 =head1 SYNOPSIS
54
55     perl mason_handler.svc --install    # install as service
56     perl mason_handler.svc --deinstall  # deinstall this service
57     perl mason_handler.svc --help       # show this help
58     perl mason_handler.svc              # launch handler from command line
59
60 =head1 DESCRIPTION
61
62 This script manages a stand-alone FastCGI server, and populates the necessary
63 registry settings to run it with Microsoft IIS Server 4.0 or above.
64
65 Before running it, you need to install the B<FCGI> module from CPAN, as well as
66 B<Win32::Daemon> from L<http://www.roth.net/perl/Daemon/> if you want to install
67 itself as a service.
68
69 This script will automatically create a virtual directory under the IIS root;
70 its name is taken from C<$WebPath> in the F<RT_Config.pm> file.  Additionally,
71 please install the ISAPI binary from L<http://www.caraveo.com/fastcgi/> and set
72 up an ISAPI Script Map that maps F<.html> files to F<isapi_fcgi.dll>.
73
74 Once the service is launched (either via C<net start RTFastCGI> or by running
75 C<perl mason_handler.svc>), a FCGI server will start and bind to port C<8284>
76 (mnemonics: the ASCII value of C<R> and C<T>); the ISAPI handler's C<BindPath>
77 registry setting will also be automatically populated.
78
79 =cut
80
81 package RT::Mason;
82
83 use strict;
84 use File::Basename;
85 use vars '$Handler';
86 require (dirname(__FILE__) . '/webmux.pl');
87
88 use Cwd;
89 use File::Spec;
90
91 use Win32;
92 use Win32::Process;
93 use Win32::Service;
94 use Win32::TieRegistry;
95
96 my $ProcessObj;
97
98 BEGIN {
99     my $runsvc = sub {
100         Win32::Process::Create(
101             $ProcessObj, $^X, "$^X $0 --run", 0, NORMAL_PRIORITY_CLASS, "."
102         ) or do {
103             die Win32::FormatMessage( Win32::GetLastError() );
104         };
105
106         chdir File::Basename::dirname($0);
107         my $path = Cwd::cwd();
108         $path =~ s|/|\\|g;
109         $path =~ s|bin$|share\\html|;
110
111         $Win32::TieRegistry::Registry->{
112             'HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services\\'.
113             'W3SVC\Parameters\Virtual Roots\\'
114         }->{RT->Config->Get('WebPath') || '/'} = "$path,,205";
115             
116         $Win32::TieRegistry::Registry->{
117             'HKEY_LOCAL_MACHINE\Software\FASTCGI\.html\\'
118         }->{'BindPath'} = $ENV{'FCGI_SOCKET_PATH'};
119
120         Win32::Service::StartService(Win32::NodeName, 'W3SVC');
121     };
122     
123     if ($ARGV[0] eq '--deinstall') {
124         chdir File::Basename::dirname($0);
125         my $path = Cwd::cwd();
126         $path =~ s|/|\\|g;
127
128         require Win32::Daemon;
129         Win32::Daemon::DeleteService('RTFastCGI');
130         warn "Service 'RTFastCGI' successfully deleted.\n";
131         exit;
132     }
133     elsif ($ARGV[0] eq '--install') {
134         chdir File::Basename::dirname($0);
135         my $path = Cwd::cwd();
136         $path =~ s|/|\\|g;
137
138         require Win32::Daemon;
139         Win32::Daemon::DeleteService('RTFastCGI');
140         
141         my $rv = Win32::Daemon::CreateService( {
142             machine =>  '',
143             name    =>  'RTFastCGI',
144             display =>  'RT FastCGI Handler',
145             path    =>  $^X,
146             user    =>  '',
147             pwd     =>  $path,
148             description => 'Enables port 8284 as the RT FastCGI handler.',
149             parameters  => File::Spec->catfile(
150                     $path, File::Basename::basename($0)
151             ) . ' --service',
152         } );
153     
154         if ($rv) {
155             warn "Service 'RTFastCGI' successfully created.\n";
156         }
157         else {
158             warn "Failed to add service: " . Win32::FormatMessage(
159                 Win32::Daemon::GetLastError()
160             ) . "\n";
161         }
162         exit;
163     }
164     elsif ($ARGV[0] eq '--service') {
165         require Win32::Daemon;
166
167         my $PrevState = Win32::Daemon::SERVICE_START_PENDING();
168         Win32::Daemon::StartService() or die $^E;
169
170         while ( 1 ) {
171             my $State = Win32::Daemon::State();
172             last if $State == Win32::Daemon::SERVICE_STOPPED();
173             
174             if ( $State == Win32::Daemon::SERVICE_START_PENDING() ) {
175                 $runsvc->();
176                 Win32::Daemon::State( Win32::Daemon::SERVICE_RUNNING() );
177                 $PrevState = Win32::Daemon::SERVICE_RUNNING();
178             }
179             elsif ( $State == Win32::Daemon::SERVICE_CONTINUE_PENDING() ) {
180                 $ProcessObj->Resume;
181                 Win32::Daemon::State( Win32::Daemon::SERVICE_RUNNING() );
182                 $PrevState = Win32::Daemon::SERVICE_RUNNING();
183             }
184             elsif ( $State == Win32::Daemon::SERVICE_STOP_PENDING() ) {
185             $ProcessObj->Kill(0);
186                 Win32::Daemon::State( Win32::Daemon::SERVICE_STOPPED() );
187                 $PrevState = Win32::Daemon::SERVICE_STOPPED();
188             }
189             elsif ( $State == Win32::Daemon::SERVICE_RUNNING() ) {
190                 my $Message = Win32::Daemon::QueryLastMessage(1);
191                 if ( $Message == Win32::Daemon::SERVICE_CONTROL_INTERROGATE() ) {
192                     Win32::Daemon::State( $PrevState );
193                 }
194                 elsif ( $Message == Win32::Daemon::SERVICE_CONTROL_SHUTDOWN() ) {
195                     Win32::Daemon::State( Win32::Daemon::SERVICE_STOP_PENDING(), 15000 );
196                 }
197                 elsif ( $Message != Win32::Daemon::SERVICE_CONTROL_NONE() ) {
198                     Win32::Daemon::State( $PrevState );
199                 }
200             }
201             
202             Win32::Sleep( 1000 );
203         }
204                 
205         Win32::Daemon::StopService();
206         exit;
207     }
208     elsif ($ARGV[0] eq '--help') {
209         system("perldoc $0");
210         exit;
211     }
212     elsif ($ARGV[0] ne '--run') {
213         $SIG{__DIE__} = sub { $ProcessObj->Kill(0) if $ProcessObj };
214         $runsvc->();
215         warn "RT FastCGI Handler launched. Press [Enter] to terminate...\n";
216         <STDIN>;
217         exit;
218     }
219 }
220
221 ###############################################################################
222
223 warn "Begin listening on $ENV{'FCGI_SOCKET_PATH'}\n";
224
225 require CGI::Fast;
226
227 RT::Init();
228 $Handler ||= RT::Interface::Web::Handler->new(
229     RT->Config->Get('MasonParameters')
230 );
231
232
233 # Response loop
234 while( my $cgi = CGI::Fast->new ) {
235     my $comp = $ENV{'PATH_INFO'};
236
237     # Each environment has its own way of handling .. and so on in paths,
238     # so RT consistently forbids such paths.
239     if ( $cgi->path_info =~ m{/\.} ) {
240         $RT::Logger->crit("Invalid request for ".$cgi->path_info." aborting");
241         print STDOUT "HTTP/1.0 400\r\n\r\n";
242
243         RT::Interface::Web::Handler->CleanupRequest();
244
245         next;
246     }
247
248     $comp = $1 if ($comp =~ /^(.*)$/);
249     my $web_path = RT->Config->Get('WebPath');
250     $comp =~ s|^\Q$web_path\E\b||i;
251     $comp .= "index.html" if ($comp =~ /\/$/);
252     $comp =~ s/.pl$/.html/g;
253     
254     warn "Serving $comp\n";
255
256     $Handler->handle_cgi($comp);
257     RT::Interface::Web::Handler->CleanupRequest();
258     # _should_ always be tied
259 }
260
261 1;
262
263 =head1 AUTHORS
264
265 Autrijus Tang E<lt>autrijus@autrijus.orgE<gt>
266
267 =head1 COPYRIGHT
268
269 Copyright 2002 by Autrijus Tang E<lt>autrijus@autrijus.orgE<gt>.
270
271 This program is free software; you can redistribute it and/or 
272 modify it under the same terms as Perl itself.
273
274 See L<http://www.perl.com/perl/misc/Artistic.html>
275
276 =cut