@@ -460,21 +460,41 @@ public override int IsMatch(Uri source, int lastPosition)
460460 }
461461
462462 /// <summary>
463- /// Gets an array of all domains that this URL filter rule applies to. In the event that this
463+ /// Gets a hashset of all referers that this URL filter rule applies to. In the event that
464+ /// this array is empty, the referer field on requests will not be checked.
465+ /// </summary>
466+ public HashSet < string > ApplicableReferers
467+ {
468+ get ;
469+ private set ;
470+ }
471+
472+ /// <summary>
473+ /// Gets a hashset of all referers that this URL filter rule applies to. In the event that
474+ /// this array is empty, the referer field on requests will not be checked.
475+ /// </summary>
476+ public HashSet < string > ExceptReferers
477+ {
478+ get ;
479+ private set ;
480+ }
481+
482+ /// <summary>
483+ /// Gets a hashset of all domains that this URL filter rule applies to. In the event that this
464484 /// array is empty, the rule applies globally, to all domains.
465485 /// </summary>
466- public List < string > ApplicableDomains
486+ public HashSet < string > ApplicableDomains
467487 {
468488 get ;
469489 private set ;
470490 }
471491
472492 /// <summary>
473- /// Gets an array of all domains that this URL filter should not be applied to. In the event
493+ /// Gets a hashset of all domains that this URL filter should not be applied to. In the event
474494 /// that this array is empty, the rule applies either globally, or exclusively to the list of
475495 /// applicable domains, if that property is not empty.
476496 /// </summary>
477- public List < string > ExceptionDomains
497+ public HashSet < string > ExceptionDomains
478498 {
479499 get ;
480500 private set ;
@@ -538,13 +558,16 @@ public List<UrlFilteringRuleFragment> Parts
538558 /// <param name="categoryId">
539559 /// The category ID of the category this filter belongs to.
540560 /// </param>
541- internal UrlFilter ( string originalRule , List < UrlFilteringRuleFragment > parts , UrlFilterOptions options , List < string > applicableDomains , List < string > exceptionDomains , bool isException , short categoryId ) : base ( originalRule , isException , categoryId )
561+ internal UrlFilter ( string originalRule , List < UrlFilteringRuleFragment > parts , UrlFilterOptions options , HashSet < string > applicableDomains , HashSet < string > exceptionDomains , HashSet < string > applicableReferers , HashSet < string > exceptionReferers , bool isException , short categoryId ) : base ( originalRule , isException , categoryId )
542562 {
543563 Parts = parts ;
544564 Options = options ;
545565
546566 ApplicableDomains = applicableDomains ;
547567 ExceptionDomains = exceptionDomains ;
568+
569+ ApplicableReferers = applicableReferers ;
570+ ExceptReferers = exceptionReferers ;
548571 }
549572
550573 /// <summary>
@@ -564,23 +587,23 @@ public bool IsMatch(Uri uri, NameValueCollection rawHeaders)
564587 {
565588 // Make sure that the headers match up with our options.
566589 if ( this . Options != UrlFilterOptions . None )
567- {
590+ {
568591 string headerVal = null ;
569592 long xmlHttpRequestBits = ( ( OptionsLong & ( long ) UrlFilterOptions . ExceptXmlHttpRequest ) | ( OptionsLong & ( long ) UrlFilterOptions . XmlHttpRequest ) ) ;
570593 if ( ( headerVal = rawHeaders . Get ( "X-Requested-With" ) ) != null )
571594 {
572595 if ( headerVal . Equals ( "XMLHttpRequest" , StringComparison . OrdinalIgnoreCase ) )
573- {
596+ {
574597 xmlHttpRequestBits &= ~ ( long ) UrlFilterOptions . XmlHttpRequest ;
575598 }
576599 else
577- {
600+ {
578601 xmlHttpRequestBits &= ~ ( long ) UrlFilterOptions . ExceptXmlHttpRequest ;
579602 }
580603 }
581604
582605 if ( xmlHttpRequestBits != 0 )
583- {
606+ {
584607 // XML HttpRequest bits were not cleared, meaning that one of those options was not satisifed.
585608 return false ;
586609 }
@@ -596,6 +619,21 @@ public bool IsMatch(Uri uri, NameValueCollection rawHeaders)
596619 {
597620 thirdPartyBits &= ~ ( long ) UrlFilterOptions . ThirdParty ;
598621 }
622+
623+ // While we have the referer field, let's go ahead and check if we have referer
624+ // options and if we do or don't have a match.
625+ //
626+ // This is a shortcut. We unfortunately need to also execute this code also when
627+ // there are no options.
628+ if ( ApplicableReferers . Count > 0 && ! ApplicableReferers . Contains ( headerVal ) )
629+ {
630+ return false ;
631+ }
632+
633+ if ( ExceptReferers . Count > 0 && ExceptReferers . Contains ( headerVal ) )
634+ {
635+ return false ;
636+ }
599637 }
600638 else
601639 {
@@ -617,7 +655,7 @@ public bool IsMatch(Uri uri, NameValueCollection rawHeaders)
617655 if ( ( headerVal = rawHeaders . Get ( "Content-Type" ) ) != null )
618656 {
619657 if ( headerVal . IndexOfQuick ( "script" ) != - 1 )
620- {
658+ {
621659 contentTypeBits &= ~ ( long ) UrlFilterOptions . Script ;
622660 }
623661 else
@@ -650,7 +688,31 @@ public bool IsMatch(Uri uri, NameValueCollection rawHeaders)
650688 return false ;
651689 }
652690 }
653-
691+ else
692+ {
693+ if ( ApplicableReferers . Count > 0 || ExceptReferers . Count > 0 )
694+ {
695+ string headerVal = null ;
696+ if ( ( headerVal = rawHeaders . Get ( "Referer" ) ) != null )
697+ {
698+ // While we have the referer field, let's go ahead and check if we have referer
699+ // options and if we do or don't have a match.
700+ //
701+ // This is a shortcut. We unfortunately need to also execute this code also when
702+ // there are no options.
703+ if ( ApplicableReferers . Count > 0 && ! ApplicableReferers . Contains ( headerVal ) )
704+ {
705+ return false ;
706+ }
707+
708+ if ( ExceptReferers . Count > 0 && ExceptReferers . Contains ( headerVal ) )
709+ {
710+ return false ;
711+ }
712+ }
713+ }
714+ }
715+
654716 int matchIndex = 0 ;
655717 foreach ( var part in Parts )
656718 {
0 commit comments