@@ -15,6 +15,7 @@ WARN=5;
1515
1616BASE_REQ_SIZE = 4096 ;
1717MAX_DELAYED = 32 ;
18+ MAX_OUTSTANDING = 20 ;
1819
1920ASN_PRIVATE = - 1 ; // Do not record the ASN this cert was seen on
2021ASN_IMPLICIT = - 2 // ASN can be learned from connecting IP
@@ -88,6 +89,9 @@ function SSLObservatory() {
8889 this . submit_host = null ;
8990 this . findSubmissionTarget ( ) ;
9091
92+ // Used to track current number of pending requests to the server
93+ this . current_outstanding_requests = 0 ;
94+
9195 // Generate nonce to append to url, to catch in nsIProtocolProxyFilter
9296 // and to protect against CSRF
9397 this . csrf_nonce = "#" + Math . random ( ) . toString ( ) + Math . random ( ) . toString ( ) ;
@@ -539,6 +543,17 @@ SSLObservatory.prototype = {
539543 this . processConvergenceChain ( c ) ;
540544 if ( ! this . shouldSubmit ( c , domain ) ) return ;
541545
546+ // only try to submit now if there aren't too many outstanding requests
547+ if ( this . current_outstanding_requests > MAX_OUTSTANDING ) {
548+ this . log ( WARN , "Too many outstanding requests (" + this . current_outstanding_requests + "), not submitting" ) ;
549+ if ( ! ( c . fps [ 0 ] in this . delayed_submissions ) ) {
550+ this . log ( WARN , "Planning to retry submission..." ) ;
551+ let retry = function ( ) { this . submitChain ( certArray , fps , domain , channel , host_ip , true ) ; } ;
552+ this . delayed_submissions [ c . fps [ 0 ] ] = retry ;
553+ }
554+ return ;
555+ }
556+
542557 for ( var i = 0 ; i < c . certArray . length ; i ++ ) {
543558 var len = new Object ( ) ;
544559 var derData = c . certArray [ i ] . getRawDER ( len ) ;
@@ -558,7 +573,7 @@ SSLObservatory.prototype = {
558573 }
559574 reqParams . push ( "certlist=" + this . compatJSON . encode ( base64Certs ) ) ;
560575
561- if ( resubmitting ) reqParams . push ( "client_asn=" + ASN_UNKNOWABLE )
576+ if ( resubmitting ) reqParams . push ( "client_asn=" + ASN_UNKNOWABLE ) ;
562577 else reqParams . push ( "client_asn=" + this . client_asn ) ;
563578
564579 if ( this . myGetBoolPref ( "priv_dns" ) ) reqParams . push ( "private_opt_in=1" )
@@ -580,14 +595,18 @@ SSLObservatory.prototype = {
580595
581596 var that = this ; // We have neither SSLObservatory nor this in scope in the lambda
582597
583-
584598 var HTTPSEverywhere = CC [ "@eff.org/https-everywhere;1" ]
585599 . getService ( Components . interfaces . nsISupports )
586600 . wrappedJSObject ;
587601 var win = channel ? HTTPSEverywhere . getWindowForChannel ( channel ) : null ;
588602 var req = this . buildRequest ( params ) ;
603+
589604 req . onreadystatechange = function ( evt ) {
590605 if ( req . readyState == 4 ) {
606+ // pop off one outstanding request
607+ that . current_outstanding_requests -= 1 ;
608+ this . log ( DBUG , "Popping one off of outstanding requests, current num is: " + that . current_outstanding_requests ) ;
609+
591610 if ( req . status == 200 ) {
592611 that . log ( INFO , "Successful cert submission" ) ;
593612 if ( ! that . prefs . getBoolPref ( "extensions.https_everywhere._observatory.cache_submitted" ) )
@@ -635,6 +654,10 @@ SSLObservatory.prototype = {
635654
636655 // Cache this here to prevent multiple submissions for all the content elements.
637656 that . already_submitted [ c . fps [ 0 ] ] = true ;
657+
658+ // add one to current outstanding request number
659+ that . current_outstanding_requests += 1 ;
660+ this . log ( DBUG , "Adding outstanding request, current num is: " + that . current_outstanding_requests ) ;
638661 req . send ( params ) ;
639662 } ,
640663
0 commit comments