@@ -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 [ ^ > ] * \? > / , "" ) ;
@@ -414,30 +420,29 @@ const HTTPSRules = {
414420 this . rulesetsByName = { } ;
415421 var t1 = new Date ( ) . getTime ( ) ;
416422 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- }
427-
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 [ "*" ] : [ ] ;
432423
433- this . rulesets . sort (
434- function ( r1 , r2 ) {
435- if ( r1 . name . toLowerCase ( ) < r2 . name . toLowerCase ( ) ) return - 1 ;
436- else return 1 ;
437- }
438- ) ;
424+ // Initialize database connection.
425+ var dbFile = FileUtils . getFile ( "ProfD" ,
426+ [ "extensions" , "https-everywhere@eff.org" , "defaults" , "rulesets.sqlite" ] ) ;
427+ var rulesetDBConn = Services . storage . openDatabase ( dbFile ) ;
428+ this . queryForRuleset = rulesetDBConn . createStatement (
429+ "select contents from rulesets where id = :id" ) ;
430+
431+ // Preload the list of which targets are available in the DB.
432+ // This is a little slow (287 ms on a Core2 Duo @ 2.2GHz with SSD),
433+ // but is faster than loading all of the rulesets. If this becomes a
434+ // bottleneck, change it to load in a background webworker, or load
435+ // a smaller bloom filter instead.
436+ this . targetsAvailable = { } ;
437+ var targetsQuery = rulesetDBConn . createStatement ( "select host, ruleset_id from targets" ) ;
438+ this . log ( DBUG , "Adding targets..." ) ;
439+ while ( targetsQuery . executeStep ( ) ) {
440+ var host = targetsQuery . row . host ;
441+ this . targetsAvailable [ host ] = targetsQuery . row . ruleset_id ;
442+ }
443+ this . log ( DBUG , "Done adding targets." ) ;
439444 } catch ( e ) {
440- this . log ( WARN , "Rules Failed: " + e ) ;
445+ this . log ( DBUG , "Rules Failed: " + e ) ;
441446 }
442447 var t2 = new Date ( ) . getTime ( ) ;
443448 this . log ( NOTE , "Loading rulesets took " + ( t2 - t1 ) / 1000.0 + " seconds" ) ;
@@ -498,6 +503,8 @@ const HTTPSRules = {
498503 }
499504 } ,
500505
506+ httpMatch : / ^ h t t p / i,
507+
501508 rewrittenURI : function ( alist , input_uri ) {
502509 // This function oversees the task of working out if a uri should be
503510 // rewritten, what it should be rewritten to, and recordkeeping of which
@@ -518,7 +525,7 @@ const HTTPSRules = {
518525 try {
519526 var rs = this . potentiallyApplicableRulesets ( uri . host ) ;
520527 } catch ( e ) {
521- this . log ( WARN , 'Could not check applicable rules for ' + uri . spec ) ;
528+ this . log ( WARN , 'Could not check applicable rules for ' + uri . spec + '\n' + e ) ;
522529 return null ;
523530 }
524531
@@ -602,17 +609,54 @@ const HTTPSRules = {
602609 intoList . push ( fromList [ i ] ) ;
603610 } ,
604611
612+ // Try to find a ruleset in the SQLite database for a given target (e.g.
613+ // '*.openssl.org')
614+ // NOTE: This call runs synchronously, which can lock up the browser UI. Is
615+ // there any way to fix that, given that we need to run blocking in the request
616+ // flow? Perhaps we can preload all targets from the DB into memory at startup
617+ // so we only hit the DB when we know there is something to be had.
618+ queryTarget : function ( target ) {
619+ this . log ( DBUG , "Querying DB for " + target ) ;
620+ var output = [ ] ;
621+
622+ this . queryForRuleset . params . id = this . targetsAvailable [ target ] ;
623+
624+ try {
625+ while ( this . queryForRuleset . executeStep ( ) )
626+ output . push ( this . queryForRuleset . row . contents ) ;
627+ } finally {
628+ this . queryForRuleset . reset ( ) ;
629+ }
630+ return output ;
631+ } ,
632+
605633 potentiallyApplicableRulesets : function ( host ) {
606634 // Return a list of rulesets that declare targets matching this host
607635 var i , tmp , t ;
608- var results = this . global_rulesets . slice ( 0 ) ; // copy global_rulesets
609- try {
610- if ( this . targets [ host ] )
611- results = results . concat ( this . targets [ host ] ) ;
612- } catch ( e ) {
613- this . log ( DBUG , "Couldn't check for ApplicableRulesets: " + e ) ;
614- return [ ] ;
615- }
636+ var results = [ ] ;
637+
638+ var attempt = function ( target ) {
639+ // First try the in-memory rulesets
640+ if ( this . targets [ target ] &&
641+ this . targets [ target ] . length > 0 ) {
642+ this . setInsert ( results , this . targets [ target ] ) ;
643+ } else if ( this . targetsAvailable [ target ] ) {
644+ // If not found there, check the DB and load the ruleset as appropriate
645+ var rulesets = this . queryTarget ( target ) ;
646+ if ( rulesets . length > 0 ) {
647+ for ( var i = 0 ; i < rulesets . length ; i ++ ) {
648+ var ruleset = rulesets [ i ] ;
649+ this . log ( INFO , "Found ruleset in DB for " + host + ": " + ruleset ) ;
650+ RuleWriter . readFromString ( ruleset , this ) ;
651+ this . setInsert ( results , this . targets [ target ] ) ;
652+ }
653+ } else {
654+ this . nonTargets [ target ] = 1 ;
655+ }
656+ }
657+ } . bind ( this ) ;
658+
659+ attempt ( host ) ;
616660
617661 // replace each portion of the domain with a * in turn
618662 var segmented = host . split ( "." ) ;
@@ -621,13 +665,13 @@ const HTTPSRules = {
621665 segmented [ i ] = "*" ;
622666 t = segmented . join ( "." ) ;
623667 segmented [ i ] = tmp ;
624- this . setInsert ( results , this . targets [ t ] ) ;
668+ attempt ( t ) ;
625669 }
626670 // now eat away from the left, with *, so that for x.y.z.google.com we
627671 // check *.z.google.com and *.google.com (we did *.y.z.google.com above)
628- for ( i = 1 ; i <= segmented . length - 2 ; ++ i ) {
672+ for ( i = 2 ; i <= segmented . length - 2 ; ++ i ) {
629673 t = "*." + segmented . slice ( i , segmented . length ) . join ( "." ) ;
630- this . setInsert ( results , this . targets [ t ] ) ;
674+ attempt ( t ) ;
631675 }
632676 this . log ( DBUG , "Potentially applicable rules for " + host + ":" ) ;
633677 for ( i = 0 ; i < results . length ; ++ i )
0 commit comments