@@ -4,12 +4,17 @@ import (
44 "fmt"
55 "io/ioutil"
66 "net/http"
7+ "strconv"
8+ "strings"
79 "time"
810
911 log "github.com/sirupsen/logrus"
12+ "github.com/tomnomnom/linkheader"
1013)
1114
1215func asyncHTTPGets (targets []string , token string ) ([]* Response , error ) {
16+ // Expand targets by following GitHub pagination links
17+ targets = paginateTargets (targets , token )
1318
1419 // Channels used to enable concurrent requests
1520 ch := make (chan * Response , len (targets ))
@@ -44,6 +49,46 @@ func asyncHTTPGets(targets []string, token string) ([]*Response, error) {
4449 }
4550}
4651
52+ // paginateTargets returns all pages for the provided targets
53+ func paginateTargets (targets []string , token string ) []string {
54+
55+ paginated := targets
56+
57+ for _ , url := range targets {
58+
59+ // make a request to the original target to get link header if it exists
60+ resp , err := getHTTPResponse (url , token )
61+ if err != nil {
62+ log .Errorf ("Error retrieving Link headers, Error: %s" , err )
63+ }
64+
65+ if resp .Header ["Link" ] != nil {
66+ links := linkheader .Parse (resp .Header ["Link" ][0 ])
67+
68+ for _ , link := range links {
69+ if link .Rel == "last" {
70+
71+ subs := strings .Split (link .URL , "&page=" )
72+
73+ lastPage , err := strconv .Atoi (subs [len (subs )- 1 ])
74+ if err != nil {
75+ log .Errorf ("Unable to convert page substring to int, Error: %s" , err )
76+ }
77+
78+ // add all pages to the slice of targets to return
79+ for page := 2 ; page <= lastPage ; page ++ {
80+ pageURL := fmt .Sprintf ("%s&page=%v" , url , page )
81+ paginated = append (paginated , pageURL )
82+ }
83+
84+ break
85+ }
86+ }
87+ }
88+ }
89+ return paginated
90+ }
91+
4792// getResponse collects an individual http.response and returns a *Response
4893func getResponse (url string , token string , ch chan <- * Response ) error {
4994
0 commit comments