File Coverage

blib/lib/CatalystX/ASP/Server.pm
Criterion Covered Total %
statement 48 81 59.2
branch 3 24 12.5
condition 0 7 0.0
subroutine 18 19 94.7
pod 14 14 100.0
total 83 145 57.2


line stmt bran cond sub pod time code
1             package CatalystX::ASP::Server;
2              
3 9     9   5230 use namespace::autoclean;
  9         10  
  9         77  
4 9     9   631 use Moose;
  9         10  
  9         52  
5 9     9   38393 use HTML::Entities;
  9         14  
  9         518  
6 9     9   3846 use URI;
  9         25927  
  9         216  
7 9     9   39 use URI::Escape;
  9         12  
  9         7885  
8              
9             has 'asp' => (
10             is => 'ro',
11             isa => 'CatalystX::ASP',
12             required => 1,
13             weak_ref => 1,
14             );
15              
16             =head1 NAME
17              
18             CatalystX::ASP::Server - $Server Object
19              
20             =head1 SYNOPSIS
21              
22             use CatalystX::ASP::Server;
23              
24             my $svr = CatalystX::ASP::Server->new(asp => $asp);
25             my $html = $svr->HTMLEncode('my $has_timeout = $Server->{ScriptTimeout} && 1');
26              
27             =head1 DESCRIPTION
28              
29             The C<$Server> object is that object that handles everything the other objects
30             do not. The best part of the server object for Win32 users is the
31             C<CreateObject> method which allows developers to create instances of ActiveX
32             components, like the ADO component.
33              
34             =head1 ATTRIBUTES
35              
36             =over
37              
38             =item $Server->{ScriptTimeout} = $seconds
39              
40             Not implemented. May never be. Please see the
41             Apache Timeout configuration option, normally in httpd.conf.
42              
43             =cut
44              
45             has 'ScriptTimeout' => (
46             is => 'ro',
47             isa => 'Str',
48             default => 0,
49             );
50              
51             =back
52              
53             =head1 METHODS
54              
55             =over
56              
57             =item $Server->Config($setting)
58              
59             API extension. Allows a developer to read the CONFIG settings, like C<Global>,
60             C<GlobalPackage>, C<StateDir>, etc. Currently implemented as a wrapper around
61              
62             $self->asp->$setting
63              
64             May also be invoked as C<< $Server->Config() >>, which will return a hash ref of
65             all the ASP configuration settings.
66              
67             =cut
68              
69             sub Config {
70 1     1 1 6 my ( $self, $setting ) = @_;
71              
72 1 50       23 return $self->asp->$setting
73             if $self->asp->can( $setting );
74              
75 0         0 return;
76             }
77              
78             =item $Server->CreateObject($program_id)
79              
80             Not implemented.
81              
82             =cut
83              
84             # TODO: will not implement
85             sub CreateObject {
86 1     1 1 2 my ( $self, $program_id ) = @_;
87 1         29 $self->asp->c->log->warn( "\$Server->CreateObject has not been implemented!" );
88 1         980 return;
89             }
90              
91             =item $Server->Execute($file, @args)
92              
93             New method from ASP 3.0, this does the same thing as
94              
95             $Response->Include($file, @args)
96              
97             and internally is just a wrapper for such. Seems like we had this important
98             functionality before the IIS/ASP camp!
99              
100             =cut
101              
102 1     1 1 1 sub Execute { my $self = shift; $self->asp->Response->Include( @_ ) }
  1         30  
