@@ -280,6 +280,12 @@ const RuleWriter = {
280280
281281 sstream . close ( ) ;
282282 fstream . close ( ) ;
283+ return this . readFromString ( data , rule_store , file ) ;
284+ } ,
285+
286+ readFromString : function ( data , rule_store , file ) {
287+ if ( typeof file === 'undefined' ) file = { path : 'fromString' } ;
288+
283289 // XXX: With DOMParser, we probably do not need to throw away the XML
284290 // declaration anymore nowadays.
285291 data = data . replace ( / < \? x m l [ ^ > ] * \? > / , "" ) ;
@@ -410,32 +416,19 @@ const HTTPSRules = {
410416 this . rulesets = [ ] ;
411417 this . targets = { } ; // dict mapping target host patterns -> lists of
412418 // applicable rules
419+ // dict listing target host patterns that don't exist in the DB
420+ // (aka negative cache)
421+ // TODO: Make this an LRU cache; clear it on history clear
422+ this . nonTargets = { } ;
413423 this . rulesetsByID = { } ;
414424 this . rulesetsByName = { } ;
415425 var t1 = new Date ( ) . getTime ( ) ;
416426 this . checkMixedContentHandling ( ) ;
417- var rulefiles = RuleWriter . enumerate ( RuleWriter . getCustomRuleDir ( ) ) ;
418- this . scanRulefiles ( rulefiles ) ;
419- rulefiles = RuleWriter . enumerate ( RuleWriter . getRuleDir ( ) ) ;
420- this . scanRulefiles ( rulefiles ) ;
421- var t , i ;
422- for ( t in this . targets ) {
423- for ( i = 0 ; i < this . targets [ t ] . length ; i ++ ) {
424- this . log ( INFO , t + " -> " + this . targets [ t ] [ i ] . name ) ;
425- }
426- }
427427
428- // for any rulesets with <target host="*">
429- // every URI needs to be checked against these rulesets
430- // (though currently we don't ship any)
431- this . global_rulesets = this . targets [ "*" ] ? this . targets [ "*" ] : [ ] ;
432-
433- this . rulesets . sort (
434- function ( r1 , r2 ) {
435- if ( r1 . name . toLowerCase ( ) < r2 . name . toLowerCase ( ) ) return - 1 ;
436- else return 1 ;
437- }
438- ) ;
428+ // Initialize database connection.
429+ var dbFile = FileUtils . getFile ( "ProfD" , [ "extensions" , "https-everywhere@eff.org" , "defaults" , "rulesets.sqlite" ] ) ;
430+ var mDBConn = Services . storage . openDatabase ( dbFile ) ;
431+ this . queryForTarget = mDBConn . createStatement ( "select id, contents from targets, rulesets where targets.ruleset_id = rulesets.id and host = :target;" ) ;
439432 } catch ( e ) {
440433 this . log ( WARN , "Rules Failed: " + e ) ;
441434 }
@@ -491,6 +484,8 @@ const HTTPSRules = {
491484 }
492485 } ,
493486
487+ httpMatch : / ^ h t t p / i,
488+
494489 rewrittenURI : function ( alist , input_uri ) {
495490 // This function oversees the task of working out if a uri should be
496491 // rewritten, what it should be rewritten to, and recordkeeping of which
@@ -511,7 +506,7 @@ const HTTPSRules = {
511506 try {
512507 var rs = this . potentiallyApplicableRulesets ( uri . host ) ;
513508 } catch ( e ) {
514- this . log ( WARN , 'Could not check applicable rules for ' + uri . spec ) ;
509+ this . log ( WARN , 'Could not check applicable rules for ' + uri . spec + '\n' + e ) ;
515510 return null ;
516511 }
517512
@@ -595,31 +590,66 @@ const HTTPSRules = {
595590 intoList . push ( fromList [ i ] ) ;
596591 } ,
597592
593+ // Try to find a ruleset in the SQLite database for a given target (e.g.
594+ // '*.openssl.org')
595+ // NOTE: This call runs synchronously, which can lock up the browser UI. Is
596+ // there any way to fix that, given that we need to run blocking in the request
597+ // flow? Perhaps we can preload all targets from the DB into memory at startup
598+ // so we only hit the DB when we know there is something to be had.
599+ queryTarget : function ( target ) {
600+ this . log ( WARN , "Querying DB for " + target ) ;
601+ var statement = this . queryForTarget . clone ( ) ;
602+ statement . params . target = target ;
603+
604+ try {
605+ if ( statement . executeStep ( ) )
606+ return statement . row . contents ;
607+ } finally {
608+ statement . reset ( ) ;
609+ }
610+ } ,
611+
598612 potentiallyApplicableRulesets : function ( host ) {
599613 // Return a list of rulesets that declare targets matching this host
600614 var i , tmp , t ;
601- var results = this . global_rulesets . slice ( 0 ) ; // copy global_rulesets
602- try {
603- if ( this . targets [ host ] )
604- results = results . concat ( this . targets [ host ] ) ;
605- } catch ( e ) {
606- this . log ( DBUG , "Couldn't check for ApplicableRulesets: " + e ) ;
607- return [ ] ;
608- }
615+ var results = [ ] ;
616+
617+ var attempt = function ( target ) {
618+ // First check for this target in our in-memory negative cache
619+ if ( this . nonTargets [ target ] ) {
620+ return ;
621+ } else if ( this . targets [ target ] && // Then our positive cache
622+ this . targets [ target ] . length > 0 ) {
623+ this . setInsert ( results , this . targets [ target ] ) ;
624+ } else {
625+ // If not found there, check the DB and load the ruleset as appropriate
626+ // TODO: Add negative caching so we don't repeatedly query the DB for
627+ // things that aren't there.
628+ var ruleset = this . queryTarget ( target ) ;
629+ if ( ruleset != null ) {
630+ this . log ( INFO , "Found ruleset in DB for " + host + ": " + ruleset ) ;
631+ RuleWriter . readFromString ( ruleset , this ) ;
632+ this . setInsert ( results , this . targets [ target ] ) ;
633+ } else {
634+ this . nonTargets [ target ] = 1 ;
635+ }
636+ }
637+ } . bind ( this ) ;
638+
609639 // replace each portion of the domain with a * in turn
610640 var segmented = host . split ( "." ) ;
611641 for ( i = 0 ; i < segmented . length ; ++ i ) {
612642 tmp = segmented [ i ] ;
613643 segmented [ i ] = "*" ;
614644 t = segmented . join ( "." ) ;
615645 segmented [ i ] = tmp ;
616- this . setInsert ( results , this . targets [ t ] ) ;
646+ attempt ( t ) ;
617647 }
618648 // now eat away from the left, with *, so that for x.y.z.google.com we
619649 // check *.z.google.com and *.google.com (we did *.y.z.google.com above)
620650 for ( i = 1 ; i <= segmented . length - 2 ; ++ i ) {
621651 t = "*." + segmented . slice ( i , segmented . length ) . join ( "." ) ;
622- this . setInsert ( results , this . targets [ t ] ) ;
652+ attempt ( t ) ;
623653 }
624654 this . log ( DBUG , "Potentially applicable rules for " + host + ":" ) ;
625655 for ( i = 0 ; i < results . length ; ++ i )
0 commit comments