[system] / trunk / webwork2 / lib / WeBWorK.pm Repository:
ViewVC logotype

View of /trunk/webwork2/lib/WeBWorK.pm

Parent Directory Parent Directory | Revision Log Revision Log


Revision 3307 - (download) (as text) (annotate)
Wed Jun 22 15:18:32 2005 UTC (7 years, 11 months ago) by gage
File size: 11315 byte(s)
Use the Timing::HiRes module to calculate timing data for each
request. This gives more accurate timing data (using the unix
time gives only to the nearest second).  I am printing the elapsed
time to 3 decimal places, it could be to 6 if that is desirable.

This will help us evaluate whether changes are increasing or decreasing
the speed with which requests are serviced.

    1 ################################################################################
    2 # WeBWorK Online Homework Delivery System
    3 # Copyright © 2000-2003 The WeBWorK Project, http://openwebwork.sf.net/
    4 # $CVSHeader: webwork-modperl/lib/WeBWorK.pm,v 1.70 2004/12/20 21:08:06 sh002i Exp $
    5 #
    6 # This program is free software; you can redistribute it and/or modify it under
    7 # the terms of either: (a) the GNU General Public License as published by the
    8 # Free Software Foundation; either version 2, or (at your option) any later
    9 # version, or (b) the "Artistic License" which comes with this package.
   10 #
   11 # This program is distributed in the hope that it will be useful, but WITHOUT
   12 # ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
   13 # FOR A PARTICULAR PURPOSE.  See either the GNU General Public License or the
   14 # Artistic License for more details.
   15 ################################################################################
   16 
   17 package WeBWorK;
   18 
   19 =head1 NAME
   20 
   21 WeBWorK - Dispatch requests to the appropriate content generator.
   22 
   23 =head1 SYNOPSIS
   24 
   25  my $r = Apache->request;
   26  my $result = eval { WeBWorK::dispatch($r) };
   27  die "something bad happened: $@" if $@;
   28 
   29 =head1 DESCRIPTION
   30 
   31 C<WeBWorK> is the dispatcher for the WeBWorK system. Given an Apache request
   32 object, it performs authentication and determines which subclass of
   33 C<WeBWorK::ContentGenerator> to call.
   34 
   35 =cut
   36 
   37 BEGIN { $main::VERSION = "2.1"; }
   38 
   39 use strict;
   40 use warnings;
   41 use Apache::Constants qw(:common REDIRECT DONE);
   42 
   43 # load WeBWorK::Constants before anything else
   44 # this sets package variables in several packages
   45 use WeBWorK::Constants;
   46 
   47 # the rest of these are modules that are acutally used by this one
   48 use WeBWorK::Authen;
   49 use WeBWorK::Authz;
   50 use WeBWorK::CourseEnvironment;
   51 use WeBWorK::DB;
   52 use WeBWorK::Debug;
   53 use WeBWorK::Request;
   54 use WeBWorK::Timing;
   55 use WeBWorK::Upload;
   56 use WeBWorK::URLPath;
   57 use WeBWorK::Utils qw(runtime_use writeTimingLogEntry);
   58 use Date::Format;
   59 
   60 use constant AUTHEN_MODULE => "WeBWorK::ContentGenerator::Login";
   61 use constant FIXDB_MODULE => "WeBWorK::ContentGenerator::FixDB";
   62 
   63 our %SeedCE;
   64 
   65 sub dispatch($) {
   66   my ($apache) = @_;
   67   my $r = new WeBWorK::Request $apache;
   68 
   69   my $method = $r->method;
   70   my $location = $r->location;
   71   my $uri = $r->uri;
   72   my $path_info = $r->path_info | "";
   73   my $args = $r->args || "";
   74   #my $webwork_root = $r->dir_config("webwork_root");
   75   #my $pg_root = $r->dir_config("pg_root");
   76 
   77   debug("\n\n===> Begin " . __PACKAGE__ . "::dispatch() <===\n\n");
   78   debug("Hi, I'm the new dispatcher!\n");
   79   debug(("-" x 80) . "\n");
   80 
   81   debug("Okay, I got some basic information:\n");
   82   debug("The apache location is $location\n");
   83   debug("The request method is $method\n");
   84   debug("The URI is $uri\n");
   85   debug("The path-info is $path_info\n");
   86   debug("The argument string is $args\n");
   87   #debug("The WeBWorK root directory is $webwork_root\n");
   88   #debug("The PG root directory is $pg_root\n");
   89   debug(("-" x 80) . "\n");
   90 
   91   debug("The first thing we need to do is munge the path a little:\n");
   92 
   93   my ($path) = $uri =~ m/$location(.*)/;
   94   $path = "/" if $path eq ""; # no path at all
   95 
   96   debug("We can't trust the path-info, so we make our own path.\n");
   97   debug("path-info claims: $path_info\n");
   98   debug("but it's really: $path\n");
   99   debug("(if it's empty, we set it to \"/\".)\n");
  100 
  101   $path =~ s|/+|/|g;
  102   debug("...and here it is without repeated slashes: $path\n");
  103 
  104   # lookbehind assertion for "not a slash"
  105   # matches the boundary after the last char
  106   $path =~ s|(?<=[^/])$|/|;
  107   debug("...and here it is with a trailing slash: $path\n");
  108 
  109   debug(("-" x 80) . "\n");
  110 
  111   debug("Now we need to look at the path a little to figure out where we are\n");
  112 
  113   debug("-------------------- call to WeBWorK::URLPath::newFromPath\n");
  114   my $urlPath = WeBWorK::URLPath->newFromPath($path);
  115   debug("-------------------- call to WeBWorK::URLPath::newFromPath\n");
  116 
  117   unless ($urlPath) {
  118     debug("This path is invalid... see you later!\n");
  119     die "The path '$path' is not valid.\n";
  120   }
  121 
  122   my $displayModule = $urlPath->module;
  123   my %displayArgs = $urlPath->args;
  124 
  125   unless ($displayModule) {
  126     debug("The display module is empty, so we can DECLINE here.\n");
  127     die "No display module found for path '$path'.";
  128   }
  129 
  130   debug("The display module for this path is: $displayModule\n");
  131   debug("...and here are the arguments we'll pass to it:\n");
  132   foreach my $key (keys %displayArgs) {
  133     debug("\t$key => $displayArgs{$key}\n");
  134   }
  135 
  136   my $selfPath = $urlPath->path;
  137   my $parent = $urlPath->parent;
  138   my $parentPath = $parent ? $parent->path : "<no parent>";
  139 
  140   debug("Reconstructing the original path gets us: $selfPath\n");
  141   debug("And we can generate the path to our parent, too: $parentPath\n");
  142   debug("(We could also figure out who our children are, but we'd need to supply additional arguments.)\n");
  143   debug(("-" x 80) . "\n");
  144 
  145   debug("The URLPath looks good, we'll add it to the request.\n");
  146   $r->urlpath($urlPath);
  147 
  148   debug("Now we want to look at the parameters we got.\n");
  149 
  150   debug("The raw params:\n");
  151   foreach my $key ($r->param) {
  152     debug("\t$key\n");
  153     debug("\t\t$_\n") foreach $r->param($key);
  154   }
  155 
  156   #mungeParams($r);
  157 
  158   debug("The munged params:\n");
  159   foreach my $key ($r->param) {
  160     debug("\t$key\n");
  161     debug("\t\t$_\n") foreach $r->param($key);
  162   }
  163 
  164   debug(("-" x 80) . "\n");
  165 
  166   # create a package-global timing object
  167   # FIXME: this is used by other modules!
  168   # FIXME: this is not thread-safe!
  169   my $label = defined $displayArgs{courseID} ? $displayArgs{courseID} : "ROOT";
  170   $WeBWorK::timer = WeBWorK::Timing->new($label);
  171   $WeBWorK::timer->start;
  172 
  173   debug("We need to get a course environment (with or without a courseID!)\n");
  174   my $ce = eval { new WeBWorK::CourseEnvironment({
  175     #webworkRoot => $r->dir_config("webwork_root"),
  176     #webworkURLRoot => $location,
  177     #pgRoot => $r->dir_config("pg_root"),
  178     %SeedCE,
  179     courseName => $displayArgs{courseID},
  180   }) };
  181   $@ and die "Failed to initialize course environment: $@\n";
  182   debug("Here's the course environment: $ce\n");
  183   $r->ce($ce);
  184 
  185   my @uploads = $r->upload;
  186   foreach my $u (@uploads) {
  187     # make sure it's a "real" upload
  188     next unless $u->filename;
  189 
  190     # store the upload
  191     my $upload = WeBWorK::Upload->store($u,
  192       dir => $ce->{webworkDirs}->{uploadCache}
  193     );
  194 
  195     # store the upload ID and hash in the file upload field
  196     my $id = $upload->id;
  197     my $hash = $upload->hash;
  198     $r->param($u->name => "$id $hash");
  199   }
  200 
  201   my ($db, $authz);
  202 
  203   if ($displayArgs{courseID}) {
  204     debug("We got a courseID from the URLPath, now we can do some stuff:\n");
  205 
  206     unless (-e $ce->{courseDirs}->{root}) {
  207       die "Course '$displayArgs{courseID}' not found: $!";
  208     }
  209 
  210     debug("...we can create a database object...\n");
  211     $db = new WeBWorK::DB($ce->{dbLayout});
  212     debug("(here's the DB handle: $db)\n");
  213     $r->db($db);
  214 
  215     debug("Now we check the database...\n");
  216     debug("(we can detect if a hash-style database from WW1 has not be converted properly.)\n");
  217     my ($dbOK, @dbMessages) = $db->hashDatabaseOK(0); # 0 == don't fix
  218     if (not $dbOK) {
  219       debug("hashDatabaseOK() returned $dbOK -- looks like trouble...\n");
  220       $displayModule = FIXDB_MODULE;
  221       debug("set displayModule to $displayModule\n");
  222     } else {
  223       debug("hashDatabaseOK() returned $dbOK -- leaving displayModule as-is\n");
  224     }
  225 
  226     debug("Create an authz object (Authen needs it to check login permission)...\n");
  227     $authz = new WeBWorK::Authz($r);
  228     debug("(here's the authz object: $authz)\n");
  229     $r->authz($authz);
  230 
  231     debug("...and now we can authenticate the remote user...\n");
  232     my $authen = new WeBWorK::Authen($r);
  233     my $authenOK = $authen->verify;
  234     if ($authenOK) {
  235       my $userID = $r->param("user");
  236       debug("Hi, $userID, glad you made it.\n");
  237 
  238       # tell authorizer to cache this user's permission level
  239       $authz->setCachedUser($userID);
  240 
  241       debug("Now we deal with the effective user:\n");
  242       my $eUserID = $r->param("effectiveUser") || $userID;
  243       debug("userID=$userID eUserID=$eUserID\n");
  244       my $su_authorized = $authz->hasPermissions($userID, "become_student", $eUserID);
  245       if ($su_authorized) {
  246         debug("Ok, looks like you're allowed to become $eUserID. Whoopie!\n");
  247       } else {
  248         debug("Uh oh, you're not allowed to become $eUserID. Nice try!\n");
  249         $eUserID = $userID;
  250       }
  251       $r->param("effectiveUser" => $eUserID);
  252     } else {
  253       debug("Bad news: authentication failed!\n");
  254       $displayModule = AUTHEN_MODULE;
  255       debug("set displayModule to $displayModule\n");
  256     }
  257   }
  258 
  259   ## if a course ID was given in the URL and resulted in an error (as stored in $!)
  260   ## it probably means that the course does not exist or was misspelled
  261   #if ($displayArgs{courseID} and $ce->{'!'}) {
  262   # debug("Something was wrong with the courseID: \n");
  263   # debug("\t\t" . $ce->{'!'} . "\n");
  264   # debug("Time to bail!\n");
  265   # die "An error occured while accessing '$displayArgs{courseID}': '", $ce->{'!'}, "'.\n";
  266   #}
  267 
  268   debug(("-" x 80) . "\n");
  269   debug("Finally, we'll load the display module...\n");
  270 
  271   # The "production timer" uses a finer grained HiRes timing module
  272   # rather than the standard unix "time".
  273   #my $localStartTime = time;
  274   my $productionTimer = WeBWorK::Timing->new($label);
  275   $productionTimer->start();
  276   runtime_use($displayModule);
  277 
  278   debug("...instantiate it...\n");
  279 
  280   my $instance = $displayModule->new($r);
  281 
  282   debug("...and call it:\n");
  283   debug("-------------------- call to ${displayModule}::go\n");
  284 
  285   my $result = $instance->go();
  286 
  287   debug("-------------------- call to ${displayModule}::go\n");
  288 
  289   debug("returning result: " . (defined $result ? $result : "UNDEF") . "\n");
  290   #$WeBWorK::timer->continue("[" . time2str("%a %b %d %H:%M:%S %Y", time) . "]" . "[" . $r->uri . "]");
  291   #$WeBWorK::timer->stop();
  292   #$WeBWorK::timer->save();
  293 
  294   #my $localStopTime = time;
  295   $productionTimer->stop();
  296   #my $timeDiff = $localStopTime - $localStartTime;
  297   my $productionTimeDiff    = $productionTimer->{stop} - $productionTimer->{start};
  298   writeTimingLogEntry($ce,"[".$r->uri."]", sprintf("runTime = %.3f sec", $productionTimeDiff)." ".$ce->{dbLayoutName},"" );
  299   return $result;
  300 
  301 }
  302 
  303 sub mungeParams {
  304   my ($r) = @_;
  305 
  306   my @paramQueue;
  307 
  308   # remove all the params from the request, and store them in the param queue
  309   foreach my $key ($r->param) {
  310     push @paramQueue, [ $key => [ $r->param($key) ] ];
  311     $r->parms->unset($key)
  312   }
  313 
  314   # exhaust the param queue, decoding encoded params
  315   while (@paramQueue) {
  316     my ($key, $values) = @{ shift @paramQueue };
  317 
  318     if ($key =~ m/\,/) {
  319       # we have multiple params encoded in a single param
  320       # split them up and add them to the end of the queue
  321       push @paramQueue, map { [ $_, $values ] } split m/\,/, $key;
  322     } elsif ($key =~ m/\:/) {
  323       # we have a whole param encoded in a key
  324       # split it up and add it to the end of the queue
  325       my ($newKey, $newValue) = split m/\:/, $key;
  326       push @paramQueue, [ $newKey, [ $newValue ] ];
  327     } else {
  328       # this is a "normal" param
  329       # add it to the param list
  330       if (defined $r->param($key)) {
  331         # the param already exists -- append the values we have
  332         $r->param($key => [ $r->param($key), @$values ]);
  333       } else {
  334         # the param doesn't exist -- create it with the values we have
  335         $r->param($key => $values);
  336       }
  337     }
  338   }
  339 }
  340 
  341 
  342 =head1 AUTHOR
  343 
  344 Written by Dennis Lambe, malsyned at math.rochester.edu. Modified by Sam
  345 Hathaway, sh002i at math.rochester.edu.
  346 
  347 =cut
  348 
  349 1;

aubreyja at gmail dot com
ViewVC Help
Powered by ViewVC 1.0.9