103              
104             =item $Server->File()
105              
106             Returns the absolute file path to current executing script. Same as
107             $ENV{SCRIPT_NAME} when running under mod_perl.
108              
109             ASP API extension.
110              
111             =cut
112              
113             sub File {
114 1     1 1 29 my $c = shift->asp->c;
115 1         4 $c->path_to( 'root', $c->request->path );
116             }
117              
118             =item $Server->GetLastError()
119              
120             Not implemented, will likely not ever be because this is dependent
121             on how IIS handles errors and is not relevant in Apache.
122              
123             =cut
124              
125             # TODO: will not implement
126             sub GetLastError {
127 1     1 1 601 my ( $self ) = @_;
128 1         29 $self->asp->c->log->warn( "\$Server->GetLastError has not been implemented!" );
129 1         7 return;
130             }
131              
132             =item $Server->HTMLEncode( $string || \$string )
133              
134             Returns an HTML escapes version of C<$string>. &, ", >, <, are each escapes with
135             their HTML equivalents. Strings encoded in this nature should be raw text
136             displayed to an end user, as HTML tags become escaped with this method.
137              
138             As of version C<2.23>, C<< $Server->HTMLEncode() >>may take a string reference
139             for an optmization when encoding a large buffer as an API extension. Here is how
140             one might use one over the other:
141              
142             my $buffer = '&' x 100000;
143             $buffer = $Server->HTMLEncode($buffer);
144             print $buffer;
145              
146             or
147              
148             my $buffer = '&' x 100000;
149             $Server->HTMLEncode(\$buffer);
150             print $buffer;
151              
152             Using the reference passing method in benchmarks on 100K of data was 5% more
153             efficient, but maybe useful for some. It saves on copying the 100K buffer twice.
154              
155             =cut
156              
157             sub HTMLEncode {
158 1     1 1 2 my ( $self, $string ) = @_;
159 1         2 for ( ref $string ) {
160 1 50       4 if ( /SCALAR/ ) { return encode_entities( $$string ) }
  0 50       0  
161 0         0 elsif ( /ARRAY/ ) { return \map { encode_entities( $_ ) } @$string }
  0         0  
162 1         5 else { return encode_entities( $string ) }
163             }
164             }
165              
166             =item $Server->MapInclude($include)
167              
168             API extension. Given the include C<$include>, as an absolute or relative file
169             name to the current executing script, this method returns the file path that
170             the include would be found from the include search path. The include search path
171             is the current script directory, C<Global>, and C<IncludesDir> directories.
172              
173             If the include is not found in the includes search path, then C<undef>, or bool
174             false, is returned. So one may do something like this:
175              
176             if ($Server->MapInclude('include.inc')) {
177             $Response->Include('include.inc');
178             }
179              
180             This code demonstrates how one might only try to execute an include if it
181             exists, which is useful since a script will error if it tries to execute an
182             include that does not exist.
183              
184             =cut
185              
186             sub MapInclude {
187 1     1 1 357 my ( $self, $include ) = @_;
188 1         28 $self->asp->search_includes_dir( $include );
189             }
190              
191             =item $Server->MapPath($url);
192              
193             Given the url C<$url>, absolute, or relative to the current executing script,
194             this method returns the equivalent filename that the server would translate the
195             request to, regardless or whether the request would be valid.
196              
197             Only a C<$url> that is relative to the host is valid. Urls like C<"."> and
198             C<"/"> are fine arguments to C<MapPath>, but C<http://localhost> would not be.
199              
200             =cut
201              
202             sub MapPath {
203 1     1 1 364 my ( $self, $url ) = @_;
204 1         28 $self->asp->c->path_to( 'root', URI->new( $url )->path );
205             }
206              
207             =item $Server->Mail(\%mail, %smtp_args);
208              
209             With the L<Net::SMTP> and L<Net::Config> modules installed, which are part of
210             the perl L<libnet> package, you may use this API extension to send email. The
211             C<\%mail> hash reference that you pass in must have values for at least
212             the C<To>, C<From>, and C<Subject> headers, and the C<Body> of the mail message.
213              
214             The return value of this routine is C<1> for success, C<0> for failure. If the
215             C<MailHost> SMTP server is not available, this will have a return value of C<0>.
216              
217             You could send an email like so:
218              
219             $Server->Mail({
220             To => 'somebody@yourdomain.com.foobar',
221             From => 'youremail@yourdomain.com.foobar',
222             Subject => 'Subject of Email',
223             Body =>
224             'Body of message. '.
225             'You might have a lot to say here!',
226             Organization => 'Your Organization',
227             CC => 'youremailcc@yourdomain.com.foobar',
228             BCC => 'youremailbcc@yourdomain.com.foobar',
229             Debug => 0 || 1,
230             });
231              
232             Any extra fields specified for the email will be interpreted as headers for the
233             email, so to send an HTML email, you could set
234             C<< 'Content-Type' => 'text/html' >> in the above example.
235              
236             If you have C<MailFrom> configured, this will be the default for the C<From>
237             header in your email. For more configuration options like the C<MailHost>
238             setting, check out the CONFIG section.
239              
240             The return value of this method call will be boolean for success of the mail
241             being sent.
242              
243             If you would like to specially configure the Net::SMTP object used internally,
244             you may set C<%smtp_args> and they will be passed on when that object is
245             initialized. C<perldoc Net::SMTP> for more into on this topic.
246              
247             If you would like to include the output of an ASP page as the body of the mail
248             message, you might do something like:
249              
250             my $mail_body = $Response->TrapInclude('mail_body.inc');
251             $Server->Mail({ %mail, Body => $$mail_body });
252              
253             =cut
254              
255             sub Mail {
256 0     0 1 0 my ( $self, $mail, %smtp_args ) = @_;
257              
258 0         0 require Net::SMTP;
259 0         0 my $smtp = Net::SMTP->new( $self->asp->MailHost, %smtp_args );
260              
261 0 0       0 return 0 unless $smtp;
262              
263 0   0     0 my ( $from ) = split( /\s*,\s*/, ( $mail->{From} || '' ) ); # just the first one
264 0   0     0 $smtp->mail( $from || $self->asp->MailFrom || return 0 );
265              
266 0         0 my @to;
267 0         0 for my $field ( qw(To BCC CC) ) {
268 0         0 my $receivers = $mail->{$field};
269 0 0       0 next unless $receivers;
270              
271             # assume ref of $receivers is an ARRAY if it is
272 0 0       0 my @receivers = ref $receivers ? @$receivers : ( split( /\s*,\s*/, $receivers ) );
273 0         0 push @to, @receivers;
274             }
275 0 0       0 $smtp->to( @to ) || return;
276              
277 0         0 my $body = delete $mail->{Body};
278              
279             # assumes MIME-Version 1.0 for Content-Type header, according to RFC 1521
280             # http://www.ietf.org/rfc/rfc1521.txt
281 0 0 0     0 $mail->{'MIME-Version'} = '1.0' if $mail->{'Content-Type'} && !$mail->{'MIME-Version'};
282              
283 0         0 my ( @data, %visited );
284              
285             # Though the list below are actually keys in $mail, this is to get them to
286             # appear first, thought I'm not sure why it's needed
287 0         0 for my $field ( 'Subject', 'From', 'Reply-To', 'Organization', 'To', keys %$mail ) {
288 0         0 my $value = $mail->{$field};
289 0 0       0 next unless $value;
290 0 0       0 next if $visited{ lc( $field ) }++;
291              
292             # assume ref of $value is an ARRAY if it is
293 0 0       0 $value = join( ",", @$value ) if ref $value;
294 0         0 $value =~ s/^[\n]*(.*?)[\n]*$/$1/;
295 0         0 push @data, "$field: $value";
296             }
297              
298 0         0 my $data = join( "\n", @data, '', $body );
299 0         0 my $result;
300 0 0       0 unless ( $result = $smtp->data( $data ) ) {
301 0         0 $self->asp->c->error( $smtp->message );
302             }
303              
304 0         0 $smtp->quit();
305 0         0 return $result;
306             }
307              
308             =item $Server->RegisterCleanup($sub)
309              
310             Not implemented. Sorry!
311              
312             =cut
313              
314             # TODO: will not implement
315             sub RegisterCleanup {
316 1     1 1 951 my ( $self, $sub ) = @_;
317 1         6 return;
318             }
319              
320             =item $Server->Transfer($file, @args)
321              
322             New method from ASP 3.0. Transfers control to another script. The Response
323             buffer will not be cleared automatically, so if you want this to serve as a
324             faster C<< $Response->Redirect() >>, you will need to call
325             C<< $Response->Clear() >> before calling this method.
326              
327             This new script will take over current execution and the current script will not
328             continue to be executed afterwards. It differs from C<Execute()> because the
329             original script will not pick up where it left off.
330              
331             As of L<Apache::ASP> 2.31, this method now accepts optional arguments like
332             C<< $Response->Include >> & C<< $Server->Execute >>. C<< $Server->Transfer >>
333             is now just a wrapper for:
334              
335             $Response->Include($file, @args);
336             $Response->End;
337              
338             =cut
339              
340 1     1 1 2 sub Transfer { my $self = shift; $self->asp->Response->Include( @_ ) }
  1         33  
