ASP4

 view release on metacpan or  search on metacpan

Changes  view on Meta::CPAN

22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
    - ->is_subrequest means that a subrequest context will not clobber ->current.
 
2012-02-24    1.083
  - A wild Meta.json appeared in 1.082!
 
2012-02-24    1.082
  - Response->Redirect after Response->TrapInclude was causing the redirect to fail.
  - This release introduces a hack to fix it, by writing a meta tag to the client.
 
2012-02-13    1.081
  - Updated logging of errors so that it outputs something interesting, instead
    of a blank line.
  - Running under mod_perl should now correctly support full RESTful interfaces.
 
2012-02-12    1.080
  - Added support for multiple external "routes.json" files.
 
2012-02-07    1.079
  - Errors output to the stderr are now derived directly from $@ not from any
    parsed version of it.

Changes  view on Meta::CPAN

85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
2011-12-10    1.068
  - ASP4 is now hosted on github. https://github.com/jdrago999/ASP4
 
2011-12-01    1.067
  - ASP4::GlobalASA is completely deprecated.
  - ASP4::ErrorHandler contained a bug (cannot find method 'context').  Thanks
    to ray.baksh++ for discovering it.
 
2011-11-16    1.066
  - Fixed a POD error in ASP4::ErrorHandler::Remote.
  - ASP4::ErrorHandler::Remote now correctly clones the error object before POSTing it.
 
2011-11-15    1.065
  - Documented asp4-prep and asp4-deploy.  These are deployment tools for ASP4 apps.
  - Other POD updates here and there.
 
2011-11-15    1.064
  - 1.063 was broken - please upgrade.
 
2011-11-15    1.063
  - Stealth-mode ASP4::ErrorHandler::Remote will send your error messages to a
    remote server via http.
  - Added ASP4::Error
  - Refactored ASP4::ErrorHandler to be more easily sub-classable.
  - GlobalASA is now officially removed.
 
2011-11-13    1.062
  - The httpd.conf produced by asphelper had an incorrect DocumentRoot.  Fixed now.
 
2011-11-07    1.061
  - asphelper now creates new ASP4 apps using the proper structure.

Changes  view on Meta::CPAN

147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
  - TODO: Add POD for asp4-prep and asp4-deploy.  This is delayed until it's proven
    that this is the correct way for onesie-twosie deployments.
 
2011-10-04    1.057
  - Renamed @AppRoot@ macro to @ProjectRoot@ to avoid confusion with $Config->web->application_root
  - Adjusted package declarations in some "stealth-mode" pm files because they have no POD yet.
 
2011-10-03    1.056
  - Updated asphelper to include directives that disable mod_deflate and Apache2::Reload
    for ASP4 websites. RayBaksh++
  - This fixes the dreaded "This website uses an invalid form of compression" error
    that you may have gotten after trying to $Response->Status(404) within an asp script.
  - Added in-memory mock sessionstate handler for faster testing and easier installation.
 
2011-09-22    1.055
  - Giving credit where credit is due :-)
  - Erikdj++
  - Added *experimental* memcached session storage backend.
 
2011-09-20    1.054
  - Added @AppRoot@ macro for asp4-config.json.  It is 1 folder "up" from @ServerRoot@.

Changes  view on Meta::CPAN

201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
2011-07-09    v1.049
[Bug Fixes]
  - v1.048 broke session cookies.
  - Upgrade to v1.049 (quick).
 
2011-07-07    v1.048
[Bug Fixes]
  - <% $Response->Status(404); return $Response->End; %> DID NOT WORK.
    Instead it continued processing other ContentPlaceHolders.  Now we check
    to see if $Response->End was called before we process anything else.
  - Still getting some "Content encoding error" messages from FF/Chrome/MSIE but
    we're almost there.
 
2011-05-19    v1.047
[Bug Fixes]
  - $Response->Expires("30M") wasn't documented.  Now it is.
  - $Response->Expires wasn't working properly.  Now it is. (Always ended up with pre-epoch expiration times).
 
2011-05-03    v1.046
[Bug Fixes]
  - $Response->Redirect(...) wasn't returning '301' - now it does.
 
2011-05-03    v1.045
[Bug Fixes]
  - Actually it turned out that setting $Session->is_read_only(1) *DID* prevent
    $Session->save() from working.  This is now fixed to match the documentation.
 
2011-05-01    v1.044
 
[Bug Fixes]
  - ASP4::ModPerl now does the Right Thing when a non-200 response is encountered.
    - 500 response does not result in an "encoding error" in firefox.
    - 200 (or 0 response) does the right thing.
    - non-200 (and non-500) response does the right thing (eg: 401)
  - ASP4::SessionStateManager now checks $s->is_changed *before* checking $s->{__lastMod} date
    before deciding whether is should persist its changes in ->save().
 
[New Features]
  - $Session->is_read_only(1) is new.  Setting it to a true value (eg: 1) will prevent
    the default behavior of calling $Session->save() at the end of each successful request.
 
