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.