gddo-server: fetch path on pkg.go.dev 404 When a godoc.org requests results in a 200, but a 404 on pkg.go.dev, make a fetch request to pkg.go.dev to fetch that path and log the output. Change-Id: I1ca12732317d7e90b42eff022357067d21f84f9b Reviewed-on: https://go-review.googlesource.com/c/gddo/+/279038 Trust: Julie Qiu <julie@golang.org> Reviewed-by: Jonathan Amsterdam <jba@google.com>
diff --git a/gddo-server/pkgsite.go b/gddo-server/pkgsite.go index e41c866..3ee9e71 100644 --- a/gddo-server/pkgsite.go +++ b/gddo-server/pkgsite.go
@@ -7,6 +7,9 @@ package main import ( + "context" + "fmt" + "io/ioutil" "net/http" "net/url" "path/filepath" @@ -22,7 +25,10 @@ Status int URL string Latency time.Duration - Error error + Error string + // If a request 404s, make a request to fetch it and store the response. + FetchStatus int + FetchResponse string } func teeRequestToPkgGoDev(godocReq *http.Request, latency time.Duration, isRobot bool, status int) (gddoEvent *gddoEvent, pkgEvent *pkggodevEvent) { @@ -39,27 +45,41 @@ Path: u.Path, URL: u.String(), } - req, err := http.NewRequest("GET", u.String(), nil) - if err != nil { - pkgEvent.Status = http.StatusInternalServerError - pkgEvent.Error = err - return gddoEvent, pkgEvent - } start := time.Now() + status, errResp := makeRequest(godocReq.Context(), u.String()) + pkgEvent.Status = status + pkgEvent.Latency = time.Since(start) + // The response will always be an error here if not empty. + pkgEvent.Error = errResp + + if pkgEvent.Status == http.StatusNotFound && gddoEvent.Status == http.StatusOK { + // If the request was successful on godoc.org but returned a 404 on + // pkg.go.dev make a fetch request. + status, body := makeRequest(godocReq.Context(), "/fetch"+u.String()) + pkgEvent.FetchStatus = status + pkgEvent.FetchResponse = body + } + return gddoEvent, pkgEvent +} + +func makeRequest(ctx context.Context, url string) (int, string) { + req, err := http.NewRequest("GET", url, nil) + if err != nil { + return http.StatusInternalServerError, fmt.Sprintf("http.NewRequest: %v", err) + } xfwd := req.Header.Get("X-Forwarded-for") req.Header.Set("X-Godoc-Forwarded-for", xfwd) - resp, err := ctxhttp.Do(godocReq.Context(), http.DefaultClient, req) + resp, err := ctxhttp.Do(ctx, http.DefaultClient, req) if err != nil { // Use StatusBadGateway to indicate the upstream error. - pkgEvent.Status = http.StatusBadGateway - pkgEvent.Error = err - return gddoEvent, pkgEvent + return http.StatusBadGateway, err.Error() } - - pkgEvent.Status = resp.StatusCode - pkgEvent.Latency = time.Since(start) - return gddoEvent, pkgEvent - + defer resp.Body.Close() + body, err := ioutil.ReadAll(resp.Body) + if err != nil { + return resp.StatusCode, fmt.Sprintf("can't read body: %v", err) + } + return resp.StatusCode, string(body) } // doNotTeeURLsToPkgGoDev are paths that should not be teed to pkg.go.dev.