2011-04-08    v1.043
  - Documentation overhaul.
 
2011-03-23    v1.042
  - Fixed sporadic error in master pages that looks like this:
    Can't call method "Write" on an undefined value at /tmp/PAGE_CACHE/BStat/_masters_global_asp.pm line 1.
  - Apparently $s->init_asp_objects($context) was not getting called before the
    master page's run() method was called, resulting in a call to $Response->Write(...)
    before $Response had been initialized.
 
2010-11-11    v1.041
  - ASP4::UserAgent calls all cleanup handlers registered via $Server->RegisterCleanup(sub { }, @args)
    at the end of each request, not when the ASP4::Mock::Pool object's DESTROY method is called.
    This fixes a condition which caused conflict when a Class::DBI::Lite ORM is
    used and the ASP4 application is executed via the `asp4` helper script.
 
2010-10-25    v1.040
  - 1.039 introduced a bug that could cause session-id conflicts in the asp_sessions table.
  - This release fixes that bug.
 
2010-10-25    v1.039
  - Session expiration now happens exclusively on the server, not as the
    result of an expiring session cookie.
 
2010-10-21    v1.038
  - Another stab at getting http response codes right for errors.
 
2010-09-25    v1.037
  - Added a couple tweaks here and there to make ASP4 run on Windows a little easier:
    * $Config->web->page_cache_root now does the Right Thing on linux & win32.
    * $Config->web->page_cache_root is automatically created if it does not exist.
 
2010-09-21    v1.036
  - Added ASP4::StaticHandler to process requests for static files - like images, css, etc.
 
2010-09-17    v1.035

Changes  view on Meta::CPAN

397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
    ASP4::HandlerResolver's %HandlerCache and %FileTimes hashes were shared between
    all VirtualHosts.  This means that if you had 2 web apps (Foo and Bar) then
    "/index.asp" on "Foo" might get handled by "Bar::_index_asp" or vice versa.
 
2010-02-08    v1.009
  ! Upgrade Recommended !
  - ASP4::ModPerl sets $ENV{DOCUMENT_ROOT} = $r->document_root before doing
    anything else.
  - The scaffold website output by 'asphelper' had some minor bugs:
      * email was sometimes referred to as email_address
      * The error message for the 'message' field was displaying the wrong error.
 
2010-02-07    v1.008
  - Multi-value form parameters (eg 3 checkboxes with the same name) will now
    *correctly* appear as an arrayref in $Form, instead of 3 values joined with
    a null byte.
 
2010-01-31    v1.007
  - $FileUpload->SaveAs("/path/to/file.txt") will now create "/path" and "/path/to"
    before writing "/path/to/file.txt".

README.markdown  view on Meta::CPAN

482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
 
<asp:Content PlaceHolderID="main_content">
<%
  # Sticky forms work like this:
  if( my $args = $Session->{__lastArgs} ) {
    map { $Form->{$_} = $args->{$_} } keys %$args;
  }
   
 
  # Our validation errors:
  my $errors = $Session->{validation_errors} || { };
  $::err = sub {
    my $field = shift;
    my $error = $errors->{$field} or return;
    %><span class="field_error"><%= $Server->HTMLEncode( $error ) %></span><%
  };
%>
<form id="register_form" method="post" action="/handlers/myapp.register">
  <p>
    <label>Email:</label>
    <input type="text" name="email" value="<%= $Server->HTMLEncode( $Form->{email} ) %>" />
    <% $::err->("email"); %>
  </p>
  <p>
    <label>Password:</label>

README.markdown  view on Meta::CPAN

