mirror of
https://github.com/dutchcoders/transfer.sh.git
synced 2020-11-18 19:53:40 -08:00
913 lines
25 KiB
Go
913 lines
25 KiB
Go
// Copyright 2015 Google Inc. All rights reserved.
|
|
//
|
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
|
// you may not use this file except in compliance with the License.
|
|
// You may obtain a copy of the License at
|
|
//
|
|
// http://www.apache.org/licenses/LICENSE-2.0
|
|
//
|
|
// Unless required by applicable law or agreed to in writing, software
|
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
// See the License for the specific language governing permissions and
|
|
// limitations under the License.
|
|
|
|
package har
|
|
|
|
import (
|
|
"bytes"
|
|
"encoding/json"
|
|
"mime/multipart"
|
|
"net/http"
|
|
"reflect"
|
|
"strings"
|
|
"testing"
|
|
"time"
|
|
|
|
"github.com/google/martian"
|
|
"github.com/google/martian/proxyutil"
|
|
)
|
|
|
|
func TestModifyRequest(t *testing.T) {
|
|
req, err := http.NewRequest("GET", "http://example.com/path?query=true", nil)
|
|
if err != nil {
|
|
t.Fatalf("http.NewRequest(): got %v, want no error", err)
|
|
}
|
|
req.Header.Add("Request-Header", "first")
|
|
req.Header.Add("Request-Header", "second")
|
|
|
|
cookie := &http.Cookie{
|
|
Name: "request",
|
|
Value: "cookie",
|
|
}
|
|
req.AddCookie(cookie)
|
|
|
|
_, remove, err := martian.TestContext(req, nil, nil)
|
|
if err != nil {
|
|
t.Fatalf("martian.TestContext(): got %v, want no error", err)
|
|
}
|
|
defer remove()
|
|
|
|
logger := NewLogger()
|
|
if err := logger.ModifyRequest(req); err != nil {
|
|
t.Fatalf("ModifyRequest(): got %v, want no error", err)
|
|
}
|
|
|
|
log := logger.Export().Log
|
|
if got, want := log.Version, "1.2"; got != want {
|
|
t.Errorf("log.Version: got %q, want %q", got, want)
|
|
}
|
|
|
|
if got, want := len(log.Entries), 1; got != want {
|
|
t.Fatalf("len(log.Entries): got %d, want %d", got, want)
|
|
}
|
|
|
|
entry := log.Entries[0]
|
|
if got, want := time.Since(entry.StartedDateTime), time.Second; got > want {
|
|
t.Errorf("entry.StartedDateTime: got %s, want less than %s", got, want)
|
|
}
|
|
|
|
hreq := entry.Request
|
|
if got, want := hreq.Method, "GET"; got != want {
|
|
t.Errorf("hreq.Method: got %q, want %q", got, want)
|
|
}
|
|
|
|
if got, want := hreq.URL, "http://example.com/path?query=true"; got != want {
|
|
t.Errorf("hreq.URL: got %q, want %q", got, want)
|
|
}
|
|
|
|
if got, want := hreq.HTTPVersion, "HTTP/1.1"; got != want {
|
|
t.Errorf("hreq.HTTPVersion: got %q, want %q", got, want)
|
|
}
|
|
|
|
if got, want := hreq.BodySize, int64(0); got != want {
|
|
t.Errorf("hreq.BodySize: got %d, want %d", got, want)
|
|
}
|
|
|
|
if got, want := hreq.HeadersSize, int64(-1); got != want {
|
|
t.Errorf("hreq.HeadersSize: got %d, want %d", got, want)
|
|
}
|
|
|
|
if got, want := len(hreq.QueryString), 1; got != want {
|
|
t.Fatalf("len(hreq.QueryString): got %d, want %q", got, want)
|
|
}
|
|
|
|
qs := hreq.QueryString[0]
|
|
if got, want := qs.Name, "query"; got != want {
|
|
t.Errorf("qs.Name: got %q, want %q", got, want)
|
|
}
|
|
if got, want := qs.Value, "true"; got != want {
|
|
t.Errorf("qs.Value: got %q, want %q", got, want)
|
|
}
|
|
|
|
wantHeaders := http.Header{
|
|
"Request-Header": {"first", "second"},
|
|
"Cookie": {cookie.String()},
|
|
"Host": {"example.com"},
|
|
}
|
|
if got := headersToHTTP(hreq.Headers); !reflect.DeepEqual(got, wantHeaders) {
|
|
t.Errorf("headers:\ngot:\n%+v\nwant:\n%+v", got, wantHeaders)
|
|
}
|
|
|
|
if got, want := len(hreq.Cookies), 1; got != want {
|
|
t.Fatalf("len(hreq.Cookies): got %d, want %d", got, want)
|
|
}
|
|
|
|
hcookie := hreq.Cookies[0]
|
|
if got, want := hcookie.Name, "request"; got != want {
|
|
t.Errorf("hcookie.Name: got %q, want %q", got, want)
|
|
}
|
|
if got, want := hcookie.Value, "cookie"; got != want {
|
|
t.Errorf("hcookie.Value: got %q, want %q", got, want)
|
|
}
|
|
}
|
|
|
|
func headersToHTTP(hs []Header) http.Header {
|
|
hh := http.Header{}
|
|
for _, h := range hs {
|
|
hh[h.Name] = append(hh[h.Name], h.Value)
|
|
}
|
|
return hh
|
|
}
|
|
|
|
func TestModifyResponse(t *testing.T) {
|
|
req, err := http.NewRequest("GET", "http://example.com", nil)
|
|
if err != nil {
|
|
t.Fatalf("NewRequest(): got %v, want no error", err)
|
|
}
|
|
|
|
_, remove, err := martian.TestContext(req, nil, nil)
|
|
if err != nil {
|
|
t.Fatalf("martian.TestContext(): got %v, want no error", err)
|
|
}
|
|
defer remove()
|
|
|
|
res := proxyutil.NewResponse(301, strings.NewReader("response body"), req)
|
|
res.ContentLength = 13
|
|
res.Header.Add("Response-Header", "first")
|
|
res.Header.Add("Response-Header", "second")
|
|
res.Header.Set("Location", "google.com")
|
|
|
|
expires := time.Now()
|
|
cookie := &http.Cookie{
|
|
Name: "response",
|
|
Value: "cookie",
|
|
Path: "/",
|
|
Domain: "example.com",
|
|
Expires: expires,
|
|
Secure: true,
|
|
HttpOnly: true,
|
|
}
|
|
res.Header.Set("Set-Cookie", cookie.String())
|
|
|
|
logger := NewLogger()
|
|
|
|
if err := logger.ModifyRequest(req); err != nil {
|
|
t.Fatalf("ModifyRequest(): got %v, want no error", err)
|
|
}
|
|
|
|
if err := logger.ModifyResponse(res); err != nil {
|
|
t.Fatalf("ModifyResponse(): got %v, want no error", err)
|
|
}
|
|
|
|
log := logger.Export().Log
|
|
if got, want := len(log.Entries), 1; got != want {
|
|
t.Fatalf("len(log.Entries): got %d, want %d", got, want)
|
|
}
|
|
|
|
hres := log.Entries[0].Response
|
|
if got, want := hres.Status, 301; got != want {
|
|
t.Errorf("hres.Status: got %d, want %d", got, want)
|
|
}
|
|
|
|
if got, want := hres.StatusText, "Moved Permanently"; got != want {
|
|
t.Errorf("hres.StatusText: got %q, want %q", got, want)
|
|
}
|
|
|
|
if got, want := hres.HTTPVersion, "HTTP/1.1"; got != want {
|
|
t.Errorf("hres.HTTPVersion: got %q, want %q", got, want)
|
|
}
|
|
|
|
if got, want := hres.Content.Text, []byte("response body"); !bytes.Equal(got, want) {
|
|
t.Errorf("hres.Content.Text: got %q, want %q", got, want)
|
|
}
|
|
|
|
wantHeaders := http.Header{
|
|
"Response-Header": {"first", "second"},
|
|
"Set-Cookie": {cookie.String()},
|
|
"Location": {"google.com"},
|
|
"Content-Length": {"13"},
|
|
}
|
|
if got := headersToHTTP(hres.Headers); !reflect.DeepEqual(got, wantHeaders) {
|
|
t.Errorf("headers:\ngot:\n%+v\nwant:\n%+v", got, wantHeaders)
|
|
}
|
|
|
|
if got, want := len(hres.Cookies), 1; got != want {
|
|
t.Fatalf("len(hres.Cookies): got %d, want %d", got, want)
|
|
}
|
|
|
|
hcookie := hres.Cookies[0]
|
|
if got, want := hcookie.Name, "response"; got != want {
|
|
t.Errorf("hcookie.Name: got %q, want %q", got, want)
|
|
}
|
|
if got, want := hcookie.Value, "cookie"; got != want {
|
|
t.Errorf("hcookie.Value: got %q, want %q", got, want)
|
|
}
|
|
if got, want := hcookie.Path, "/"; got != want {
|
|
t.Errorf("hcookie.Path: got %q, want %q", got, want)
|
|
}
|
|
if got, want := hcookie.Domain, "example.com"; got != want {
|
|
t.Errorf("hcookie.Domain: got %q, want %q", got, want)
|
|
}
|
|
if got, want := hcookie.Expires, expires; got.Equal(want) {
|
|
t.Errorf("hcookie.Expires: got %s, want %s", got, want)
|
|
}
|
|
if !hcookie.HTTPOnly {
|
|
t.Error("hcookie.HTTPOnly: got false, want true")
|
|
}
|
|
if !hcookie.Secure {
|
|
t.Error("hcookie.Secure: got false, want true")
|
|
}
|
|
}
|
|
|
|
func TestModifyRequestBodyURLEncoded(t *testing.T) {
|
|
logger := NewLogger()
|
|
|
|
body := strings.NewReader("first=true&second=false")
|
|
req, err := http.NewRequest("POST", "http://example.com", body)
|
|
if err != nil {
|
|
t.Fatalf("http.NewRequest(): got %v, want no error", err)
|
|
}
|
|
req.Header.Set("Content-Type", "application/x-www-form-urlencoded")
|
|
|
|
_, remove, err := martian.TestContext(req, nil, nil)
|
|
if err != nil {
|
|
t.Fatalf("martian.TestContext(): got %v, want no error", err)
|
|
}
|
|
defer remove()
|
|
|
|
if err := logger.ModifyRequest(req); err != nil {
|
|
t.Fatalf("ModifyRequest(): got %v, want no error", err)
|
|
}
|
|
|
|
log := logger.Export().Log
|
|
if got, want := len(log.Entries), 1; got != want {
|
|
t.Errorf("len(log.Entries): got %v, want %v", got, want)
|
|
}
|
|
|
|
pd := log.Entries[0].Request.PostData
|
|
if got, want := pd.MimeType, "application/x-www-form-urlencoded"; got != want {
|
|
t.Errorf("PostData.MimeType: got %v, want %v", got, want)
|
|
}
|
|
|
|
if got, want := len(pd.Params), 2; got != want {
|
|
t.Fatalf("len(PostData.Params): got %d, want %d", got, want)
|
|
}
|
|
|
|
for _, p := range pd.Params {
|
|
var want string
|
|
switch p.Name {
|
|
case "first":
|
|
want = "true"
|
|
case "second":
|
|
want = "false"
|
|
default:
|
|
t.Errorf("PostData.Params: got %q, want to not be present", p.Name)
|
|
continue
|
|
}
|
|
|
|
if got := p.Value; got != want {
|
|
t.Errorf("PostData.Params[%q]: got %q, want %q", p.Name, got, want)
|
|
}
|
|
}
|
|
}
|
|
|
|
func TestModifyRequestBodyArbitraryContentType(t *testing.T) {
|
|
logger := NewLogger()
|
|
|
|
body := "arbitrary binary data"
|
|
req, err := http.NewRequest("POST", "http://www.example.com", strings.NewReader(body))
|
|
if err != nil {
|
|
t.Fatalf("http.NewRequest(): got %v, want no error", err)
|
|
}
|
|
|
|
_, remove, err := martian.TestContext(req, nil, nil)
|
|
if err != nil {
|
|
t.Fatalf("martian.TestContext(): got %v, want no error", err)
|
|
}
|
|
defer remove()
|
|
|
|
if err := logger.ModifyRequest(req); err != nil {
|
|
t.Fatalf("ModifyRequest(): got %v, want no error", err)
|
|
}
|
|
|
|
log := logger.Export().Log
|
|
if got, want := len(log.Entries), 1; got != want {
|
|
t.Errorf("len(log.Entries): got %d, want %d", got, want)
|
|
}
|
|
|
|
pd := log.Entries[0].Request.PostData
|
|
if got, want := pd.MimeType, ""; got != want {
|
|
t.Errorf("PostData.MimeType: got %q, want %q", got, want)
|
|
}
|
|
if got, want := len(pd.Params), 0; got != want {
|
|
t.Errorf("len(PostData.Params): got %d, want %d", got, want)
|
|
}
|
|
|
|
if got, want := pd.Text, body; got != want {
|
|
t.Errorf("PostData.Text: got %q, want %q", got, want)
|
|
}
|
|
}
|
|
|
|
func TestModifyRequestBodyMultipart(t *testing.T) {
|
|
logger := NewLogger()
|
|
|
|
body := new(bytes.Buffer)
|
|
mpw := multipart.NewWriter(body)
|
|
mpw.SetBoundary("boundary")
|
|
|
|
if err := mpw.WriteField("key", "value"); err != nil {
|
|
t.Errorf("mpw.WriteField(): got %v, want no error", err)
|
|
}
|
|
|
|
w, err := mpw.CreateFormFile("file", "test.txt")
|
|
if _, err = w.Write([]byte("file contents")); err != nil {
|
|
t.Fatalf("Write(): got %v, want no error", err)
|
|
}
|
|
mpw.Close()
|
|
|
|
req, err := http.NewRequest("POST", "http://example.com", body)
|
|
if err != nil {
|
|
t.Fatalf("http.NewRequest(): got %v, want no error", err)
|
|
}
|
|
req.Header.Set("Content-Type", mpw.FormDataContentType())
|
|
|
|
_, remove, err := martian.TestContext(req, nil, nil)
|
|
if err != nil {
|
|
t.Fatalf("martian.TestContext(): got %v, want no error", err)
|
|
}
|
|
defer remove()
|
|
|
|
if err := logger.ModifyRequest(req); err != nil {
|
|
t.Fatalf("ModifyRequest(): got %v, want no error", err)
|
|
}
|
|
|
|
log := logger.Export().Log
|
|
if got, want := len(log.Entries), 1; got != want {
|
|
t.Fatalf("len(log.Entries): got %d, want %d", got, want)
|
|
}
|
|
|
|
pd := log.Entries[0].Request.PostData
|
|
if got, want := pd.MimeType, "multipart/form-data"; got != want {
|
|
t.Errorf("PostData.MimeType: got %q, want %q", got, want)
|
|
}
|
|
if got, want := len(pd.Params), 2; got != want {
|
|
t.Errorf("PostData.Params: got %d, want %d", got, want)
|
|
}
|
|
|
|
for _, p := range pd.Params {
|
|
var want Param
|
|
|
|
switch p.Name {
|
|
case "key":
|
|
want = Param{
|
|
Filename: "",
|
|
ContentType: "",
|
|
Value: "value",
|
|
}
|
|
case "file":
|
|
want = Param{
|
|
Filename: "test.txt",
|
|
ContentType: "application/octet-stream",
|
|
Value: "file contents",
|
|
}
|
|
default:
|
|
t.Errorf("pd.Params: got %q, want not to be present", p.Name)
|
|
continue
|
|
}
|
|
|
|
if got, want := p.Filename, want.Filename; got != want {
|
|
t.Errorf("p.Filename: got %q, want %q", got, want)
|
|
}
|
|
if got, want := p.ContentType, want.ContentType; got != want {
|
|
t.Errorf("p.ContentType: got %q, want %q", got, want)
|
|
}
|
|
if got, want := p.Value, want.Value; got != want {
|
|
t.Errorf("p.Value: got %q, want %q", got, want)
|
|
}
|
|
}
|
|
}
|
|
|
|
func TestModifyRequestErrorsOnDuplicateRequest(t *testing.T) {
|
|
logger := NewLogger()
|
|
|
|
req, err := http.NewRequest("POST", "http://example.com", nil)
|
|
if err != nil {
|
|
t.Fatalf("http.NewRequest(): got %v, want no error", err)
|
|
}
|
|
|
|
_, remove, err := martian.TestContext(req, nil, nil)
|
|
if err != nil {
|
|
t.Fatalf("martian.TestContext(): got %v, want no error", err)
|
|
}
|
|
defer remove()
|
|
|
|
if err := logger.ModifyRequest(req); err != nil {
|
|
t.Fatalf("ModifyRequest(): got %v, want no error", err)
|
|
}
|
|
|
|
if logger.ModifyRequest(req) == nil {
|
|
t.Fatalf("ModifyRequest(): was supposed to error")
|
|
}
|
|
}
|
|
|
|
func TestHARExportsTime(t *testing.T) {
|
|
logger := NewLogger()
|
|
|
|
req, err := http.NewRequest("GET", "http://example.com", nil)
|
|
if err != nil {
|
|
t.Fatalf("NewRequest(): got %v, want no error", err)
|
|
}
|
|
|
|
_, remove, err := martian.TestContext(req, nil, nil)
|
|
if err != nil {
|
|
t.Fatalf("martian.TestContext(): got %v, want no error", err)
|
|
}
|
|
defer remove()
|
|
|
|
if err := logger.ModifyRequest(req); err != nil {
|
|
t.Fatalf("ModifyRequest(): got %v, want no error", err)
|
|
}
|
|
|
|
// Simulate fast network round trip.
|
|
time.Sleep(10 * time.Millisecond)
|
|
|
|
res := proxyutil.NewResponse(200, nil, req)
|
|
|
|
if err := logger.ModifyResponse(res); err != nil {
|
|
t.Fatalf("ModifyResponse(): got %v, want no error", err)
|
|
}
|
|
|
|
log := logger.Export().Log
|
|
if got, want := len(log.Entries), 1; got != want {
|
|
t.Fatalf("len(log.Entries): got %v, want %v", got, want)
|
|
}
|
|
|
|
entry := log.Entries[0]
|
|
min, max := int64(10), int64(100)
|
|
if got := entry.Time; got < min || got > max {
|
|
t.Errorf("entry.Time: got %dms, want between %dms and %vms", got, min, max)
|
|
}
|
|
}
|
|
|
|
func TestReset(t *testing.T) {
|
|
logger := NewLogger()
|
|
|
|
req, err := http.NewRequest("GET", "http://example.com", nil)
|
|
if err != nil {
|
|
t.Fatalf("NewRequest(): got %v, want no error", err)
|
|
}
|
|
|
|
_, remove, err := martian.TestContext(req, nil, nil)
|
|
if err != nil {
|
|
t.Fatalf("martian.TestContext(): got %v, want no error", err)
|
|
}
|
|
defer remove()
|
|
|
|
if err := logger.ModifyRequest(req); err != nil {
|
|
t.Fatalf("ModifyRequest(): got %v, want no error", err)
|
|
}
|
|
|
|
log := logger.Export().Log
|
|
if got, want := len(log.Entries), 1; got != want {
|
|
t.Fatalf("len(log.Entries): got %d, want %d", got, want)
|
|
}
|
|
|
|
logger.Reset()
|
|
|
|
log = logger.Export().Log
|
|
if got, want := len(log.Entries), 0; got != want {
|
|
t.Errorf("len(log.Entries): got %d, want %d", got, want)
|
|
}
|
|
}
|
|
|
|
func TestExportSortsEntries(t *testing.T) {
|
|
logger := NewLogger()
|
|
count := 10
|
|
|
|
for i := 0; i < count; i++ {
|
|
req, err := http.NewRequest("GET", "http://example.com", nil)
|
|
if err != nil {
|
|
t.Fatalf("NewRequest(): got %v, want no error", err)
|
|
}
|
|
|
|
_, remove, err := martian.TestContext(req, nil, nil)
|
|
if err != nil {
|
|
t.Fatalf("martian.TestContext(): got %v, want no error", err)
|
|
}
|
|
defer remove()
|
|
|
|
if err := logger.ModifyRequest(req); err != nil {
|
|
t.Fatalf("ModifyRequest(): got %v, want no error", err)
|
|
}
|
|
}
|
|
|
|
log := logger.Export().Log
|
|
|
|
for i := 0; i < count-1; i++ {
|
|
first := log.Entries[i]
|
|
second := log.Entries[i+1]
|
|
|
|
if got, want := first.StartedDateTime, second.StartedDateTime; got.After(want) {
|
|
t.Errorf("entry.StartedDateTime: got %s, want to be before %s", got, want)
|
|
}
|
|
}
|
|
}
|
|
|
|
func TestExportIgnoresOrphanedResponse(t *testing.T) {
|
|
logger := NewLogger()
|
|
|
|
req, err := http.NewRequest("GET", "http://example.com", nil)
|
|
if err != nil {
|
|
t.Fatalf("http.NewRequest(): got %v, want no error", err)
|
|
}
|
|
|
|
_, remove, err := martian.TestContext(req, nil, nil)
|
|
if err != nil {
|
|
t.Fatalf("martian.TestContext(): got %v, want no error", err)
|
|
}
|
|
defer remove()
|
|
|
|
if err := logger.ModifyRequest(req); err != nil {
|
|
t.Fatalf("ModifyRequest(): got %v, want no error", err)
|
|
}
|
|
|
|
// Reset before the response comes back.
|
|
logger.Reset()
|
|
|
|
res := proxyutil.NewResponse(200, nil, req)
|
|
if err := logger.ModifyResponse(res); err != nil {
|
|
t.Fatalf("ModifyResponse(): got %v, want no error", err)
|
|
}
|
|
|
|
log := logger.Export().Log
|
|
if got, want := len(log.Entries), 0; got != want {
|
|
t.Errorf("len(log.Entries): got %d, want %d", got, want)
|
|
}
|
|
}
|
|
|
|
func TestExportAndResetResetsCompleteRequests(t *testing.T) {
|
|
logger := NewLogger()
|
|
|
|
req, err := http.NewRequest("GET", "http://example.com", nil)
|
|
if err != nil {
|
|
t.Fatalf("http.NewRequest(): got %v, want no error", err)
|
|
}
|
|
|
|
_, remove, err := martian.TestContext(req, nil, nil)
|
|
if err != nil {
|
|
t.Fatalf("martian.TestContext(): got %v, want no error", err)
|
|
}
|
|
defer remove()
|
|
|
|
if err := logger.ModifyRequest(req); err != nil {
|
|
t.Fatalf("ModifyRequest(): got %v, want no error", err)
|
|
}
|
|
|
|
res := proxyutil.NewResponse(200, nil, req)
|
|
if err := logger.ModifyResponse(res); err != nil {
|
|
t.Fatalf("ModifyResponse(): got %v, want no error", err)
|
|
}
|
|
|
|
logger.ExportAndReset()
|
|
|
|
log := logger.Export().Log
|
|
if got, want := len(log.Entries), 0; got != want {
|
|
t.Errorf("len(log.Entries): got %d, want %d", got, want)
|
|
}
|
|
}
|
|
|
|
func TestExportAndResetLeavesPendingRequests(t *testing.T) {
|
|
logger := NewLogger()
|
|
|
|
req, err := http.NewRequest("GET", "http://example.com", nil)
|
|
if err != nil {
|
|
t.Fatalf("http.NewRequest(): got %v, want no error", err)
|
|
}
|
|
|
|
_, remove, err := martian.TestContext(req, nil, nil)
|
|
if err != nil {
|
|
t.Fatalf("martian.TestContext(): got %v, want no error", err)
|
|
}
|
|
defer remove()
|
|
|
|
if err := logger.ModifyRequest(req); err != nil {
|
|
t.Fatalf("ModifyRequest(): got %v, want no error", err)
|
|
}
|
|
|
|
logger.ExportAndReset()
|
|
|
|
log := logger.Export().Log
|
|
if got, want := len(log.Entries), 1; got != want {
|
|
t.Errorf("len(log.Entries): got %d, want %d", got, want)
|
|
}
|
|
}
|
|
|
|
func TestExportAndResetExportsCompleteRequests(t *testing.T) {
|
|
logger := NewLogger()
|
|
|
|
req, err := http.NewRequest("GET", "http://example.com", nil)
|
|
if err != nil {
|
|
t.Fatalf("http.NewRequest(): got %v, want no error", err)
|
|
}
|
|
|
|
_, remove, err := martian.TestContext(req, nil, nil)
|
|
if err != nil {
|
|
t.Fatalf("martian.TestContext(): got %v, want no error", err)
|
|
}
|
|
defer remove()
|
|
|
|
if err := logger.ModifyRequest(req); err != nil {
|
|
t.Fatalf("ModifyRequest(): got %v, want no error", err)
|
|
}
|
|
|
|
res := proxyutil.NewResponse(200, nil, req)
|
|
if err := logger.ModifyResponse(res); err != nil {
|
|
t.Fatalf("ModifyResponse(): got %v, want no error", err)
|
|
}
|
|
|
|
log := logger.ExportAndReset().Log
|
|
if got, want := len(log.Entries), 1; got != want {
|
|
t.Errorf("len(log.Entries): got %d, want %d", got, want)
|
|
}
|
|
}
|
|
|
|
func TestExportAndResetExportsCompleteRequestsWithPendingLeft(t *testing.T) {
|
|
logger := NewLogger()
|
|
|
|
req, err := http.NewRequest("GET", "http://example.com", nil)
|
|
if err != nil {
|
|
t.Fatalf("http.NewRequest(): got %v, want no error", err)
|
|
}
|
|
|
|
_, remove, err := martian.TestContext(req, nil, nil)
|
|
if err != nil {
|
|
t.Fatalf("martian.TestContext(): got %v, want no error", err)
|
|
}
|
|
defer remove()
|
|
|
|
if err := logger.ModifyRequest(req); err != nil {
|
|
t.Fatalf("ModifyRequest(): got %v, want no error", err)
|
|
}
|
|
|
|
req, err = http.NewRequest("GET", "http://example.com", nil)
|
|
if err != nil {
|
|
t.Fatalf("http.NewRequest(): got %v, want no error", err)
|
|
}
|
|
|
|
_, remove, err = martian.TestContext(req, nil, nil)
|
|
if err != nil {
|
|
t.Fatalf("martian.TestContext(): got %v, want no error", err)
|
|
}
|
|
defer remove()
|
|
|
|
if err := logger.ModifyRequest(req); err != nil {
|
|
t.Fatalf("ModifyRequest(): got %v, want no error", err)
|
|
}
|
|
|
|
req, err = http.NewRequest("GET", "http://example.com", nil)
|
|
if err != nil {
|
|
t.Fatalf("http.NewRequest(): got %v, want no error", err)
|
|
}
|
|
|
|
_, remove, err = martian.TestContext(req, nil, nil)
|
|
if err != nil {
|
|
t.Fatalf("martian.TestContext(): got %v, want no error", err)
|
|
}
|
|
defer remove()
|
|
|
|
if err := logger.ModifyRequest(req); err != nil {
|
|
t.Fatalf("ModifyRequest(): got %v, want no error", err)
|
|
}
|
|
|
|
res := proxyutil.NewResponse(200, nil, req)
|
|
if err := logger.ModifyResponse(res); err != nil {
|
|
t.Fatalf("ModifyResponse(): got %v, want no error", err)
|
|
}
|
|
|
|
log := logger.ExportAndReset().Log
|
|
if got, want := len(log.Entries), 1; got != want {
|
|
t.Errorf("len(log.Entries): got %d, want %d", got, want)
|
|
}
|
|
|
|
log = logger.Export().Log
|
|
if got, want := len(log.Entries), 2; got != want {
|
|
t.Errorf("len(log.Entries): got %d, want %d", got, want)
|
|
}
|
|
}
|
|
|
|
func TestSkippingLogging(t *testing.T) {
|
|
req, err := http.NewRequest("GET", "http://example.com", nil)
|
|
if err != nil {
|
|
t.Fatalf("NewRequest(): got %v, want no error", err)
|
|
}
|
|
|
|
ctx, remove, err := martian.TestContext(req, nil, nil)
|
|
if err != nil {
|
|
t.Fatalf("martian.TestContext(): got %v, want no error", err)
|
|
}
|
|
defer remove()
|
|
|
|
ctx.SkipLogging()
|
|
|
|
logger := NewLogger()
|
|
|
|
if err := logger.ModifyRequest(req); err != nil {
|
|
t.Fatalf("ModifyRequest(): got %v, want no error", err)
|
|
}
|
|
|
|
res := proxyutil.NewResponse(200, nil, req)
|
|
if err := logger.ModifyResponse(res); err != nil {
|
|
t.Fatalf("ModifyResponse(): got %v, want no error", err)
|
|
}
|
|
|
|
log := logger.Export().Log
|
|
if got, want := len(log.Entries), 0; got != want {
|
|
t.Fatalf("len(log.Entries): got %d, want %d", got, want)
|
|
}
|
|
}
|
|
|
|
func TestOptionResponseBodyLogging(t *testing.T) {
|
|
req, err := http.NewRequest("GET", "http://example.com", nil)
|
|
if err != nil {
|
|
t.Fatalf("NewRequest(): got %v, want no error", err)
|
|
}
|
|
|
|
_, remove, err := martian.TestContext(req, nil, nil)
|
|
if err != nil {
|
|
t.Fatalf("martian.TestContext(): got %v, want no error", err)
|
|
}
|
|
defer remove()
|
|
|
|
bdr := strings.NewReader("{\"response\": \"body\"}")
|
|
res := proxyutil.NewResponse(200, bdr, req)
|
|
res.ContentLength = int64(bdr.Len())
|
|
res.Header.Set("Content-Type", "application/json")
|
|
|
|
logger := NewLogger()
|
|
|
|
if err := logger.ModifyRequest(req); err != nil {
|
|
t.Fatalf("ModifyRequest(): got %v, want no error", err)
|
|
}
|
|
|
|
if err := logger.ModifyResponse(res); err != nil {
|
|
t.Fatalf("ModifyResponse(): got %v, want no error", err)
|
|
}
|
|
|
|
log := logger.Export().Log
|
|
if got, want := len(log.Entries), 1; got != want {
|
|
t.Fatalf("len(log.Entries): got %d, want %d", got, want)
|
|
}
|
|
|
|
if got, want := string(log.Entries[0].Response.Content.Text), "{\"response\": \"body\"}"; got != want {
|
|
t.Fatalf("log.Entries[0].Response.Content.Text: got %s, want %s", got, want)
|
|
}
|
|
|
|
logger = NewLogger()
|
|
logger.SetOption(BodyLogging(false))
|
|
|
|
if err := logger.ModifyRequest(req); err != nil {
|
|
t.Fatalf("ModifyRequest(): got %v, want no error", err)
|
|
}
|
|
|
|
if err := logger.ModifyResponse(res); err != nil {
|
|
t.Fatalf("ModifyResponse(): got %v, want no error", err)
|
|
}
|
|
|
|
log = logger.Export().Log
|
|
if got, want := len(log.Entries), 1; got != want {
|
|
t.Fatalf("len(log.Entries): got %d, want %d", got, want)
|
|
}
|
|
|
|
if got, want := string(log.Entries[0].Response.Content.Text), ""; got != want {
|
|
t.Fatalf("log.Entries[0].Response.Content: got %s, want %s", got, want)
|
|
}
|
|
|
|
logger = NewLogger()
|
|
logger.SetOption(BodyLoggingForContentTypes("application/json"))
|
|
|
|
if err := logger.ModifyRequest(req); err != nil {
|
|
t.Fatalf("ModifyRequest(): got %v, want no error", err)
|
|
}
|
|
|
|
if err := logger.ModifyResponse(res); err != nil {
|
|
t.Fatalf("ModifyResponse(): got %v, want no error", err)
|
|
}
|
|
|
|
log = logger.Export().Log
|
|
if got, want := string(log.Entries[0].Response.Content.Text), "{\"response\": \"body\"}"; got != want {
|
|
t.Fatalf("log.Entries[0].Response.Content: got %s, want %s", got, want)
|
|
}
|
|
|
|
logger = NewLogger()
|
|
logger.SetOption(SkipBodyLoggingForContentTypes("application/json"))
|
|
|
|
if err := logger.ModifyRequest(req); err != nil {
|
|
t.Fatalf("ModifyRequest(): got %v, want no error", err)
|
|
}
|
|
|
|
if err := logger.ModifyResponse(res); err != nil {
|
|
t.Fatalf("ModifyResponse(): got %v, want no error", err)
|
|
}
|
|
|
|
log = logger.Export().Log
|
|
if got, want := string(log.Entries[0].Response.Content.Text), ""; got != want {
|
|
t.Fatalf("log.Entries[0].Response.Content: got %v, want %v", got, want)
|
|
}
|
|
}
|
|
|
|
func TestOptionRequestPostDataLogging(t *testing.T) {
|
|
logger := NewLogger()
|
|
logger.SetOption(PostDataLoggingForContentTypes("application/x-www-form-urlencoded"))
|
|
|
|
body := strings.NewReader("first=true&second=false")
|
|
req, err := http.NewRequest("POST", "http://example.com", body)
|
|
if err != nil {
|
|
t.Fatalf("http.NewRequest(): got %v, want no error", err)
|
|
}
|
|
req.Header.Set("Content-Type", "application/x-www-form-urlencoded")
|
|
|
|
_, remove, err := martian.TestContext(req, nil, nil)
|
|
if err != nil {
|
|
t.Fatalf("martian.TestContext(): got %v, want no error", err)
|
|
}
|
|
defer remove()
|
|
|
|
if err := logger.ModifyRequest(req); err != nil {
|
|
t.Fatalf("ModifyRequest(): got %v, want no error", err)
|
|
}
|
|
|
|
log := logger.Export().Log
|
|
|
|
for _, param := range log.Entries[0].Request.PostData.Params {
|
|
if param.Name == "first" {
|
|
if got, want := param.Value, "true"; got != want {
|
|
t.Fatalf("Params[%q].Value: got %s, want %s", param.Name, got, want)
|
|
}
|
|
}
|
|
|
|
if param.Name == "second" {
|
|
if got, want := param.Value, "false"; got != want {
|
|
t.Fatalf("Params[%q].Value: got %s, want %s", param.Name, got, want)
|
|
}
|
|
}
|
|
}
|
|
|
|
logger = NewLogger()
|
|
logger.SetOption(SkipPostDataLoggingForContentTypes("application/x-www-form-urlencoded"))
|
|
|
|
body = strings.NewReader("first=true&second=false")
|
|
req, err = http.NewRequest("POST", "http://example.com", body)
|
|
if err != nil {
|
|
t.Fatalf("http.NewRequest(): got %v, want no error", err)
|
|
}
|
|
req.Header.Set("Content-Type", "application/x-www-form-urlencoded")
|
|
|
|
_, remove, err = martian.TestContext(req, nil, nil)
|
|
if err != nil {
|
|
t.Fatalf("martian.TestContext(): got %v, want no error", err)
|
|
}
|
|
defer remove()
|
|
|
|
if err := logger.ModifyRequest(req); err != nil {
|
|
t.Fatalf("ModifyRequest(): got %v, want no error", err)
|
|
}
|
|
|
|
log = logger.Export().Log
|
|
if got, want := len(log.Entries[0].Request.PostData.Params), 0; got != want {
|
|
t.Fatalf("len(log.Entries[0].Request.PostData.Params): got %v, want %v", got, want)
|
|
}
|
|
}
|
|
|
|
func TestJSONMarshalPostData(t *testing.T) {
|
|
// Verify that encoding/json round-trips har.PostData with both text and binary data.
|
|
for _, text := range []string{"hello", string([]byte{150, 151, 152})} {
|
|
want := &PostData{
|
|
MimeType: "m",
|
|
Params: []Param{{Name: "n", Value: "v"}},
|
|
Text: text,
|
|
}
|
|
data, err := json.Marshal(want)
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
var got PostData
|
|
if err := json.Unmarshal(data, &got); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
if !reflect.DeepEqual(&got, want) {
|
|
t.Errorf("got %+v, want %+v", &got, want)
|
|
}
|
|
}
|
|
}
|