Changeset 4065


Ignore:
Timestamp:
06/09/09 11:34:42 (4 years ago)
Author:
MichaelDaum
Message:

Item1699: Item3695: Item1698: Item1699:

  • added Foswiki:Development/FoswikiCache (some experimental cache backends will go out again)
  • removing html before generating anchor heads for TOC and headlines
  • distinguish browsers more accurately so that not everything is Mozilla
  • fixed %RENDERHEAD% to be usable actually
Location:
trunk/core/lib
Files:
16 added
7 edited

Legend:

Unmodified
Added
Removed
  • trunk/core/lib/Foswiki.pm

    r3980 r4065  
    6363use Foswiki::Store           (); 
    6464use Foswiki::Users           (); 
     65use Foswiki::PageCache       (); 
    6566 
    6667require 5.005;    # For regex objects and internationalisation 
     
    208209        REMOTE_PORT       => \&REMOTE_PORT_deprecated, 
    209210        REMOTE_USER       => \&REMOTE_USER_deprecated, 
    210         RENDERHEAD        => \&RENDERHEAD, 
    211211        REVINFO           => \&REVINFO, 
    212212        REVTITLE          => \&REVTITLE, 
     
    232232        WIKINAME          => \&WIKINAME_deprecated, 
    233233        WIKIUSERNAME      => \&WIKIUSERNAME_deprecated, 
     234        DISPLAYDEPENDENCIES => \&DISPLAYDEPENDENCIES, 
    234235 
    235236        # Constant tag strings _not_ dependent on config. These get nicely 
     
    639640    $contentType ||= 'text/html'; 
    640641 
    641     if ( $contentType ne 'text/plain' ) { 
    642  
    643         # Remove <nop> and <noautolink> tags 
    644         $text =~ s/([\t ]?)[ \t]*<\/?(nop|noautolink)\/?>/$1/gis; 
    645         $text .= "\n" unless $text =~ /\n$/s; 
    646  
    647         my $cgis = $this->getCGISession(); 
    648         if ( $cgis && $contentType eq 'text/html' 
    649                && $Foswiki::cfg{Validation}{Method} ne 'none') { 
    650  
    651             # Don't expire the validation key through login, or when 
    652             # endpoint is an error. 
    653             Foswiki::Validation::expireValidationKeys($cgis) 
    654               unless ( $this->{request}->action() eq 'login' 
    655                 or ( $ENV{REDIRECT_STATUS} || 0 ) >= 400 ); 
    656  
    657             my $usingStrikeOne = 0; 
    658             if ($Foswiki::cfg{Validation}{Method} eq 'strikeone' 
    659                   # Add the onsubmit handler to the form 
    660                   && $text =~ s/(<form[^>]*method=['"]POST['"][^>]*>)/ 
    661                     Foswiki::Validation::addOnSubmit($1)/gei) { 
    662                 # At least one form has been touched; add the validation 
    663                 # cookie 
    664                 $this->{users}->{loginManager}->addCookie( 
    665                     Foswiki::Validation::getCookie( 
    666                         $cgis, $this->{response})); 
    667                 # Add the JS module to the page. Note that this is *not* 
    668                 # incorporated into the foswikilib.js because that module 
    669                 # is conditionally loaded under the control of the 
    670                 # templates, and we have to be *sure* it gets loaded. 
    671                 $this->addToHEAD( 'FOSWIKI STRIKE ONE', 
    672                                   <<STRIKEONE); 
     642    my $cgis = $this->getCGISession(); 
     643    if ( $cgis && $contentType eq 'text/html' 
     644           && $Foswiki::cfg{Validation}{Method} ne 'none') { 
     645 
     646        # Don't expire the validation key through login, or when 
     647        # endpoint is an error. 
     648        Foswiki::Validation::expireValidationKeys($cgis) 
     649          unless ( $this->{request}->action() eq 'login' 
     650            or ( $ENV{REDIRECT_STATUS} || 0 ) >= 400 ); 
     651 
     652        my $usingStrikeOne = 0; 
     653        if ($Foswiki::cfg{Validation}{Method} eq 'strikeone' 
     654              # Add the onsubmit handler to the form 
     655              && $text =~ s/(<form[^>]*method=['"]POST['"][^>]*>)/ 
     656                Foswiki::Validation::addOnSubmit($1)/gei) { 
     657 
     658            # At least one form has been touched; add the validation 
     659            # cookie 
     660            $this->{users}->{loginManager}->addCookie( 
     661                Foswiki::Validation::getCookie( 
     662                    $cgis, $this->{response})); 
     663            # Add the JS module to the page. Note that this is *not* 
     664            # incorporated into the foswikilib.js because that module 
     665            # is conditionally loaded under the control of the 
     666            # templates, and we have to be *sure* it gets loaded. 
     667            $this->addToHEAD( 'FOSWIKI STRIKE ONE', 
     668                              <<STRIKEONE); 
    673669<script type="text/javascript" src="$Foswiki::cfg{PubUrlPath}/$Foswiki::cfg{SystemWebName}/JavascriptFiles/strikeone.js"></script> 
    674670STRIKEONE 
    675                 $usingStrikeOne = 1; 
    676             } 
    677             # Inject validation key in HTML forms 
    678             my $context = 
    679               $this->{request}->url( -full => 1, -path => 1, -query => 1 ) 
    680                 . time(); 
    681             $text =~ s/(<form[^>]*method=['"]POST['"][^>]*>)/ 
    682               $1 . Foswiki::Validation::addValidationKey( 
    683                   $cgis, $context, $usingStrikeOne )/gei; 
    684         } 
    685         my $htmlHeader = join( "\n", 
    686             map { '<!--' . $_ . '-->' . $this->{_HTMLHEADERS}{$_} } 
    687               keys %{ $this->{_HTMLHEADERS} } ); 
    688         $text =~ s!(</head>)!$htmlHeader$1!i if $htmlHeader; 
    689         chomp($text); 
    690     } 
    691  
    692     $this->generateHTTPHeaders( $pageType, $contentType ); 
    693     my $hdr = $this->{response}->printHeaders; 
     671            $usingStrikeOne = 1; 
     672        } 
     673 
     674        # Inject validation key in HTML forms 
     675        my $context = 
     676          $this->{request}->url( -full => 1, -path => 1, -query => 1 ) 
     677            . time(); 
     678        $text =~ s/(<form[^>]*method=['"]POST['"][^>]*>)/ 
     679          $1 . Foswiki::Validation::addValidationKey( 
     680              $cgis, $context, $usingStrikeOne )/gei; 
     681    } 
     682 
     683    my $htmlHeader = _genHeaders($this); 
     684    unless ($text =~ s/%RENDERHEAD%/$htmlHeader/g) { 
     685      # fallback if there's no RENDERHEAD in the skin 
     686      $text =~ s!(</head>)!$htmlHeader$1!i if $htmlHeader; 
     687    } 
     688    chomp($text); 
     689 
     690    # SMELL: can't compute; faking content-type for backwards compatibility; 
     691    # any other information might become bogus later anyway 
     692    my $hdr = "Content-type: ".$contentType."\r\n"; 
    694693 
    695694    # Call final handler 
    696     $this->{plugins}->dispatch( 'completePageHandler', $text, $hdr ); 
     695    $this->{plugins}->dispatch('completePageHandler', $text, $hdr); 
     696 
     697    # cache final page, but only view 
     698    my $cachedPage; 
     699    if ($this->inContext('view') && $Foswiki::cfg{Cache}{Enabled}) { 
     700        $cachedPage = $this->{cache}->cachePage($contentType, $text); 
     701        $this->{cache}->renderDirtyAreas(\$text) if $cachedPage->{isDirty}; 
     702    } else { 
     703      # remove <dirtyarea> tags 
     704      $text =~ s/<\/?dirtyarea[^>]*>//go; 
     705    } 
     706 
     707    # Remove <nop> and <noautolink> tags 
     708    $text =~ s/([\t ]?)[ \t]*<\/?(nop|noautolink)\/?>/$1/gis; 
     709 
     710    $this->generateHTTPHeaders( $pageType, $contentType, $text, $cachedPage ); 
     711 
     712    # SMELL: null operation. the http headers are written out during Foswiki::Engine::finalize 
     713    #$hdr = $this->{response}->printHeaders; 
    697714 
    698715    $this->{response}->print($text); 
     
    701718=begin TML 
    702719 
    703 ---++ ObjectMethod generateHTTPHeaders( $pageType, $contentType ) -> $header 
     720---++ ObjectMethod generateHTTPHeaders( $pageType, $contentType, $text, $cachedPage ) 
    704721 
    705722All parameters are optional. 
     
    707724   * =$pageType= - May be "edit", which will cause headers to be generated that force caching for 24 hours, to prevent Codev.BackFromPreviewLosesText bug, which caused data loss with IE5 and IE6. 
    708725   * =$contentType= - page content type | text/html 
     726   * =$text= - page content 
     727   * =$cachedPage= - a pointer to the page container as fetched from the page cache 
    709728 
    710729=cut 
    711730 
    712731sub generateHTTPHeaders { 
    713     my ( $this, $pageType, $contentType ) = @_; 
     732    my( $this, $pageType, $contentType, $text, $cachedPage ) = @_; 
     733 
     734    my $hopts = {}; 
    714735 
    715736    # Handle Edit pages - future versions will extend to caching 
    716737    # of other types of page, with expiry time driven by page type. 
    717     my ( $pluginHeaders, $coreHeaders ); 
    718  
    719     my $hopts = {}; 
    720  
    721738    if ( $pageType && $pageType eq 'edit' ) { 
    722739 
     
    743760    # DEPRECATED plugins header handler. Plugins should use 
    744761    # modifyHeaderHandler instead. 
    745     $pluginHeaders = 
     762    my $pluginHeaders = 
    746763      $this->{plugins}->dispatch( 'writeHeaderHandler', $this->{request} ) 
    747764      || ''; 
     
    770787    # add cookie(s) 
    771788    $this->{users}->{loginManager}->modifyHeader($hopts); 
     789 
     790    # add http compression and conditional cache controls 
     791    if (!$this->inContext('command_line') && $text) { 
     792 
     793        my $contentEncodingHdr = ''; 
     794        if ($Foswiki::cfg{Cache}{Enabled} && 
     795            $Foswiki::cfg{Cache}{Compress}) { 
     796          # compress 
     797          if ($ENV{'HTTP_ACCEPT_ENCODING'} && 
     798              $ENV{'HTTP_ACCEPT_ENCODING'} =~ /(x-gzip|gzip)/i) { 
     799            my $encoding = $1; 
     800 
     801            # check if we take the compressed version from the cache 
     802            if ($cachedPage && !$cachedPage->{isDirty}) { 
     803              $text = $cachedPage->{text};  
     804            } else { 
     805 
     806              # well, then compress it now 
     807              if (!$cachedPage || $cachedPage->{isDirty}) { 
     808                require Compress::Zlib; 
     809                $text = Compress::Zlib::memGzip($text); 
     810                #print STDERR "compressing\n"; 
     811              } 
     812            } 
     813 
     814            $hopts->{'Content-Encoding'} = $encoding; 
     815            $hopts->{'Vary'} = 'Accept-Encoding'; 
     816 
     817          } else { 
     818            if ($cachedPage && !$cachedPage->{isDirty}) { 
     819 
     820              # sorry, we need to uncompressed pages from cache again 
     821              require Compress::Zlib; 
     822              $text = Compress::Zlib::memGunzip($text); 
     823              #print STDERR "uncompressing\n"; 
     824            } 
     825          } 
     826        } else { 
     827          if ($cachedPage && !$cachedPage->{isDirty}) { 
     828            $text = $cachedPage->{text}  
     829          } 
     830        } 
     831 
     832        # we need to force the browser into a check on every 
     833        # request; let the server decide on an 304 as below 
     834        $hopts->{'Cache-Control'} = 'max-age=0'; 
     835 
     836        # check etag and last modification time 
     837        # if we have a cached page on the server side 
     838        if ($cachedPage) { 
     839          my $etag = $cachedPage->{etag}; 
     840          my $lastModified = $cachedPage->{lastModified}; 
     841 
     842          $hopts->{'ETag'} = $etag; 
     843          $hopts->{'Last-Modified'} = $lastModified; 
     844 
     845          # only send a 304 if both criteria are true 
     846          my $etagFlag = 1; 
     847          my $lastModifiedFlag = 1; 
     848 
     849          # check etag 
     850          unless ($ENV{'HTTP_IF_NONE_MATCH'} && 
     851              $etag eq $ENV{'HTTP_IF_NONE_MATCH'}) { 
     852            $etagFlag = 0; 
     853          } 
     854 
     855          # check last-modified 
     856          unless ($ENV{'HTTP_IF_MODIFIED_SINCE'} && 
     857              $lastModified eq $ENV{'HTTP_IF_MODIFIED_SINCE'}) { 
     858            $lastModifiedFlag = 0; 
     859          }  
     860 
     861          # finally decide on a 304 reply 
     862          if ($etagFlag && $lastModified) { 
     863            $hopts->{'Status'} = '304 Not Modified'; 
     864            $text = ''; 
     865            #print STDERR "NOT modified\n"; 
     866          } 
     867        } 
     868 
     869        # write back to text 
     870        $_[3] = $text; 
     871    } 
     872 
     873    $hopts->{"X-FoswikiAction"} = $this->{request}->action; 
     874    $hopts->{"X-FoswikiURI"} = $this->{request}->uri; 
    772875 
    773876    # The headers method resets all headers to what we pass 
     
    14351538    $this->{context}      = $initialContext; 
    14361539 
     1540    $this->{cache} = new Foswiki::PageCache( $this ); 
    14371541    my $prefs = new Foswiki::Prefs($this); 
    14381542    $this->{prefs}   = $prefs; 
     
    17971901    $this->{i18n}->finish() if $this->{i18n}; 
    17981902    undef $this->{i18n}; 
     1903    $this->{cache}->finish() if $this->{cache}; 
    17991904 
    18001905    undef $this->{_HTMLHEADERS}; 
     
    18521957            my $agent = $cgiQuery->user_agent(); 
    18531958            if ($agent) { 
    1854                 if ( $agent =~ m/([\w]+)/ ) { 
    1855                     $extra .= ' ' . $1; 
     1959                $extra .= ' ' if $extra; 
     1960                if ( $agent =~ /(MSIE 6|MSIE 7|Firefox|Opera|Konqueror|Safari)/ ) { 
     1961                  $extra .= $1; 
     1962                } else { 
     1963                  $agent =~ m/([\w]+)/; 
     1964                  $extra .= $1; 
    18561965                } 
    18571966            } 
     
    25612670 
    25622671    my $verbatim = {}; 
    2563     $text = $this->renderer->takeOutBlocks( $text, 'verbatim', $verbatim ); 
     2672    $text = $this->renderer->takeOutBlocks( $text, 'verbatim', 
     2673                                               $verbatim); 
     2674 
     2675    my $dirtyAreas = {}; 
     2676    $text = $this->renderer->takeOutBlocks( $text, 'dirtyarea', $dirtyAreas)  
     2677      if $Foswiki::cfg{Cache}{Enabled}; 
     2678 
    25642679 
    25652680    # See Item1442 
     
    26772792    #$stackTop =~ s/$percent/%/go; 
    26782793 
     2794    $this->renderer->putBackBlocks( \$stackTop, $dirtyAreas, 'dirtyarea' ) 
     2795      if $Foswiki::cfg{Cache}{Enabled}; 
    26792796    $this->renderer->putBackBlocks( \$stackTop, $verbatim, 'verbatim' ); 
    26802797 
     
    28122929=begin TML 
    28132930 
    2814 ---++ ObjectMethod handleCommonTags( $text, $topicObject ) -> $text 
     2931---++ ObjectMethod expandMacros( $text, $topicObject ) -> $text 
    28152932 
    28162933Processes %<nop>VARIABLE%, and %<nop>TOC% syntax; also includes 
     
    28312948 
    28322949    return $text unless $text; 
    2833     my $verbatim = {}; 
    28342950 
    28352951    # Plugin Hook (for cache Plugins only) 
     
    28402956    #use a "global var", so included topics can extract and putback 
    28412957    #their verbatim blocks safetly. 
    2842     $text = $this->renderer->takeOutBlocks( $text, 'verbatim', $verbatim ); 
     2958    my $verbatim={}; 
     2959    $text = $this->renderer->takeOutBlocks( $text, 'verbatim', 
     2960                                              $verbatim); 
     2961 
     2962    # take out dirty areas 
     2963    my $dirtyAreas = {}; 
     2964    $text = $this->renderer->takeOutBlocks( $text, 'dirtyarea', $dirtyAreas ) 
     2965      if $Foswiki::cfg{Cache}{Enabled}; 
     2966 
    28432967 
    28442968    # Require defaults for plugin handlers :-( 
     
    28813005    $text =~ s/^<nop>\r?\n//gm; 
    28823006 
     3007    # restore dirty areas 
     3008    $this->renderer->putBackBlocks( \$text, $dirtyAreas, 'dirtyarea' ) 
     3009      if $Foswiki::cfg{Cache}{Enabled}; 
     3010 
     3011 
    28833012    $this->renderer->putBackBlocks( \$text, $verbatim, 'verbatim' ); 
    28843013 
     
    29043033    my ( $this, $tag, $header, $requires, $topicObject ) = @_; 
    29053034 
     3035    return unless $header; # don't add empty or even undef stuff 
     3036 
    29063037    # Expand macros in the header 
    29073038    $header = $topicObject->expandMacros($header) if $topicObject; 
    29083039 
    2909     $this->{_SORTEDHEADS} ||= {}; 
     3040    $this->{_HTMLHEADERS} ||= {}; 
    29103041    $tag ||= ''; 
    29113042 
     
    29163047    my @requires; 
    29173048    foreach my $req ( split( /,\s*/, $requires ) ) { 
    2918         unless ( $this->{_SORTEDHEADS}->{$req} ) { 
    2919             $this->{_SORTEDHEADS}->{$req} = { 
     3049        unless ( $this->{_HTMLHEADERS}->{$req} ) { 
     3050            $this->{_HTMLHEADERS}->{$req} = { 
    29203051                tag      => $req, 
    29213052                requires => [], 
     
    29233054            }; 
    29243055        } 
    2925         push( @requires, $this->{_SORTEDHEADS}->{$req} ); 
    2926     } 
    2927     my $record = $this->{_SORTEDHEADS}->{$tag}; 
     3056        push( @requires, $this->{_HTMLHEADERS}->{$req} ); 
     3057    } 
     3058    my $record = $this->{_HTMLHEADERS}->{$tag}; 
    29283059    unless ($record) { 
    29293060        $record = { tag => $tag }; 
    2930         $this->{_SORTEDHEADS}->{$tag} = $record; 
     3061        $this->{_HTMLHEADERS}->{$tag} = $record; 
    29313062    } 
    29323063    $record->{requires} = \@requires; 
    29333064    $record->{header}   = $header; 
    2934  
    2935     # Temporary, for compatibility until %RENDERHEAD% is embedded 
    2936     # in the skins 
    2937     $this->{_HTMLHEADERS}{GENERATED_HEADERS} = _genHeaders($this); 
    29383065} 
    29393066 
     
    29503077sub _genHeaders { 
    29513078    my ($this) = @_; 
    2952     return '' unless $this->{_SORTEDHEADS}; 
     3079    return '' unless $this->{_HTMLHEADERS}; 
    29533080 
    29543081    # Loop through the vertices of the graph, in any order, initiating 
     
    29633090    my %visited; 
    29643091    my @total; 
    2965     foreach my $v ( values %{ $this->{_SORTEDHEADS} } ) { 
     3092    foreach my $v ( values %{ $this->{_HTMLHEADERS} } ) { 
    29663093        _visit( $v, \%visited, \@total ); 
    29673094    } 
    29683095 
    29693096    return join( "\n", map { "<!-- $_->{tag} --> $_->{header}" } @total ); 
    2970 } 
    2971  
    2972 =begin TML 
    2973  
    2974 ---+++ %<nop}RENDERHEAD% 
    2975 =%RENDERHEAD%= should be written where you want the sorted head tags to be generated. This will normally be in a template. The variable expands to a sorted list of the head blocks added up to the point the RENDERHEAD variable is expanded. Each expanded head block is preceded by an HTML comment that records the ID of the head block. 
    2976  
    2977 Head blocks are sorted to satisfy all their =requires= constraints. 
    2978 The output order of blocks with no =requires= value is undefined. If cycles 
    2979 exist in the dependency order, the cycles will be broken but the resulting 
    2980 order of blocks in the cycle is undefined. 
    2981  
    2982 =cut 
    2983  
    2984 sub RENDERHEAD { 
    2985     my $this = shift; 
    2986     return _genHeaders($this); 
    29873097} 
    29883098 
     
    33173427    # local (SESSION) macro definitions without polluting the including 
    33183428    # topic namespace. 
    3319     $this->{prefs}->pushTopicContext( $includedWeb, $includedTopic ); 
     3429    $this->{prefs}->pushTopicContext( $this->{webName}, $this->{topicName} ); 
    33203430 
    33213431    $this->{_INCLUDES}->{$key} = 1; 
     
    33333443    my $memTopic = $this->{prefs}->getPreference('INCLUDINGTOPIC'); 
    33343444 
     3445    my $dirtyAreas = {}; 
    33353446    try { 
    33363447 
     
    33593470            $text =~ s/%STOPINCLUDE%.*//s; 
    33603471        } 
     3472 
     3473        # prevent dirty areas in included topics from being parsed  
     3474        $text = $this->renderer->takeOutBlocks( $text, 'dirtyarea', $dirtyAreas)  
     3475          if $Foswiki::cfg{Cache}{Enabled}; 
    33613476 
    33623477        # handle sections 
     
    34473562            INCLUDINGTOPIC => $memTopic 
    34483563        ); 
     3564 
     3565        # restoring dirty areas 
     3566        $this->renderer->putBackBlocks( \$text, $dirtyAreas, 'dirtyarea' ) 
     3567          if $Foswiki::cfg{Cache}{Enabled}; 
    34493568 
    34503569        ( $this->{webName}, $this->{topicName} ) = 
     
    41344253sub META { 
    41354254    my ( $this, $params, $topicObject ) = @_; 
     4255     
     4256    $topicObject->reload() unless $topicObject->getLoadedRev(); 
    41364257 
    41374258    my $option = $params->{_DEFAULT} || ''; 
     
    43124433 
    43134434    return '| *Group* | *Members* |' . "\n" . join( "\n", sort @table ); 
     4435} 
     4436 
     4437sub DISPLAYDEPENDENCIES { 
     4438    my ( $this, $params ) = @_; 
     4439 
     4440    my $web = $params->{web} || $this->{webName}; 
     4441    my $topic = $params->{topic} || $this->{topicName}; 
     4442    my $header = $params->{header} || ''; 
     4443    my $footer = $params->{footer} || ''; 
     4444    my $format = $params->{format} || '   1 [[$web.$topic]]'; 
     4445    my $separator = $params->{sep} || $params->{separator} || "\n"; 
     4446    my $exclude = $params->{exclude}; 
     4447 
     4448    ($web, $topic) = $this->normalizeWebTopicName($web, $topic); 
     4449 
     4450    my $deps = $this->{cache}->getDependencies($web, $topic); 
     4451    my @lines; 
     4452    my $thisWeb; 
     4453    my $thisTopic; 
     4454    foreach my $dep (sort @$deps) { 
     4455      next if $exclude && $dep =~ /$exclude/; 
     4456      $dep =~ /^(.*)[\.\/](.*?)$/; 
     4457      $thisWeb = $1; 
     4458      $thisTopic = $2; 
     4459      my $text = $format; 
     4460      $text =~ s/\$web/$thisWeb/g; 
     4461      $text =~ s/\$topic/$thisTopic/g; 
     4462      push @lines, $text; 
     4463    } 
     4464    return '' unless @lines; 
     4465    return expandStandardEscapes($header.join($separator, @lines).$footer); 
    43144466} 
    43154467 
  • trunk/core/lib/Foswiki.spec

    r4036 r4065  
    10001000$Foswiki::cfg{UsersWebName} = 'Main'; 
    10011001 
     1002#---+ Cache settings 
     1003 
     1004#---++ Enable page caching 
     1005# This setting will switch on/off caching of html pages rendered by a view action. 
     1006# This can dramatically increase performance, i.e. if there are a lot more 
     1007# page views than changes. 
     1008# **BOOLEAN** 
     1009$Foswiki::cfg{Cache}{Enabled} = $FALSE; 
     1010 
     1011#---++ Cache namespace 
     1012# Specify the namespace used by this site in a store shared with other systems. 
     1013# Leave this empty to use the <code>DefaultUrlHost</code> as a default. 
     1014$Foswiki::cfg{Cache}{NameSpace} = ''; 
     1015 
     1016#---++ CacheManager for PageCache 
     1017# Select the default caching mechanism. Note, that individual subsystems might 
     1018# chose a different backend for their own purposes. Some recommendations: 
     1019# <ul> 
     1020#   <li>Use <code>Foswiki::Cache::FileCache</code> for long term 
     1021#     caching. Cached pages will be stored on disk.</li> 
     1022#   <li>Use <code>Foswiki::Cache::Memcached</code> for distributed caching 
     1023#     on high end sites</li> 
     1024#   <li>Use <code>Foswiki::Cache::MemoryLRU</code> for an in-memory LRU cache. 
     1025#     Note that this CacheManager will only keep pages during one call or for 
     1026#     the time of a perl persistent backend.</li> 
     1027# </ul> 
     1028# **SELECTCLASS none,Foswiki::Cache::*** 
     1029$Foswiki::cfg{CacheManager} = 'Foswiki::Cache::FileCache'; 
     1030 
     1031#---++ CacheRoot directory 
     1032# Specify the root directory for CacheManagers with a file-system based storage 
     1033# **PATH** 
     1034$Foswiki::cfg{Cache}{RootDir} = '/tmp/cache'; 
     1035 
     1036#---++ DB_File 
     1037# Specify the database file for the <code>Foswiki::Cache::DB_File</code> 
     1038# CacheManager 
     1039$Foswiki::cfg{Cache}{DBFile} = '/tmp/foswiki_db'; 
     1040 
     1041#---++ MaxSize 
     1042# Specify the maximum number of cache entries for size-aware CacheManagers like 
     1043# <code>MemoryLRU</code>. This won't have any effect on other CacheManagers. 
     1044$Foswiki::cfg{Cache}{MaxSize} = 1000; 
     1045 
     1046#---++ Cache Servers 
     1047# Specify a comma separated list of servers for distributed CacheManagers like 
     1048# <code>Memcached</code>. This setting won't have any effect on other CacheManagers. 
     1049# **STRING 30** 
     1050$Foswiki::cfg{Cache}{Servers} = '127.0.0.1:11211'; 
     1051 
    10021052#---+ Mail and Proxies 
    10031053# **BOOLEAN** 
  • trunk/core/lib/Foswiki/Meta.pm

    r3965 r4065  
    315315    my $this = shift; 
    316316    if ( defined $this->{_topic} ) { 
     317 
     318        # only checking for a topic existence already establishes a dependency 
     319        $this->addDependency(); 
     320 
    317321        return $this->{_session}->{store} 
    318322          ->topicExists( $this->{_web}, $this->{_topic} ); 
     
    345349    return $s; 
    346350} 
     351 
     352=begin TML 
     353 
     354---++ ObjectMethod addDependency() -> $this 
     355 
     356This establishes a dependency between $this and the 
     357base topic this session is currently rendering. The dependency 
     358will be asserted during Foswiki::PageCache::cachePage(). 
     359See Foswiki::PageCache::addDependency(). 
     360 
     361=cut 
     362 
     363sub addDependency { 
     364    my $cache = $_[0]->{_session}->{cache}; 
     365    return unless $cache; 
     366    return $cache->addDependency( 
     367        $_[0]->{_web}, $_[0]->{_topic}); 
     368} 
     369 
     370=begin TML 
     371 
     372---++ ObjectMethod fireDependency() -> $this 
     373 
     374Invalidates the cache bucked of the current meta object 
     375within the Foswiki::PageCache. See Foswiki::PageCache::fireDependency(). 
     376 
     377=cut 
     378 
     379sub fireDependency { 
     380    return $_[0]->{_session}->{cache}->fireDependency( 
     381        $_[0]->{_web}, $_[0]->{_topic}); 
     382} 
     383 
    347384 
    348385############# WEB METHODS ############# 
     
    607644    $this->{_preferences}->finish() if defined $this->{_preferences}; 
    608645    $this->{_preferences} = undef; 
     646 
     647    $this->addDependency(); 
    609648} 
    610649 
     
    881920 
    882921    if ($type) { 
     922        return if $type =~ /^_/; 
    883923        my @data; 
    884924        foreach my $item ( @{ $other->{$type} } ) { 
     
    14511491    finally { 
    14521492        $this->_atomicUnlock($cUID); 
     1493        $this->fireDependency(); 
    14531494    }; 
    14541495} 
     
    15441585            $this->_atomicUnlock($cUID); 
    15451586            $to->_atomicUnlock($cUID); 
     1587            $this->fireDependency(); 
     1588            $to->fireDependency(); 
    15461589        }; 
    15471590 
     
    19582001            $error = shift; 
    19592002        }; 
     2003        finally { 
     2004            $this->fireDependency(); 
     2005        }; 
    19602006 
    19612007        my $fileVersion = $this->getMaxRevNo( $opts{name} ); 
     
    20482094    my ( $this, $attachment, $test ) = @_; 
    20492095 
     2096    $this->addDependency(); 
     2097 
    20502098    $test =~ /(\w)/; 
    20512099    $test = $1; 
     
    21252173        $to->_atomicUnlock($cUID); 
    21262174        $this->_atomicUnlock($cUID); 
     2175        $this->fireDependency(); 
     2176        $to->fireDependency(); 
    21272177    }; 
    21282178 
     
    24232473 
    24242474    foreach my $type (@types) { 
     2475        next if $type eq '_session'; 
    24252476        my $data = $this->{$type}; 
    24262477        foreach my $item (@$data) { 
  • trunk/core/lib/Foswiki/Render.pm

    r3947 r4065  
    458458    # $anchorName is a *byte* string. If it contains any wide characters 
    459459    # the encoding algorithm will not work. 
     460    #ASSERT($text !~ /[^\x00-\xFF]/) if DEBUG; 
     461    $text =~ s/[^\x00-\xFF]//g; 
    460462    ASSERT( $text !~ /[^\x00-\xFF]/ ) if DEBUG; 
     463 
     464    # remove HTML tags and entities 
     465    $text =~ s/<\/?[a-zA-Z][^>]*>//gi; 
     466    $text =~ s/&#?[a-zA-Z0-9]+;//g; 
     467 
     468    # remove spaces 
     469    $text =~ s/\s+/_/g; 
    461470 
    462471    # use _ as an escape character to escape any byte outside the 
    463472    # range specified by http://www.w3.org/TR/html401/struct/links.html 
    464     $text =~ s/([^A-Za-z0-9:.])/'_'.sprintf('%02d', ord($1))/ge; 
     473    $text =~ s/([^A-Za-z0-9:._])/'_'.sprintf('%02d', ord($1))/ge; 
     474 
     475    # clean up a bit 
     476    $text =~ s/__/_/g; 
     477    $text =~ s/^_*(.*?)_*$/$1/; 
    465478 
    466479    # Ensure the anchor always starts with an [A-Za-z] 
    467     $text = 'A' . $text; 
     480    $text = 'A_'.$text unless $text =~ /^[A-Za-z]/; 
    468481 
    469482    return $text; 
     
    611624 
    612625    if ($topicExists) { 
     626        # add a dependency so that the page gets invalidated as soon as the 
     627        # topic is deleted 
     628        $this->{session}->{cache}->addDependency($web, $topic)  
     629          if $Foswiki::cfg{Cache}{Enabled}; 
     630 
    613631        return _renderExistingWikiWord( $this, $web, $topic, $linkText, 
    614632            $anchor ); 
     
    620638        #     #unshift( @topics, $singular); 
    621639        # } 
     640 
     641        # add a dependency so that the page gets invalidated as soon as the 
     642        # WikiWord comes into existance 
     643        $this->{session}->{cache}->addDependency($web, $topic) 
     644          if $Foswiki::cfg{Cache}{Enabled}; 
     645 
    622646        return _renderNonExistingWikiWord( $this, $web, $topic, $linkText ); 
    623647    } 
     
    974998    $text = $this->takeOutBlocks( $text, 'verbatim', $removed ); 
    975999    $text = $this->takeOutBlocks( $text, 'literal',  $removed ); 
     1000    $text = $this->takeOutBlocks( $text, 'dirtyarea', $removed ) 
     1001      if $Foswiki::cfg{Cache}{Enabled}; 
    9761002 
    9771003    $text = 
     
    12681294    $this->_putBackProtected( \$text, 'script', $removed, \&_filterScript ); 
    12691295    $this->putBackBlocks( \$text, $removed, 'literal', '', \&_filterLiteral ); 
    1270  
    12711296    $this->_putBackProtected( \$text, 'literal',  $removed ); 
     1297    $this->putBackBlocks( \$text, $removed, 'dirtyarea' ) 
     1298      if $Foswiki::cfg{Cache}{Enabled}; 
    12721299    $this->_putBackProtected( \$text, 'comment',  $removed ); 
    12731300    $this->_putBackProtected( \$text, 'head',     $removed ); 
  • trunk/core/lib/Foswiki/Search.pm

    r4024 r4065  
    465465        my $infoCache = $webObject->query( $query, $inputTopicSet, $options ); 
    466466        $this->sortResults( $web, $infoCache, %params ); 
     467 
     468        # add dependencies 
     469        my $cache = $session->{cache}; 
     470        if ($cache) { 
     471          foreach my $topic ( $infoCache->{list} ) { 
     472              $cache->addDependency($web, $topic); 
     473          } 
     474        } 
     475 
    467476        my ( $web_ttopics, $web_searchResult ); 
    468477        ( $web_ttopics, $web_searchResult, $tmplTail ) = 
  • trunk/core/lib/Foswiki/UI.pm

    r4036 r4065  
    298298    my $res = $session->{response}; 
    299299 
    300     $res->pushHeader( 'X-FoswikiAction' => $req->action() ); 
    301     $res->pushHeader( 'X-FoswikiURI'    => $req->uri() ); 
    302  
    303300    unless ( defined $session->{response}->status() 
    304301        && $session->{response}->status() =~ /^\s*3\d\d/ ) 
  • trunk/core/lib/Foswiki/UI/View.pm

    r3947 r4065  
    4747    my $web   = $session->{webName}; 
    4848    my $topic = $session->{topicName}; 
     49 
     50    my $fire = $query->param('firedependency') || ''; 
     51    my $cachedPage; 
     52    my $cache = $session->{cache}; 
     53    if ($cache) { 
     54      if ($fire eq 'on') { 
     55        $cache->fireDependency($web, $topic); 
     56      } else { 
     57        $cachedPage = $cache->getPage($web, $topic); 
     58      } 
     59    } 
     60    if ($cachedPage) { 
     61        print STDERR "found $web.$topic in cache\n" if $Foswiki::cfg{Cache}{Debug}; 
     62        Monitor::MARK("found page in cache"); 
     63 
     64        # render uncacheable areas 
     65        my $text = $cachedPage->{text}; 
     66        $session->{cache}->renderDirtyAreas(\$text) if $cachedPage->{isDirty}; 
     67 
     68        # compute headers 
     69        my $contentType = $cachedPage->{contentType}; 
     70        $session->generateHTTPHeaders('view', $contentType, $text, $cachedPage); 
     71        $session->{response}->print($text); 
     72 
     73        Monitor::MARK('Wrote HTML'); 
     74        if ($Foswiki::cfg{Log}{view}) { 
     75            $session->logEvent('view', $web . '.' . $topic, '(cached)' ); 
     76        } 
     77        return; 
     78    } 
     79 
     80    print STDERR "computing page for $web.$topic\n" if $Foswiki::cfg{Cache}{Debug}; 
    4981 
    5082    my $raw = $query->param('raw') || ''; 
     
    398430    $text = $topicObject->expandMacros($text); 
    399431    $text = $topicObject->renderTML($text); 
    400     $text =~ s/( ?) *<\/?(nop|noautolink)\/?>\n?/$1/gois; 
    401432 
    402433    if ($minimalist) { 
Note: See TracChangeset for help on using the changeset viewer.