530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
    use warnings 'all';
    use base 'https://metacpan.org/pod/ASP4::FormHandler">ASP4::FormHandler';
    use vars __PACKAGE__->VARS; # Import $Response, $Form, $Session, etc
    use App::db::user;
     
 
    sub run {
      my ($self, $context) = @_;
       
 
    # If there is an error, return the user to the registration page:
    if( my $errors = $self->validate() ) {
      $Session->{validation_errors} = $errors;
      $Session->{__lastArgs} = $Form;
      $Session->save;
      return $Response->Redirect( $ENV{HTTP_REFERER} );
    }
     
 
    # Create the user:
    my $user = eval {
      App::db::user->do_transaction(sub {
        return App::db::user->create(
          email     => $Form->{email},
          password  => $Form->{password},
        );
      });
    };
     
 
    if( $@ ) {
      # There was an error:
      $Session->{validation_errors} = {email => "Server error.  Sorry!"};
      $Session->{__lastArgs} = $Form;
      $Session->save;
      return $Response->Redirect( $ENV{HTTP_REFERER} );
    }
    else {
      # No error - Sign them in:
      $Session->{user_id} = $user->id;
      $Session->{msg} = "Thank you for registering!";
      $Session->save;
       
 
        # Redirect to /profile.asp:
      return $Response->Redirect("/profile.asp");
      }# end if()
    }
     
 
    sub validate {
      my ($self) = @_;
       
 
    $self->trim_form;
     
 
    my $errors = { };
    no warnings 'uninitialized';
     
 
    # email:
    if( length($Form->{email}) ) {
      # Basic email validation:
      unless( $Form->{email} =~ m{[^@]+@[^@]+\.[^@]+} ) {
        $errors->{email} = "Invalid email address";
      }
    }
    else {
      $errors->{email} = "Required";
    }
     
 
    # password:
    unless( length($Form->{password} ) {
      $errors->{password} = "Required";
    }
     
 
    # password2:
    if( length($Form->{password2}) ) {
      if( length($Form->{password}) ) {
        unless( $Form->{password} eq $Form->{password2} ) {
          $errors->{password2} = "Passwords don't match";
        }
      }
    }
    else {
      $errors->{password2} = "Required";
    }
     
 
    # Bail out of we already have errors:
    return $errors if keys %$errors;
     
 
    # See if the user already exists:
    if( App::db::user->count_search( email => $Form->{email} ) ) {
      $errors->{email} = "Already in use";
    }
     
 
      # Errors or not?:
      keys %$errors ? return $errors : return;
    }
     
 
    1;# return true:
 
File: `htdocs/profile.asp`
 
    <%@ Page UseMasterPage="/masters/global.asp" %>
    

inc/Module/Install.pm  view on Meta::CPAN

39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
 
 
 
 
# Whether or not inc::Module::Install is actually loaded, the
# $INC{inc/Module/Install.pm} is what will still get set as long as
# the caller loaded module this in the documented manner.
# If not set, the caller may NOT have loaded the bundled version, and thus
# they may not have a MI version that works with the Makefile.PL. This would
# result in false errors or unexpected behaviour. And we don't want that.
my $file = join( '/', 'inc', split /::/, __PACKAGE__ ) . '.pm';
unless ( $INC{$file} ) { die <<"END_DIE" }
 
Please invoke ${\__PACKAGE__} with:
 
        use inc::${\__PACKAGE__};
 
not:
 
        use ${\__PACKAGE__};

lib/ASP4.pm  view on Meta::CPAN

465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
<asp:Content PlaceHolderID="headline">Register</asp:Content>
 
<asp:Content PlaceHolderID="main_content">
<%
  # Sticky forms work like this:
  if( my $args = $Session->{__lastArgs} ) {
    map { $Form->{$_} = $args->{$_} } keys %$args;
  }
   
  # Our validation errors:
  my $errors = $Session->{validation_errors} || { };
  $::err = sub {
    my $field = shift;
    my $error = $errors->{$field} or return;
    %><span class="field_error"><%= $Server->HTMLEncode( $error ) %></span><%
  };
%>
<form id="register_form" method="post" action="/handlers/myapp.register">
  <p>
    <label>Email:</label>
    <input type="text" name="email" value="<%= $Server->HTMLEncode( $Form->{email} ) %>" />
    <% $::err->("email"); %>
  </p>
  <p>
    <label>Password:</label>

lib/ASP4.pm  view on Meta::CPAN

510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
    
  use strict;
  use warnings 'all';
  use base 'https://metacpan.org/pod/ASP4::FormHandler">ASP4::FormHandler';
  use vars __PACKAGE__->VARS; # Import $Response, $Form, $Session, etc
  use App::db::user;
   
  sub run {
    my ($self, $context) = @_;
     
    # If there is an error, return the user to the registration page:
    if( my $errors = $self->validate() ) {
      $Session->{validation_errors} = $errors;
      $Session->{__lastArgs} = $Form;
      $Session->save;
      return $Response->Redirect( $ENV{HTTP_REFERER} );
    }
     
    # Create the user:
    my $user = eval {
      App::db::user->do_transaction(sub {
        return App::db::user->create(
          email     => $Form->{email},
          password  => $Form->{password},
        );
      });
    };
     
    if( $@ ) {
      # There was an error:
      $Session->{validation_errors} = {email => "Server error.  Sorry!"};
      $Session->{__lastArgs} = $Form;
      $Session->save;
      return $Response->Redirect( $ENV{HTTP_REFERER} );
    }
    else {
      # No error - Sign them in:
      $Session->{user_id} = $user->id;
      $Session->{msg} = "Thank you for registering!";
      $Session->save;
       
      # Redirect to /profile.asp:
    return $Response->Redirect("/profile.asp");
    }# end if()
  }
   
  sub validate {
    my ($self) = @_;
     
    $self->trim_form;
     
    my $errors = { };
    no warnings 'uninitialized';
     
    # email:
    if( length($Form->{email}) ) {
      # Basic email validation:
      unless( $Form->{email} =~ m{[^@]+@[^@]+\.[^@]+} ) {
        $errors->{email} = "Invalid email address";
      }
    }
    else {
      $errors->{email} = "Required";
    }
     
    # password:
    unless( length($Form->{password} ) {
      $errors->{password} = "Required";
    }
     
    # password2:
    if( length($Form->{password2}) ) {
      if( length($Form->{password}) ) {
        unless( $Form->{password} eq $Form->{password2} ) {
          $errors->{password2} = "Passwords don't match";
        }
      }
    }
    else {
      $errors->{password2} = "Required";
    }
     
    # Bail out of we already have errors:
    return $errors if keys %$errors;
     
    # See if the user already exists:
    if( App::db::user->count_search( email => $Form->{email} ) ) {
      $errors->{email} = "Already in use";
    }
     
    # Errors or not?:
    keys %$errors ? return $errors : return;
  }
   
  1;# return true:
 
File: C<htdocs/profile.asp>
 
  <%@ Page UseMasterPage="/masters/global.asp" %>
   
  <asp:Content PlaceHolderID="meta_title">My Profile</asp:Content>
  

lib/ASP4/Config.pm  view on Meta::CPAN

151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
ASP4::Config - Central configuration for ASP4
 
=head1 SYNOPSIS
 
  # Settings:
  $Config->system->settings->some_setting;
  $Config->system->settings->another_setting;
   
  # Error-handling:
  $Config->errors->error_handler;
  $Config->errors->mail_errors_to;
  $Config->errors->mail_errors_from;
  $Config->errors->smtp_server;
   
  # Web:
  $Config->web->application_name;
  $Config->web->application_root;
  $Config->web->project_root;
  $Config->web->www_root;
  $Config->web->handler_root;
  $Config->web->media_manager_upload_root;
  $Config->web->page_cache_root;
  

lib/ASP4/Config.pm  view on Meta::CPAN

203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
  ],
  "env_vars": {
    "myvar":        "Some-Value",
    "another_var""Another Value"
  },
  "settings": {
    "foo": "bar",
    "baz": "bux"
  }
},
"errors": {
  "error_handler":    "ASP4::ErrorHandler",
  "mail_errors_to":   "you@yours.com",
  "mail_errors_from": "root@localhost",
  "smtp_server":      "localhost"
},
"web": {
  "application_name": "DefaultApp",
  "application_root": "@ServerRoot@",
  "www_root":         "@ServerRoot@/htdocs",
  "handler_root":     "@ServerRoot@/handlers",
  "page_cache_root""/tmp/PAGE_CACHE",
  "handler_resolver": "ASP4::HandlerResolver",
  "handler_runner":   "ASP4::HandlerRunner",

lib/ASP4/Error.pm  view on Meta::CPAN

28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
}# end if()
 
