Show
Ignore:
Timestamp:
04/14/08 07:35:20 (20 months ago)
Author:
fumiakiy
Message:

Implemented alarm based search throttling. The throttling methods can be added from plugins. BugId:69031

Files:
1 modified

Legend:

Unmodified
Added
Removed
  • branches/release-34/lib/MT/App/Search.pm

    r1855 r1882  
    3333    #} 
    3434    $app->_register_core_callbacks({ 
    35         'search_post_execute' => \&log_search, 
    36         'search_post_render'  => \&cache_out, 
     35        'MT::App::Search::search_post_execute' => \&log_search, 
     36        'MT::App::Search::search_post_render'  => \&cache_out, 
     37        'MT::App::Search::prepare_throttle'    => \&_default_throttle, 
     38        'MT::App::Search::take_down'           => \&_default_takedown, 
    3739    }); 
    3840    $app; 
     
    8890        delete $app->{$_} if exists $app->{$_} 
    8991    } 
     92    delete $app->{__have_throttle} if exists $app->{__have_throttle}; 
    9093 
    9194    my %no_override; 
     
    115118    my $processed = 0; 
    116119    my $list      = {}; 
    117     if ( MT->run_callbacks( 'search_blog_list', $app, $list, \$processed ) ) { 
     120    if ( $app->run_callbacks( 'search_blog_list', $app, $list, \$processed ) ) { 
    118121        if ( $processed ) { 
    119122            $app->{searchparam}{IncludeBlogs} = $list; 
     
    243246sub process { 
    244247    my $app = shift; 
     248 
     249    my @messages; 
     250    return $app->throttle_response(\@messages) unless $app->throttle_control(\@messages); 
    245251 
    246252    my ( $count, $out ) = $app->check_cache(); 
     
    773779} 
    774780 
     781# throttling related methods 
     782sub throttle_control { 
     783    my $app = shift; 
     784    my ( $messages ) = @_; 
     785    my $result; 
     786    $app->run_callbacks( 'prepare_throttle', $app, \$result, $messages ); 
     787    $result; 
     788} 
     789 
     790sub throttle_response { 
     791    my $app = shift; 
     792    my ( $messages ) = @_; 
     793    my $tmpl = $app->param('Template') || ''; 
     794    if ($tmpl eq 'feed') { 
     795        $app->response_code(503); 
     796        $app->set_header('Retry-After' => $app->config('ThrottleSeconds')); 
     797        $app->send_http_header("text/plain"); 
     798        $app->{no_print_body} = 1; 
     799    } 
     800    my $msg = $messages && @$messages 
     801      ? join '; ', @$messages 
     802      : $app->translate('Throttled'); 
     803    return $app->error($msg); 
     804} 
     805 
     806sub _default_throttle { 
     807    my ( $cb, $app, $result, $messages ) = @_; 
     808 
     809    # Don't bother if a callback proiritized higher 
     810    # set up its throttle already 
     811    return $$result if defined $$result; 
     812 
     813    ## Get login information if user is logged in (via cookie). 
     814    ## If no login cookie, this fails silently, and that's fine. 
     815    ($app->{user}) = $app->login; 
     816 
     817    ## Don't throttle MT registered users 
     818    if ( $app->{user} && $app->{user}->type == MT::Author::AUTHOR() ) { 
     819        $$result = 1; 
     820        return 1; 
     821    } 
     822 
     823    my $ip = $app->remote_ip; 
     824    my $whitelist = $app->config->SearchThrottleIPWhitelist; 
     825    if ($whitelist) { 
     826        # check for $ip in $whitelist 
     827        my @list = split /(\s*[,;]\s*|\s+)/, $whitelist; 
     828        foreach (@list) { 
     829            next unless $_ =~ m/^\d{1,3}(\.\d{0,3}){0,3}$/; 
     830            if (($ip eq $_) || ($ip =~ m/^\Q$_\E/)) { 
     831                $$result = 1; 
     832                return 1; 
     833            } 
     834        } 
     835    } 
     836 
     837    unless ( $^O eq 'Win32' ) { 
     838        # Use SIGALRM to stop processing in 5 seconds for each request 
     839        $SIG{ALRM} = sub { $app->errtrans('Throttled'); die; }; 
     840        $app->{__have_throttle} = 1; 
     841        alarm($app->config->SearchThrottleSeconds); 
     842        $$result = 1; 
     843    } 
     844    1; 
     845} 
     846 
     847sub _default_takedown { 
     848    my ( $cb, $app ) = @_; 
     849    alarm(0) if $app->{__have_throttle}; 
     850    1; 
     851} 
     852 
    7758531; 
    776854__END__ 
     
    820898the app must not overwrite the blog list created by the plugin. 
    821899 
     900=item prepare_throttle 
     901 
     902    callback($cb, $app, \$result, \@messages); 
     903 
     904Called right before the beginning of the search processing. 
     905Each callback should see if certain condition is met, and 
     906set 0 to $$result if the request should be throttled. 
     907 
     908There can be more than one throttling method set up. 
     909Callbacks are called in order of priority set up when add_callback 
     910was called.  Each callback should start its own code by something like 
     911below, to prevent itself overwriting throttle set up in the callback 
     912whose priority is higher than itself. 
     913 
     914    return $$result if defined $$result; 
     915 
    822916=head1 AUTHOR & COPYRIGHT 
    823917