CGI.pm 4.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117
  1. package Troglodyne::CGI;
  2. use strict;
  3. use warnings;
  4. # Need to also get POST args, etc.
  5. sub get_args {
  6. my $meth = $ENV{'REQUEST_METHOD'};
  7. die "Unsupported request method: '$meth'" if !grep{ $meth eq $_ } qw{GET POST};
  8. my $args_hr = {};
  9. my %handlers = (
  10. 'GET' => sub { return { map { split( /=/, $_ ) } split( /&/, $ENV{'QUERY_STRING'} ) } },
  11. 'POST' => sub {
  12. die "Content length longer than 4096 bytes on a POST. Get lost!" if $ENV{'CONTENT_LENGTH'} > 4096;
  13. sysread( STDIN, my $line, $ENV{'CONTENT_LENGTH'} );
  14. return { map { split( /=/, $_ ) } split( /&/, $line ) };
  15. },
  16. );
  17. $args_hr = $handlers{$meth}->();
  18. return $args_hr;
  19. }
  20. our $CP_SECURITY_TOKEN = $ENV{'cp_security_token'} || 'cpsess0000000000';
  21. our $CP_USER = $ENV{'REMOTE_USER'} || 'nobody';
  22. # XXX TODO TODO TODO Need to make API calls return 304 unmodified if the data is
  23. # unchanged! hehehe
  24. # TODO delete cached templates via cron or hook or something, as the cache files
  25. # will otherwise begin to pile up.
  26. # Suggest using Cpanel::Session::is_active_security_token_for_user($user,$token)
  27. # in a loop and trashing inactive templates.
  28. # Yay. I now have ~250ms pageloads instead of 350+ms pageloads.
  29. # XXX Need to check when the chrome updates and pop cache then too?
  30. # Maybe upcp hook instead?
  31. sub render_cached_or_process_template {
  32. my ( $service, $input_hr ) = @_;
  33. if( $input_hr->{'troglodyne_do_static_render'} ) {
  34. # Try to print from cache, as Cpanel::Template is slow AF
  35. my ( $cached, $cache_dir ) = cached( $service, $input_hr->{'template_file'} );
  36. return if( $cached && render_from_cache($cache_dir) );
  37. # OK, so no cache. Let's fix that.
  38. $input_hr->{'print'} = 0;
  39. require Cpanel::Template;
  40. my ( $success, $output_sr ) = Cpanel::Template::process_template( $service, $input_hr );
  41. # TODO: Investigate whether I can send to two filehandles simultaneously -- $output_sr and STDOUT (as we are a CGI).
  42. # Then we could cache & print without the below step.
  43. if( $success ) {
  44. return if render_to_cache_and_print( $cache_dir, $output_sr );
  45. }
  46. }
  47. # Crap, everything failed. Just try to print it, sigh
  48. require Cpanel::Template;
  49. Cpanel::Template::process_template( $service, $input_hr );
  50. return;
  51. }
  52. sub render_to_cache_and_print {
  53. my ( $cache_dir, $content_sr ) = @_;
  54. local $@;
  55. require Cpanel::Mkdir;
  56. Cpanel::Mkdir::ensure_directory_existence_and_mode($cache_dir, 0711);
  57. my $worked = eval {
  58. open( my $fh, '>', "$cache_dir/$CP_SECURITY_TOKEN" ) or die "Couldn't open cache file \"$cache_dir/$CP_SECURITY_TOKEN\" for writing: $!";
  59. print $fh $$content_sr;
  60. print STDOUT $$content_sr;
  61. };
  62. if(my $err = $@) {
  63. # Require bashes $@, so assign first
  64. require Cpanel::Debug;
  65. Cpanel::Debug::log_error($err);
  66. }
  67. return $worked;
  68. }
  69. sub render_from_cache {
  70. my ( $cache_dir ) = @_;
  71. local $@;
  72. my $worked = eval {
  73. open( my $fh, '<', "$cache_dir/$CP_SECURITY_TOKEN" ) or die "Couldn't open cache file \"$cache_dir/$CP_SECURITY_TOKEN\" for reading: $!";
  74. while( <$fh> ) { print $_; }
  75. 1;
  76. };
  77. if(my $err = $@) {
  78. # Require bashes $@, so assign first
  79. require Cpanel::Debug;
  80. Cpanel::Debug::log_error($err);
  81. }
  82. return $worked;
  83. }
  84. # These MUST be indexed by cp_security_token... sadly
  85. our $ULC = '/usr/local/cpanel';
  86. our %TMPL_DIRS_BY_SVC = (
  87. 'whostmgr' => 'whostmgr/docroot/templates',
  88. 'cpanel' => 'base/frontend/paper_lantern',
  89. 'webmail' => 'base/webmail/paper_lantern',
  90. );
  91. sub cached {
  92. my ( $service, $tmpl_file ) = @_;
  93. my $tmpl_path = "$ULC/$TMPL_DIRS_BY_SVC{$service}/$tmpl_file";
  94. my $cache_dir = "${tmpl_path}_caches/$CP_USER";
  95. my $cache_path = "$cache_dir/$CP_SECURITY_TOKEN";
  96. # If cache mtime is older than template mtime, we are fine to use the cache.
  97. my $cached = ( -s $cache_path && ( (stat(_))[9] > (stat($tmpl_path))[9] ) );
  98. return ( $cached, $cache_dir );
  99. }
  100. 1;