my $context   = ASP4::HTTPContext->current;
my $Config    = $context->config;
my $Response  = $context->response;
my $Session   = $context->session;
my $Form      = $context->request->Form;
 
my %session_data = %$Session;
 
my $error;
if( $err_str )
{
  my ($main, $message, $file, $line) = $err_str =~ m/^((.*?)\s(?:at|in)\s(.*?)\sline\s(\d+))/;
  $error = {
    message     => $err_str,
    file        => $file,
    line        => $line,
    stacktrace  => $err_str,
  };
   
  if( $error->{file} =~ m{_asp\.pm$} )
  {
    $error->{file} = -f $ENV{SCRIPT_FILENAME} ? $ENV{SCRIPT_FILENAME} : $error->{file};
  }# end if()
}
else
{
  $error = \%args;
}# end if()
   
# Get the line of code that's breaking:
# And maybe a few before and after:
my $code;
if( -f $error->{file} )
{
  if( open my $ifh, '<', $error->{file} )
  {
    my $max = 0;
    $max++ while <$ifh>;
    close($ifh);
    open $ifh, '<', $error->{file};
     
    my $padding = 10;
    my ($low, $high) = $class->_number_range($error->{line}, $max, $padding);
 
    my $line_number = 0;
    my @lines = ( );
    while( my $line = <$ifh> )
    {
      $line_number++;
      next unless $line_number >= $low;
      last if $line_number > $high;
      push @lines, "line $line_number: $line";
    }# end while()
    close($ifh);
    $code = join "", @lines;
  }# end if()
}# end if()
 
my %info = (
  # Defaults:
  domain        => eval { $Config->errors->domain } || $ENV{HTTP_HOST},
  request_uri   => $ENV{REQUEST_URI},
  file          => $error->{file},
  line          => $error->{line},
  message       => $error->{message},
  stacktrace    => $error->{stacktrace},
  code          => $code,
  form_data     => encode_json($Form) || "{}",
  session_data  => eval { encode_json(\%session_data) } || "{}",
  http_referer  => $ENV{HTTP_REFERER},
  user_agent    => $ENV{HTTP_USER_AGENT},
  http_code     => ($Response->Status =~ m{^(\d+)})[0],
  remote_addr   => $ENV{REMOTE_ADDR} || '127.0.0.1',
  # Allow overrides:
  %args
);

lib/ASP4/Error.pm  view on Meta::CPAN

132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
  my $high = $number + $padding <= $max ? $number + $padding : $max;
  return ($low, $high);
}# end _number_range()
 
1;# return true:
 
=pod
 
=head1 NAME
 
