Bug 1976779 - rsclientcerts: make each backend responsible for rate-limiting calls to find_objects r=jschanck
Before this patch, `rsclientcerts::manager` would rate-limit calls to
`find_objects` to once every 3 seconds because the underlying operation can be
time-consuming (in particular, on macOS and Windows, if there are many
certificates/keys available). On Android, keys aren't available until the user
selects one, which means that if a call to `find_objects` happened before the
selection prompt was shown (which is what happens) and the user chose one in
less than 3 seconds, the backend wouldn't search again, thus making it seem like
no keys were available, which would cause Firefox to not send a client
certificate. This patch makes each backend implementation responsible for this
rate-limiting, because only they know if it's appropriate to do so (in particular,
on Android, `find_objects` doesn't have the same performance concern as
on macOS and Windows because rather than searching for certificates and
keys, it asks `ClientAuthCertificateManager` for the cached list of certificates
and keys that have already been approved for use by the user).
Differential Revision: https://phabricator.services.mozilla.com/D257065
<!DOCTYPE><html><head><title>user-select selection tests</title><scriptsrc="/tests/SimpleTest/SimpleTest.js"></script><scriptsrc="/tests/SimpleTest/EventUtils.js"></script><linkrel="stylesheet"type="text/css"href="/tests/SimpleTest/test.css"/><styletype="text/css">@font-face{font-family:Ahem;src:url("Ahem.ttf");}body{font-family:Ahem;font-size:20px;}s,.non-selectable{user-select:none;}n{display:none;}a{position:absolute;bottom:0;right:0;}.text{user-select:text;}</style></head><body><divid="test1">aaaaaaa<s>bbbbbbbb</s>ccccccc</div><divid="test2"><s>aaaaaaa</s>bbbbbbbbccccccc</div><divid="test3">aaaaaaabbbbbbbb<s>ccccccc</s></div><divid="test4">aaaaaaa<x><s>bbbbbbbb</s></x>ccccccc</div><divid="test5"><x><s>aaaaaaa</s></x>bbbbbbbbccccccc</div><divid="test6">aaaaaaabbbbbbbb<x><s>ccccccc</s></x></div><divid="test7">aaaaaaa<x><s><n>bbbb</n>bbbb</s></x>ccccccc</div><divid="test8"><x><s>aa<n>aaa</n>aa</s></x>bbbbbbbbccccccc</div><divid="test9">aaaaaaabbbbbbbb<x><s>cc<n>ccccc</n></s></x></div><divid="testA">aaaaaaa<n>bbb<s>bbbbb</s></n>ccccccc</div><divid="testB"><n><s>aaaa</s>aaa</n>bbbbbbbbccccccc</div><divid="testC">aaaaaaabbbbbbbb<n>cc<s>c</s>cccc</n></div><divid="testE">aaa<sid="testEc1">aaaa<aclass="text">bbbb</a>dd<a>cccc</a>ddddddd</s>eeee</div><divid="testI">aaa<spancontenteditable="true"spellcheck="false">bbb</span><s>ccc</s>ddd</div><divid="testF">aaaa<divclass="non-selectable">x</div><divclass="non-selectable">x</div><divclass="non-selectable">x</div>bbbb</div><divid="testG"style="white-space:pre">aaaa<divclass="non-selectable">x</div><divclass="non-selectable">x</div><divclass="non-selectable">x</div>bbbb</div><divid="testH"style="white-space:pre">aaaa<divclass="non-selectable">x</div><input>bbbbbbb</div><iframeid="testD"srcdoc="<body>aaaa<span style='user-select:none'>bbbb</span>cccc"></iframe><preid="test"><scriptclass="testbody"type="text/javascript">functiontest(){functionclear(w){varsel=(w?w:window).getSelection();sel.removeAllRanges();}functiondoneTest(e){// We hide the elements we're done with so that later tests// are inside the rather narrow iframe mochitest gives us.// It matters for synthesizeMouse event tests.e.style.display='none';e.offsetHeight;}functiondragSelect(e,x1,x2,x3){dir=x2>x1?1:-1;synthesizeMouse(e,x1,5,{type:"mousedown"});synthesizeMouse(e,x1+dir,5,{type:"mousemove"});if(x3)synthesizeMouse(e,x3,5,{type:"mousemove"});synthesizeMouse(e,x2-dir,5,{type:"mousemove"});synthesizeMouse(e,x2,5,{type:"mouseup"});}functionshiftClick(e,x){synthesizeMouse(e,x,5,{type:"mousedown",shiftKey:true});synthesizeMouse(e,x,5,{type:"mouseup",shiftKey:true});}functioninit(arr,e){clear();varsel=window.getSelection();for(i=0;i<arr.length;++i){vardata=arr[i];varr=newRange()r.setStart(node(e,data[0]),data[1]);r.setEnd(node(e,data[2]),data[3]);sel.addRange(r);}}functionNL(s){returns.replace(/(\r\n|\n\r|\r)/g,'\n');}functioncheckText(text,e){varsel=window.getSelection();is(NL(sel.toString()),text,e.id+": selected text")}functioncheckRangeText(text,index){varr=window.getSelection().getRangeAt(index);is(NL(r.toString()),text,e.id+": range["+index+"].toString()")}functionnode(e,arg){if(typeofarg=="number")returnarg==-1?e:e.childNodes[arg];returnarg;}functioncheckRangeCount(n,e){varsel=window.getSelection();is(sel.rangeCount,n,e.id+": Selection range count");}functioncheckRange(i,expected,e){varsel=window.getSelection();varr=sel.getRangeAt(i);is(r.startContainer,node(e,expected[0]),e.id+": range["+i+"].startContainer");is(r.startOffset,expected[1],e.id+": range["+i+"].startOffset");is(r.endContainer,node(e,expected[2]),e.id+": range["+i+"].endContainer");is(r.endOffset,expected[3],e.id+": range["+i+"].endOffset");}functioncheckRanges(arr,e){checkRangeCount(arr.length,e);for(i=0;i<arr.length;++i){varexpected=arr[i];checkRange(i,expected,e);}}// ======================================================// ================== dragSelect tests ==================// ======================================================vare=document.getElementById('test1');dragSelect(e,20,340);checkText('aaaaaacc',e);checkRanges([[0,1,-1,1],[2,0,2,2]],e);clear();dragSelect(e,20,260,120);checkText('aaaaa',e);checkRanges([[0,1,0,6]],e);doneTest(e);clear();e=document.getElementById('test2');dragSelect(e,20,340);checkText('',e);checkRanges([],e);clear();dragSelect(e,340,20,141);checkText('bbbbbbbbcc',e);checkRanges([[1,0,1,10]],e);// #test2 is used again belowclear();e=document.getElementById('test3');dragSelect(e,20,340,295);checkText('aaaaaabbbbbbbb',e);checkRanges([[0,1,0,15]],e);// #test3 is used again belowclear();e=document.getElementById('test4');dragSelect(e,20,340);checkText('aaaaaacc',e);checkRanges([[0,1,1,0],[2,0,2,2]],e);doneTest(e);clear();e=document.getElementById('test5');dragSelect(e,340,20,141);checkText('bbbbbbbbcc',e);checkRanges([[1,0,1,10]],e);doneTest(e);clear();e=document.getElementById('test6');dragSelect(e,20,340,295);checkText('aaaaaabbbbbbbb',e);checkRanges([[0,1,0,15]],e);doneTest(e);clear();e=document.getElementById('test7');dragSelect(e,20,340);checkText('aaaaaacccccc',e);checkRanges([[0,1,1,0],[2,0,2,6]],e);doneTest(e);clear();e=document.getElementById('test8');dragSelect(e,340,20,140);checkText('bbbbbccccc',e);checkRanges([[1,3,1,13]],e);doneTest(e);clear();e=document.getElementById('test9');dragSelect(e,20,340,295);checkText('aaaaaabbbbbbbb',e);checkRanges([[0,1,0,15]],e);doneTest(e);clear();e=document.getElementById('testA');dragSelect(e,20,340);checkText('aaaaaaccccccc',e);checkRanges([[0,1,2,7]],e);checkRangeText('aaaaaabbbbbbbbccccccc',0);doneTest(e);clear();e=document.getElementById('testB');dragSelect(e,340,20,140);checkText('bbbbbbbccccccc',e);checkRanges([[1,1,1,15]],e);doneTest(e);clear();e=document.getElementById('testE');dragSelect(e,20,360,295);checkText('aa\nbbbb\nee',e);checkRangeCount(3,e);checkRange(0,[0,1,-1,1],e);checkRange(1,[1,0,-1,2],e.children[0]);checkRange(2,[2,0,2,2],e);doneTest(e);clear();e=document.getElementById('testI');dragSelect(e,200,80);checkText('bbd',e);checkRangeCount(2,e);doneTest(e);// ======================================================// ================== shift+click tests =================// ======================================================// test extending a selection that starts in a -moz-user-select:none nodeclear();e=document.getElementById('test2');init([[0,0,0,1]],e);checkRangeText('aaaaaaa',0);checkText('',e);shiftClick(e,340);checkRangeText('bbbbbbbbcc',0);checkText('bbbbbbbbcc',e);checkRanges([[-1,1,1,10]],e);doneTest(e);// test extending a selection that end in a -moz-user-select:none nodeclear();e=document.getElementById('test3');init([[1,0,1,1]],e);checkRangeText('ccccccc',0);checkText('',e);shiftClick(e,20);checkRangeText('aaaaaabbbbbbbb',0);checkText('aaaaaabbbbbbbb',e);checkRanges([[0,1,-1,1]],e);doneTest(e);clear();e=document.getElementById('testF');synthesizeMouse(e,1,1,{});synthesizeMouse(e,400,100,{shiftKey:true});checkText("aaaa bbbb",e);checkRanges([[0,0,-1,1],[6,0,6,5]],e);doneTest(e);clear();e=document.getElementById('testG');synthesizeMouse(e,1,1,{});synthesizeMouse(e,400,180,{shiftKey:true});checkText("aaaa\n\n\n\nbbbb",e);checkRanges([[0,0,-1,1],[2,0,-1,3],[4,0,-1,5],[6,0,6,5]],e);doneTest(e);clear();e=document.getElementById('testH');synthesizeMouse(e,1,1,{});synthesizeMouse(e,30,90,{shiftKey:true});synthesizeMouse(e,50,90,{shiftKey:true});synthesizeMouse(e,70,90,{shiftKey:true});checkText("aaaa\n\nbbb",e);checkRanges([[0,0,-1,1],[-1,2,3,4]],e);doneTest(e);// ======================================================// ==================== Script tests ====================// ======================================================clear();e=document.getElementById('testD');clear(e.contentWindow);sel=e.contentWindow.getSelection();sel.selectAllChildren(e.contentDocument.body);is(window.getSelection().rangeCount,0,"testD: no selection in outer window");is(sel.toString(),'aaaacccc',"testD: scripted selection");is(sel.rangeCount,1,"testD: scripted selection isn't filtered");is(sel.getRangeAt(0).toString(),'aaaabbbbcccc',"testD: scripted selection isn't filtered");// ======================================================// ================== Kbd command tests =================// ======================================================clear();e=document.getElementById('testD');clear(e.contentWindow);e.contentWindow.focus();synthesizeKey("a",{accelKey:true},e.contentWindow);sel=e.contentWindow.getSelection();is(window.getSelection().rangeCount,0,"testD: no selection in outer window");is(sel.toString(),'aaaacccc',"testD: kbd selection");is(sel.rangeCount,2,"testD: kbd selection is filtered");is(sel.getRangeAt(0).toString(),'aaaa',"testD: kbd selection is filtered");is(sel.getRangeAt(1).toString(),'cccc',"testD: kbd selection is filtered");doneTest(e);clear();SimpleTest.finish();}// These tests depends on the Ahem font being loaded and rendered so wait for// font to load, then wait a frame for them to be rendered too.window.onload=function(){document.fonts.ready.then(function(){requestAnimationFrame(test);});};SimpleTest.waitForExplicitFinish();</script></pre></body></html>