@@ -3,16 +3,21 @@ package runner
33import (
44 "context"
55 "fmt"
6+ "log"
67 "net/http"
8+ "net/http/httptest"
79 "os"
810 "strings"
11+ "sync"
12+ "sync/atomic"
913 "testing"
1014 "time"
1115
1216 _ "github.com/projectdiscovery/fdmax/autofdmax"
1317 "github.com/projectdiscovery/httpx/common/httpx"
1418 "github.com/projectdiscovery/mapcidr/asn"
1519 stringsutil "github.com/projectdiscovery/utils/strings"
20+ syncutil "github.com/projectdiscovery/utils/sync"
1621 "github.com/stretchr/testify/require"
1722)
1823
@@ -315,70 +320,94 @@ func TestCreateNetworkpolicyInstance_AllowDenyFlags(t *testing.T) {
315320 }
316321}
317322
318- func TestRunner_RetryLoop (t * testing.T ) {
319- retryCh := make (chan retryJob )
320- out := make (chan Result )
323+ func TestRunner_Process_And_RetryLoop (t * testing.T ) {
324+ var hits1 , hits2 int32
325+ srv1 := httptest .NewServer (http .HandlerFunc (func (w http.ResponseWriter , r * http.Request ) {
326+ if atomic .AddInt32 (& hits1 , 1 ) != 4 {
327+ log .Println ("serv1 429" )
328+ w .WriteHeader (http .StatusTooManyRequests )
329+ return
330+ }
331+ log .Println ("serv1 200" )
332+ w .WriteHeader (http .StatusOK )
333+ }))
334+ defer srv1 .Close ()
335+
336+ srv2 := httptest .NewServer (http .HandlerFunc (func (w http.ResponseWriter , r * http.Request ) {
337+ if atomic .AddInt32 (& hits2 , 1 ) != 3 {
338+ log .Println ("serv2 429" )
339+ w .WriteHeader (http .StatusTooManyRequests )
340+ return
341+ }
342+ log .Println ("serv2 200" )
343+ w .WriteHeader (http .StatusOK )
344+ }))
345+ defer srv2 .Close ()
321346
322347 r , err := New (& Options {
323- RetryDelay : 500 ,
348+ Threads : 1 ,
349+ Delay : 0 ,
324350 RetryRounds : 3 ,
351+ RetryDelay : 200 , // Duration 권장
352+ Timeout : 2 ,
325353 })
326- require .Nil (t , err , "could not create httpx runner" )
354+ require .NoError (t , err )
327355
328- var calls = map [string ]int {}
329- analyze := func (hp * httpx.HTTPX ,
330- protocol string ,
331- target httpx.Target ,
332- method , origInput string ,
333- scanopts * ScanOptions ) Result {
334- calls [method ]++
335- if strings .HasPrefix (method , "retry-" ) && calls [method ] == 1 {
336- return Result {StatusCode : http .StatusTooManyRequests }
337- }
338- return Result {StatusCode : http .StatusOK }
339- }
356+ output := make (chan Result )
357+ retryCh := make (chan retryJob )
340358
341- cancel , wait := r .retryLoop (context .Background (), retryCh , out , analyze )
359+ // ctx, timeout := context.WithTimeout(context.Background(), time.Duration(r.options.Timeout))
360+ // defer timeout()
361+ cancel , wait := r .retryLoop (context .Background (), retryCh , output , r .analyze )
342362
343- seed := []retryJob {
344- {method : "ok-a" , when : time .Now ().Add (- time .Millisecond ), attempt : 1 },
345- {method : "retry-a" , when : time .Now ().Add (- time .Millisecond ), attempt : 1 },
346- {method : "ok-b" , when : time .Now ().Add (- time .Millisecond ), attempt : 1 },
347- {method : "retry-b" , when : time .Now ().Add (- time .Millisecond ), attempt : 1 },
348- }
349- for _ , j := range seed {
350- retryCh <- j
351- }
363+ wg , _ := syncutil .New (syncutil .WithSize (r .options .Threads ))
364+ so := r .scanopts .Clone ()
365+ so .Methods = []string {"GET" }
366+ so .TLSProbe = false
367+ so .CSPProbe = false
352368
353- want := 6
354- got := make ([]Result , 0 , want )
355- deadline := time .After (2 * time .Second )
369+ seed := map [string ]string {
370+ "srv1" : srv1 .URL ,
371+ "srv2" : srv2 .URL ,
372+ }
356373
357- for len (got ) < want {
358- select {
359- case r := <- out :
360- got = append (got , r )
361- case <- deadline :
362- t .Errorf ("timed out waiting results: got=%d want=%d" , len (got ), want )
374+ var drainWG sync.WaitGroup
375+ drainWG .Add (1 )
376+ var s1n429 , s1n200 , s2n429 , s2n200 int
377+ go func (output chan Result ) {
378+ defer drainWG .Done ()
379+ for res := range output {
380+ switch res .StatusCode {
381+ case http .StatusTooManyRequests :
382+ if res .URL == srv1 .URL {
383+ s1n429 ++
384+ } else {
385+ s2n429 ++
386+ }
387+ case http .StatusOK :
388+ if res .URL == srv1 .URL {
389+ s1n200 ++
390+ } else {
391+ s2n200 ++
392+ }
393+ }
363394 }
395+ }(output )
396+
397+ for _ , url := range seed {
398+ r .process (url , wg , r .hp , httpx .HTTP , so , output , retryCh )
364399 }
365400
401+ wg .Wait ()
366402 wait ()
367403 cancel ()
368- close (retryCh )
369404
370- close (out )
371-
372- var n429 , n200 int
373- for _ , r := range got {
374- switch r .StatusCode {
375- case http .StatusTooManyRequests :
376- n429 ++
377- case http .StatusOK :
378- n200 ++
379- }
380- }
405+ close (retryCh )
406+ close (output )
407+ drainWG .Wait ()
381408
382- require .GreaterOrEqual (t , n429 , 2 )
383- require .Equal (t , 4 , n200 )
409+ require .Equal (t , 3 , s1n429 )
410+ require .Equal (t , 1 , s1n200 )
411+ require .Equal (t , 2 , s2n429 )
412+ require .Equal (t , 1 , s2n200 )
384413}
0 commit comments