ASP4::Error - Representation of a server-side error
 
=head1 SYNOPSIS
 
  use ASP4::Error;
   
  # Pass in the $@ value after something dies or confesses:
  eval { die "Foo" };
  if( $@ ) {
    my $error = ASP4::Error->new( $@ )
  }
   
  # Pass in your own info:
  unless( $something ) {
    my $error = ASP4::Error->new(
      message => "If can, can.  If no can, no can!"
    );
  }
   
=head1 DESCRIPTION
 
ASP4 provides a simple means of dealing with errors.  It emails them, by default,
to an email address you specify.
 
Sometimes that is not convenient.  Maybe you want to do something special with
the error - like log it someplace special.
 
ASP4::Error is a simple representation of a server-side error.
 
=head1 PUBLIC READ-ONLY PROPERTIES
 
=head2 domain
 
C<<$Config->errors->domain>> or C<$ENV{HTTP_HOST}>
 
=head2 request_uri
 
C<$ENV{REQUEST_URI}>
 
=head2 file
 
The name of the file in which the error occurred.  This is gleaned from C<$@> unless C<file> is
passed to the constructor.
 
=head2 line
 
The line number within the file that the error occurred.  This is gleaned from C<$@> unless
C<line> is passed to the constructor.
 
=head2 code
 
A string.  Includes the 5 lines of code before and after the line of code where the error occurred.
 
=head2 message
 
Defaults to the first part of C<$@> unless otherwise specified.
 
=head2 stacktrace
 
A string - defaults to the value of C<$@>.
 
=head2 form_data

lib/ASP4/ErrorHandler.pm  view on Meta::CPAN

6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
use vars __PACKAGE__->VARS;
 
 
sub run
{
  my ($s, $context) = @_;
   
  my $error = $Stash->{error};
  $s->print_error( $error );
  $s->send_error( $error );
}# end run()
 
 
sub print_error
{
  my ($s, $error) = @_;
   
  $Response->ContentType('text/html');
 
  if( $ENV{HTTP_HOST} eq 'localhost' )
  {
    $Response->Write( Dumper(\%$error) );
  }
  else
  {
    $Response->Write( $s->error_html( $error ) );
  }# end if()
   
  $Response->Flush;
}# end print_error()
 
 
sub send_error
{
  my ($s, $error) = @_;
   
  $Server->Mail(
    To                          => $Config->errors->mail_errors_to,
    From                        => $Config->errors->mail_errors_from,
    Subject                     => "ASP4: Error in @{[ $ENV{HTTP_HOST} ]}@{[ $ENV{REQUEST_URI} ]}",
    'content-type'              => 'text/html',
    'content-transfer-encoding' => 'base64',
    Message                     => encode_base64( $s->error_html($error) ),
    smtp                        => $Config->errors->smtp_server,
  );
}# end send_error()
 
 
sub error_html
{
  my ($s, $error) = @_;
   
  my $msg = <<"ERROR";
<!DOCTYPE html>
<html>
<head><title>500 Server Error</title>
<meta charset="utf-8" />
<style type="text/css">
HTML,BODY {
  background-color: #FFFFFF;
}

lib/ASP4/ErrorHandler.pm  view on Meta::CPAN

100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
  width: 80px;
  font-weight: bold;
}
.info {
  float: left;
  color: #CC0000;
}
</style>
<body>
<h1>500 Server Error</h1>
<h2>@{[ $error->message ]}</h2>
<div><div class="label">URL:</div> <div class="info"><code>@{[ $ENV{HTTP_HOST} ]}@{[ $ENV{REQUEST_URI} ]}</code></div></div>
<div class="clear"></div>
<div><div class="label">File:</div> <div class="info"><code>@{[ $error->file ]}</code></div></div>
<div class="clear"></div>
<div><div class="label">Line:</div> <div class="info">@{[ $error->line ]}</div></div>
<div class="clear"></div>
<div><div class="label">Time:</div> <div class="info">@{[ HTTP::Date::time2iso() ]}</div></div>
<div class="clear"></div>
<h2>Stacktrace follows below:</h2>
<div class="code"><pre>@{[ $error->stacktrace ]}</pre></div>
<div class="clear"></div>
<h3>\%ENV</h3>
<div class="code"><pre>
HTTP_REFERER:     '@{[ $Server->HTMLEncode($ENV{HTTP_REFERER}||'NONE') ]}'
HTTP_COOKIE:      '@{[ $Server->HTMLEncode($ENV{HTTP_COOKIE}||'NONE') ]}'
HTTP_USER_AGENT:  '@{[ $Server->HTMLEncode($ENV{HTTP_USER_AGENT}||'NONE') ]}'
REMOTE_ADDR:      '@{[ $Server->HTMLEncode($ENV{REMOTE_ADDR}||'NONE') ]}'
</pre></div>
<h3>\$Form</h3>
<div class="code"><pre>@{[ Dumper($Form) ]}</pre></div>
<div class="clear"></div>
<div style="display: none;">
</body>
</html>
ERROR
   
  return $msg;
}# end error_html()
 
 
1;# return true:
 
