gddo-server: parse host and url from request correctly
Most browsers send requests to http://godoc.org/net/http as
GET /net/http HTTP/1.1
Host: godoc.org
instead of as expected in current tests
GET https://godoc.org/net/http HTTP/1.1
Host: godoc.org
This causes http.Request.URL to have empty strings for the "Scheme" and
"Host" fields (see https://golang.org/src/net/http/request.go#L120 and
RFC 7230 Section 5.3). As a result, server logs show most gddoEvent
structs as having an empty "Host" field and a relative path for the URL.
This CL enables the parsing of these fields from the other fields of the
http.Request struct.
Change-Id: Iab923a0d9a70f32f36b6e4a15019afc648699796
Reviewed-on: https://go-review.googlesource.com/c/gddo/+/236143
Reviewed-by: Julie Qiu <julie@golang.org>
Reviewed-by: Jonathan Amsterdam <jba@google.com>
diff --git a/gddo-server/main.go b/gddo-server/main.go
index d316344..9ffb342 100644
--- a/gddo-server/main.go
+++ b/gddo-server/main.go
@@ -1074,11 +1074,20 @@
}
func newGDDOEvent(r *http.Request, latency time.Duration, isRobot bool) *gddoEvent {
+ targetURL := url.URL{
+ Scheme: "https",
+ Host: r.URL.Host,
+ Path: r.URL.Path,
+ RawQuery: r.URL.RawQuery,
+ }
+ if targetURL.Host == "" && r.Host != "" {
+ targetURL.Host = r.Host
+ }
pkgGoDevURL := url.URL{Scheme: "https", Host: pkgGoDevHost}
return &gddoEvent{
- Host: r.URL.Host,
+ Host: targetURL.Host,
Path: r.URL.Path,
- URL: r.URL.String(),
+ URL: targetURL.String(),
Header: r.Header,
RedirectHost: pkgGoDevURL.String(),
Latency: latency,
diff --git a/gddo-server/main_test.go b/gddo-server/main_test.go
index 1f29fa7..28f53a4 100644
--- a/gddo-server/main_test.go
+++ b/gddo-server/main_test.go
@@ -7,9 +7,11 @@
package main
import (
+ "bufio"
"net/http"
"net/http/httptest"
"net/url"
+ "strings"
"testing"
"github.com/google/go-cmp/cmp"
@@ -306,3 +308,140 @@
})
}
}
+
+func TestNewGDDOEventFromRequests(t *testing.T) {
+ for _, test := range []struct {
+ name string
+ requestURI string
+ host string
+ want *gddoEvent
+ }{
+ {
+ name: "absolute index path",
+ requestURI: "https://godoc.org",
+ host: "godoc.org",
+ want: &gddoEvent{
+ Host: "godoc.org",
+ Path: "",
+ URL: "https://godoc.org",
+ },
+ },
+ {
+ name: "absolute index path with trailing slash",
+ requestURI: "https://godoc.org/",
+ host: "godoc.org",
+ want: &gddoEvent{
+ Host: "godoc.org",
+ Path: "/",
+ URL: "https://godoc.org/",
+ },
+ },
+ {
+ name: "relative index path",
+ requestURI: "/",
+ host: "godoc.org",
+ want: &gddoEvent{
+ Host: "godoc.org",
+ Path: "/",
+ URL: "https://godoc.org/",
+ },
+ },
+ {
+ name: "absolute about path",
+ requestURI: "https://godoc.org/-/about",
+ host: "godoc.org",
+ want: &gddoEvent{
+ Host: "godoc.org",
+ Path: "/-/about",
+ URL: "https://godoc.org/-/about",
+ },
+ },
+ {
+ name: "relative about path",
+ requestURI: "/-/about",
+ host: "godoc.org",
+ want: &gddoEvent{
+ Host: "godoc.org",
+ Path: "/-/about",
+ URL: "https://godoc.org/-/about",
+ },
+ },
+ {
+ name: "absolute package path",
+ requestURI: "https://godoc.org/net/http",
+ host: "godoc.org",
+ want: &gddoEvent{
+ Host: "godoc.org",
+ Path: "/net/http",
+ URL: "https://godoc.org/net/http",
+ },
+ },
+ {
+ name: "relative package path",
+ requestURI: "/net/http",
+ host: "godoc.org",
+ want: &gddoEvent{
+ Host: "godoc.org",
+ Path: "/net/http",
+ URL: "https://godoc.org/net/http",
+ },
+ },
+ {
+ name: "absolute path with query parameters",
+ requestURI: "https://godoc.org/net/http?q=test",
+ host: "godoc.org",
+ want: &gddoEvent{
+ Host: "godoc.org",
+ Path: "/net/http",
+ URL: "https://godoc.org/net/http?q=test",
+ },
+ },
+ {
+ name: "relative path with query parameters",
+ requestURI: "/net/http?q=test",
+ host: "godoc.org",
+ want: &gddoEvent{
+ Host: "godoc.org",
+ Path: "/net/http",
+ URL: "https://godoc.org/net/http?q=test",
+ },
+ },
+ {
+ name: "absolute api path",
+ requestURI: "https://api.godoc.org/imports/net/http",
+ host: "api.godoc.org",
+ want: &gddoEvent{
+ Host: "api.godoc.org",
+ Path: "/imports/net/http",
+ URL: "https://api.godoc.org/imports/net/http",
+ },
+ },
+ {
+ name: "relative api path",
+ requestURI: "/imports/net/http",
+ host: "api.godoc.org",
+ want: &gddoEvent{
+ Host: "api.godoc.org",
+ Path: "/imports/net/http",
+ URL: "https://api.godoc.org/imports/net/http",
+ },
+ },
+ } {
+ t.Run(test.name, func(t *testing.T) {
+ want := test.want
+ want.Latency = 100
+ want.RedirectHost = "https://" + pkgGoDevHost
+ want.Header = http.Header{}
+ want.IsRobot = false
+ requestLine := "GET " + test.requestURI + " HTTP/1.1\r\nHost: " + test.host + "\r\n\r\n"
+ req, err := http.ReadRequest(bufio.NewReader(strings.NewReader(requestLine)))
+ if err != nil {
+ t.Fatal("invalid NewRequest arguments; " + err.Error())
+ }
+ got := newGDDOEvent(req, want.Latency, want.IsRobot)
+ if diff := cmp.Diff(want, got); diff != "" {
+ t.Fatalf("mismatch (-want +got):\n%s", diff)
+ }
+ })
+ }
+}