Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Expose HTTP request information in response #447

Merged
merged 8 commits into from
Jan 29, 2018
20 changes: 12 additions & 8 deletions js/modules/k6/http/http.go
Original file line number Diff line number Diff line change
Expand Up @@ -128,21 +128,25 @@ func (*HTTP) CookieJar(ctx context.Context) *HTTPCookieJar {
return &HTTPCookieJar{state.CookieJar, &ctx}
}

func (*HTTP) setRequestCookies(req *http.Request, jar *cookiejar.Jar, reqCookies map[string]*HTTPRequestCookie) {
jarCookies := make(map[string][]*http.Cookie)
func (*HTTP) mergeCookies(req *http.Request, jar *cookiejar.Jar, reqCookies map[string]*HTTPRequestCookie) map[string][]*HTTPRequestCookie {
allCookies := make(map[string][]*HTTPRequestCookie)
for _, c := range jar.Cookies(req.URL) {
jarCookies[c.Name] = append(jarCookies[c.Name], c)
allCookies[c.Name] = append(allCookies[c.Name], &HTTPRequestCookie{Name: c.Name, Value: c.Value})
}
for key, reqCookie := range reqCookies {
if jc := jarCookies[key]; jc != nil && reqCookie.Replace {
jarCookies[key] = []*http.Cookie{{Name: key, Value: reqCookie.Value}}
if jc := allCookies[key]; jc != nil && reqCookie.Replace {
allCookies[key] = []*HTTPRequestCookie{{Name: key, Value: reqCookie.Value}}
} else {
jarCookies[key] = append(jarCookies[key], &http.Cookie{Name: key, Value: reqCookie.Value})
allCookies[key] = append(allCookies[key], &HTTPRequestCookie{Name: key, Value: reqCookie.Value})
}
}
for _, cookies := range jarCookies {
return allCookies
}

func (*HTTP) setRequestCookies(req *http.Request, reqCookies map[string][]*HTTPRequestCookie) {
for _, cookies := range reqCookies {
for _, c := range cookies {
req.AddCookie(c)
req.AddCookie(&http.Cookie{Name: c.Name, Value: c.Value})
}
}
}
25 changes: 22 additions & 3 deletions js/modules/k6/http/http_request.go
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,14 @@ import (
null "gopkg.in/guregu/null.v3"
)

type HTTPRequest struct {
Method string
URL string
Headers map[string][]string
Body string
Cookies map[string][]*HTTPRequestCookie
}

func (http *HTTP) Get(ctx context.Context, url goja.Value, args ...goja.Value) (*HTTPResponse, error) {
// The body argument is always undefined for GETs and HEADs.
args = append([]goja.Value{goja.Undefined()}, args...)
Expand Down Expand Up @@ -113,9 +121,14 @@ func (h *HTTP) request(ctx context.Context, rt *goja.Runtime, state *common.Stat
URL: url.URL,
Header: make(http.Header),
}
respReq := &HTTPRequest{
Method: req.Method,
URL: req.URL.String(),
}
if bodyBuf != nil {
req.Body = ioutil.NopCloser(bodyBuf)
req.ContentLength = int64(bodyBuf.Len())
respReq.Body = bodyBuf.String()
}
if contentType != "" {
req.Header.Set("Content-Type", contentType)
Expand Down Expand Up @@ -231,7 +244,9 @@ func (h *HTTP) request(ctx context.Context, rt *goja.Runtime, state *common.Stat
}

if activeJar != nil {
h.setRequestCookies(req, activeJar, reqCookies)
mergedCookies := h.mergeCookies(req, activeJar, reqCookies)
respReq.Cookies = mergedCookies
h.setRequestCookies(req, mergedCookies)
}

// Check rate limit *after* we've prepared a request; no need to wait with that part.
Expand All @@ -241,7 +256,9 @@ func (h *HTTP) request(ctx context.Context, rt *goja.Runtime, state *common.Stat
}
}

resp := &HTTPResponse{ctx: ctx, URL: url.URLString}
respReq.Headers = req.Header

resp := &HTTPResponse{ctx: ctx, URL: url.URLString, Request: *respReq}
client := http.Client{
Transport: state.HTTPTransport,
Timeout: timeout,
Expand All @@ -252,7 +269,9 @@ func (h *HTTP) request(ctx context.Context, rt *goja.Runtime, state *common.Stat
activeJar.SetCookies(req.URL, respCookies)
}
req.Header.Del("Cookie")
h.setRequestCookies(req, activeJar, reqCookies)
mergedCookies := h.mergeCookies(req, activeJar, reqCookies)

h.setRequestCookies(req, mergedCookies)
}

if l := len(via); int64(l) > redirects.Int64 {
Expand Down
33 changes: 33 additions & 0 deletions js/modules/k6/http/http_request_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -862,4 +862,37 @@ func TestRequestAndBatch(t *testing.T) {
assertRequestMetricsEmitted(t, state.Samples, "PUT", "https://httpbin.org/put", "", 200, "")
})
})

t.Run("HTTPRequest", func(t *testing.T) {
t.Run("EmptyBody", func(t *testing.T) {
_, err := common.RunString(rt, `
let reqUrl = "https://httpbin.org/cookies"
let res = http.get(reqUrl);
let jar = new http.CookieJar();

jar.set("https://httpbin.org/cookies", "key", "value");
res = http.request("GET", "https://httpbin.org/cookies", null, { cookies: { key2: "value2" }, jar: jar });

if (res.json().cookies.key != "value") { throw new Error("wrong cookie value: " + res.json().cookies.key); }

if (res.status != 200) { throw new Error("wrong status: " + res.status); }
if (res.request["method"] !== "GET") { throw new Error("http request method was not \"GET\": " + JSON.stringify(res.request)) }
if (res.request["body"].length != 0) { throw new Error("http request body was not null: " + JSON.stringify(res.request["body"])) }
if (res.request["url"] != reqUrl) {
throw new Error("wrong http request url: " + JSON.stringify(res.request))
}
if (res.request["cookies"]["key2"][0].name != "key2") { throw new Error("wrong http request cookies: " + JSON.stringify(JSON.stringify(res.request["cookies"]["key2"]))) }
if (res.request["headers"]["User-Agent"][0] != "TestUserAgent") { throw new Error("wrong http request headers: " + JSON.stringify(res.request)) }
`)
assert.NoError(t, err)
})
t.Run("NonEmptyBody", func(t *testing.T) {
_, err := common.RunString(rt, `
let res = http.post("https://httpbin.org/post", {a: "a", b: 2}, {headers: {"Content-Type": "application/x-www-form-urlencoded; charset=utf-8"}});
if (res.status != 200) { throw new Error("wrong status: " + res.status); }
if (res.request["body"] != "a=a&b=2") { throw new Error("http request body was not set properly: " + JSON.stringify(res.request))}
`)
assert.NoError(t, err)
})
})
}
1 change: 1 addition & 0 deletions js/modules/k6/http/response.go
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,7 @@ type HTTPResponse struct {
TLSCipherSuite string
OCSP OCSP `js:"ocsp"`
Error string
Request HTTPRequest

cachedJSON goja.Value
}
Expand Down