=pod
 
=head1 NAME
 
ASP4::ErrorHandler - Default fatal error handler
 
=head1 SYNOPSIS
 
In your C<asp4-config.json>:
 
  ...
    "errors": {
      "error_handler":    "ASP4::ErrorHandler",
      "mail_errors_to":   "you@server.com",
      "mail_errors_from": "root@localhost",
      "smtp_server":      "localhost"
    },
  ...
 
=head1 DESCRIPTION
 
This class provides a default error handler which does the following:
 
1) Makes a simple HTML page and prints it to the browser, telling the user
that an error has just occurred.
 
2) Sends that same HTML to the email address specified in the config, using the
SMTP server also specified in the config.  The email subject will look something like:
 
  ASP4: Error in your-site.com/index.asp
 
=head1 SUBCLASSING
 
To subclass C<ASP4::ErrorHandler> you must do the following:
 
  package My::ErrorHandler;
   
  use strict;
  use warnings 'all';
  use base 'ASP4::ErrorHandler';
  use vars __PACKAGE__->VARS;
   
  sub run {
    my ($s, $context) = @_;
     
    my $error = $Stash->{error};
     
    # $error is an ASP4::Error object.
   
    # Do something here about the error.
    $s->print_error( $error );
    $s->send_error( $error );
  }
   
  1;# return true:
 
=head1 METHODS
 
=head2 error_html( $error )
 
Returns a string of html suitable for printing to the browser or emailing.
 
=head2 print_error( $error )
 
Prints the error html to the browser.
 
=head2 send_error( $error )
 
Sends the error html to the email address specified in the config, using C<<$Server->Mail(...)>>
and the smtp server specified in the config.
 
=head1 BUGS
 
It's possible that some bugs have found their way into this release.
 
Use RT L<http://rt.cpan.org/NoAuth/Bugs.html?Dist=ASP4> to submit bug reports.
 
=head1 HOMEPAGE

lib/ASP4/ErrorHandler/Remote.pm  view on Meta::CPAN

11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
require ASP4;
 
our $ua;
 
sub run
{
  my ($s, $context) = @_;
   
  my $error = $Stash->{error};
   
  $s->print_error( $error );
  $s->send_error($error);
}# end run()
 
 
sub send_error
{
  my ($s, $error) = @_;
   
  $ua ||= LWP::UserAgent->new();
  $ua->agent( ref($s) . " $ASP4::VERSION" );
  my %clone = %$error;
  my $req = POST $Config->errors->post_errors_to, \%clone;
  $ua->request( $req );
}# end send_error()
 
1;# return true:
 
=pod
 
=head1 NAME
 
ASP4::ErrorHandler::Remote - Send your errors someplace else via http.
 
=head1 SYNOPSIS
 
In your C<asp4-config.json>:
 
  ...
    "errors": {
      "error_handler":    "ASP4::ErrorHandler::Remote",
      "post_errors_to":   "http://errors.ohno.com/post/errors/here/"
    },
  ...
 
=head1 DESCRIPTION
 
This class provides a default error handler which does the following:
 
1) Makes a simple HTML page and prints it to the browser, telling the user
that an error has just occurred.
 
2) Sends an error notification to the web address specified in the config.
 
The data contained within the POST will match the public properties of L<ASP4::Error>, like this:
 
  $VAR1 = {
            'remote_addr' => '127.0.0.1',
            'request_uri' => '/',
            'user_agent' => 'test-useragent v2.0',
            'file' => '/home/john/Projects/myapp/www/htdocs/index.asp',
            'session_data' => '{}',
            'message' => 'A fake error has occurred',
            'http_code' => '500',
            'stacktrace' => 'A fake error has occurred at /tmp/PAGE_CACHE/TSR_WWW/__index_asp.pm line 2.
  ',
            'domain' => 'www.tsr.local',
            'form_data' => '{}',
            'http_referer' => '',
            'code' => 'line 1: <h1>Hello, world!</h1>
  line 2: <%
  line 3:   die "A fake error has occurred";
  line 4: %>
  ',
            'line' => '2'
  };
 
 
=head1 PUBLIC METHODS
 
=head2 send_error( $error )
 
Sends the error data to the web address specified in C<<$Config->errors->post_errors_to>>.
 
The field names and values will correspond to the properties of an C<ASP4::Error> object.
 
=head1 BUGS
 
It's possible that some bugs have found their way into this release.
 
Use RT L<http://rt.cpan.org/NoAuth/Bugs.html?Dist=ASP4> to submit bug reports.
 
=head1 HOMEPAGE

lib/ASP4/HTTPContext.pm  view on Meta::CPAN