341              
342             =item $Server->URLEncode($string)
343              
344             Returns the URL-escaped version of the string C<$string>. C<+>'s are substituted
345             in for spaces and special characters are escaped to the ascii equivalents.
346             Strings encoded in this manner are safe to put in urls... they are especially
347             useful for encoding data used in a query string as in:
348              
349             $data = $Server->URLEncode("test data");
350             $url = "http://localhost?data=$data";
351              
352             C<$url> evaluates to C<http://localhost?data=test+data>, and is a
353             valid URL for use in anchor <a> tags and redirects, etc.
354              
355             =cut
356              
357             sub URLEncode {
358 1     1 1 2 my ( $self, $string ) = @_;
359 1         6 uri_escape_utf8( $string );
360             }
361              
362             =item $Server->URL($url, \%params)
363              
364             Will return a URL with C<%params> serialized into a query string like:
365              
366             $url = $Server->URL('test.asp', { test => value });
367              
368             which would give you a URL of C<test.asp?test=value>
369              
370             Used in conjunction with the C<SessionQuery>* settings, the returned URL will
371             also have the session id inserted into the query string, making this a critical
372             part of that method of implementing cookieless sessions. For more information on
373             that topic please read on the setting in the CONFIG section, and the SESSIONS
374             section too.
375              
376             =cut
377              
378             sub URL {
379 1     1 1 396 my ( $self, $url, $params ) = @_;
380 1         8 my $uri = URI->new( $url );
381 1         61 $uri->query_form( $params );
382 1         133 $uri->as_string;
383             }
384              
385             =item $Server->XSLT(\$xsl_data, \$xml_data)
386              
387             Not implemented. Sorry!
388              
389             =cut
390              
391             # TODO: will not implement
392             sub XSLT {
393 1     1 1 351 my ( $self, $xsl_dataref, $xml_dataref ) = @_;
394 1         30 $self->asp->c->log->warn( "\$Server->XSLT has not been implemented!" );
395 1         12 return;
396             }
397              
398             __PACKAGE__->meta->make_immutable;
399              
400             =back
401              
402             =head1 SEE ALSO
403              
404             =over
405              
406             =item * L<CatalystX::ASP::Session>
407              
408             =item * L<CatalystX::ASP::Request>
409              
410             =item * L<CatalystX::ASP::Response>
411              
412             =item * L<CatalystX::ASP::Application>
413              
414             =back