151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
    }# end foreach()
  }# end unless()
   
  eval {
    $s->{handler} = $s->config->web->handler_resolver->new()->resolve_request_handler( $s->r->uri );
  };
   
  if( $@ )
  {
    $s->server->{LastError} = $@;
    return $s->handle_error;
  }# end if()
 
  return $s->response->Status( 404 ) unless $s->{handler};
   
  eval {
    $s->config->load_class( $s->handler );
    $s->config->web->handler_runner->new()->run_handler( $s->handler, $args );
  };
   
  if( $@ )
  {
    $s->server->{LastError} = $@;
    return $s->handle_error;
  }# end if()
   
  $s->response->Flush;
  my $res = $s->end_request();
   
  $res = 0 if $res =~ m/^200/;
  return $res;
}# end execute()
 
 
sub handle_phase
{
  my ($s, $ref, $is_filter) = @_;
   
  my $res = eval { $ref->( ) };
  if( $@ )
  {
    $s->handle_error;
  }# end if()
   
  # Undef on success:
  if( $is_filter )
  {
    if( defined($res) && $res > -1 )
    {
      $s->response->Status( $res );
      return $res;
    }

lib/ASP4/HTTPContext.pm  view on Meta::CPAN

206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
    }# end if()
  }
  else
  {
    return if (! defined($res)) || $res == -1;
    return $s->response->Status =~ m/^200/ ? undef : $s->response->Status;
  }# end if()
}# end handle_phase()
 
 
sub handle_error
{
  my $s = shift;
   
  $s->response->Status( 500 );
  $s->response->Clear();
  my $err_str = $@;
  my $error = $s->server->Error( $@ );
  warn "[Error: @{[ HTTP::Date::time2iso() ]}] $err_str\n";
   
  return $s->end_request;
}# end handle_error()
 
 
sub end_request
{
  my $s = shift;
   
  $s->response->End;
  my $res = $s->response->Status =~ m/^200/ ? 0 : $s->response->Status;
   
  return $res;

lib/ASP4/RequestFilter.pm  view on Meta::CPAN

29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
    my ($self, $context) = @_;
     
    if( $Session->{is_logged_in} )
    {
      # The user is logged in - we can ignore this request:
      return $Response->Declined;
    }
    else
    {
      # The user must authenticate first:
      $Session->{validation_errors} = { general => "You must log in first" };
      return $Response->Redirect("/login/");
    }# end if()
  }
   
  1;# return true:
 
Then, in your C<asp4-config.json>:
 
  {
    ...

lib/ASP4/Server.pm  view on Meta::CPAN

62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
    
  ASP4::HTTPContext->current->config->web->www_root . $path;
}# end MapPath()
 
 
sub Mail
{
  my $s = shift;
   
  Mail::Sendmail::sendmail( @_ );
  die $Mail::Sendmail::error if $Mail::Sendmail::error;
  return $Mail::Sendmail::log;
}# end Mail()
 
 
sub RegisterCleanup
{
  my ($s, $sub, @args) = @_;
   
  $s->context->r->pool->cleanup_register( $sub, \@args );
}# end RegisterCleanup()
 
 
sub Error
{
  my $s = shift;
   
  my $error = ref($_[0]) && $_[0]->isa('ASP4::Error') ? $_[0] : ASP4::Error->new( @_ );
 
  $s->context->stash->{error} = $error;
  $s->context->config->load_class( $s->context->config->errors->error_handler );
  my $error_handler = $s->context->config->errors->error_handler->new();
  $error_handler->init_asp_objects( $s->context );
  $error_handler->run( $s->context );
  return $error;
}# end Error()
 
 
1;# return true:
 
=pod
 
=head1 NAME
 
ASP4::Server - Utility Methods

lib/ASP4/Server.pm  view on Meta::CPAN

201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
The supplied coderef will be executed with its arguments as the request enters
its Cleanup phase.
 
See L<http://perl.apache.org/docs/2.0/user/handlers/http.html#PerlCleanupHandler> for details.
 
=head2 Error( [%args] )
 
Calling C<<$Server->Error()>> without arguments will use the value of C<$@> and
generate a L<ASP4::Error> object from it, then pass it to the C<run(...)> method
of your C<<$Config->errors->error_handler>> for processing.
 
Please take a look at the documentation for L<ASP4::Error>, L<ASP4::ErrorHandler>
and L<ASP4::ErrorHandler::Remote> for details on how errors are handled.
 
=head1 BUGS
 
It's possible that some bugs have found their way into this release.
 
Use RT L<http://rt.cpan.org/NoAuth/Bugs.html?Dist=ASP4> to submit bug reports.
 
=head1 HOMEPAGE
 
Please visit the ASP4 homepage at L<http://0x31337.org/code/> to see examples

sbin/asp4-deploy  view on Meta::CPAN

22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
  -d $target && chdir($target)
    or die "Invalid --target: '$target': $!\n";
}# end if()
 
if( -d 'latest' )
{
  `rm -f deploying`;
   
  # Copy over the config files:
  `tar -zxvf "$src" && ln -s "$id" deploying`;
  my @test_errors = ( );
  foreach( grep { $_ !~ m{latest/common$} } <latest/*> )
  {
    my ($folder) = $_ =~ m{latest/([^/]+)};
    `cp -rf latest/$folder/conf/* deploying/$folder/conf/`;
    chdir("deploying/$folder");
    unless( eval { runtests( <t/*/*.t> ) } ) #/
    {
      push @test_errors, $@;
    }# end unless()
  }# end foreach()
  chdir($start_cwd);
   
  if( @test_errors )
  {
    die "Tests failed:\n", join "\n", @test_errors;
  }# end if()
   
  `rm -rf latest`;
  `rm -rf deploying`;
  `ln -s "$id" latest`;
}
else
{
  `tar -zxvf "$src" && ln -s "$id" latest`;
  my @to_update = ( );

sbin/asp4-deploy  view on Meta::CPAN

153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
  /var/www/myweb/deploying  ->  /var/www/myweb/MyWeb_2011-11-15_23.59.39
 
=item Step 3
 
Copies all your configuration files from 'C<latest/*/conf/*>' into 'C<deploying/*/conf/*>'
 
=item Step 4
 
Runs unit tests on all folders under deploying except for 'C<common>'.
 
If all tests pass, we continue.  Otherwise, we bail out with errors.
 
=item Step 5
 
Unlink the C<deploying> symbolic link and change C<latest> to point to the new directory.
 
=item Step 6
 
B<After a successful deployment, you should restart apache.>
 
=back

sbin/asphelper  view on Meta::CPAN

48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
  $dbUser,
  $dbPass
);
 
my $drh = DBI->install_driver("mysql");
my $rc = $drh->func('createdb', $dbName, $dbHost, $dbUser, $dbPass, 'admin');
 
my $dbh = eval { DBI->connect( @DSN, {RaiseError => 1} ) };
if( $@ )
{
  (my $error = $@) =~ s/\sat\s\Q$0\E\s+line.*//;
  die "[ERROR]: $error\n";
}# end if()
 
# Setup folder structure:
(my $project_path = lc($appName)) =~ s{::}{_}sg;
make_path($project_path);
chdir($project_path);
my $cwd = cwd();
my $appFolder = join( '/'split(/::/, $appName) );
make_path("common/lib/$appFolder/db");
make_path("common/sbin");

sbin/asphelper  view on Meta::CPAN

381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
    "@ServerRoot@/lib",
    "@ProjectRoot@/common/lib"
  ],
  "load_modules": [
  ],
  "env_vars": {
  },
  "settings": {
  }
},
"errors": {
  "error_handler":    "ASP4::ErrorHandler",
  "mail_errors_to":   "%email%",
  "mail_errors_from": "root@localhost",
  "smtp_server":      "localhost"
},
"web": {
  "application_name": "%appName%",
  "application_root": "@ServerRoot@",
  "www_root":         "@ServerRoot@/htdocs",
  "handler_root":     "@ServerRoot@/handlers",
  "page_cache_root""/tmp/PAGE_CACHE",
  "handler_resolver": "ASP4::HandlerResolver",
  "handler_runner":   "ASP4::HandlerRunner",

sbin/asphelper  view on Meta::CPAN

463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
sub generic_httpconf {
  <<'EOF';
 
# Load up some important modules:
PerlModule DBI
PerlModule DBD::mysql
PerlModule ASP4::ModPerl
 
# Apache2::Reload does not play well with ASP4.
# Uncomment the following line if you get Apache2::Reload errors:
#PerlSetVar ReloadAll Off
 
# Admin website:
<VirtualHost *:80>
 
  ServerName    %domain%
  DocumentRoot  %CWD%/www/htdocs
   
  # Set the directory index:
  DirectoryIndex index.asp

t/010-basic/090-everything.t  view on Meta::CPAN

37
38
39
40
41
42
43
44
45
46
47
48
# static 404:
{
  ok(
    my $res = $api->ua->get('/missing-file.txt'),
    "Requested /missing-file.txt"
  );
  ok(
    ! $res->is_success,
    "Not successful"
  );
  like $res->status_line, qr{^404}, "Status looks like a 404 error";
}

t/conf/asp4-config.json  view on Meta::CPAN

13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
    
  "env_vars": {
    "myvar":        "Some-Value",
    "another_var""Another Value"
  },
  "settings": {
    "foo": "bar",
    "baz": "bux"
  }
},
"errors": {
  "error_handler":    "ASP4::ErrorHandler",
  "mail_errors_to":   "jdrago_999@yahoo.com",
  "mail_errors_from": "root@localhost",
  "smtp_server":      "localhost"
},
"web": {
  "application_name": "DefaultApp",
  "application_root": "@ServerRoot@",
  "www_root":         "@ServerRoot@/htdocs",
  "handler_root":     "@ServerRoot@/handlers",
  "handler_resolver": "ASP4::HandlerResolver",
  "handler_runner":   "ASP4::HandlerRunner",
  "filter_resolver""ASP4::FilterResolver",



( run in 0.481 second using v1.01-cache-2.11-cpan-26ccb49234f )