pax_global_header00006660000000000000000000000064142312615040014510gustar00rootroot0000000000000052 comment=ef9fc62cdc3cc5abc33d6018fe1324890bb48145 httpsnoop-1.0.3/000077500000000000000000000000001423126150400135475ustar00rootroot00000000000000httpsnoop-1.0.3/.gitignore000066400000000000000000000000001423126150400155250ustar00rootroot00000000000000httpsnoop-1.0.3/.travis.yml000066400000000000000000000000521423126150400156550ustar00rootroot00000000000000language: go go: - 1.6 - 1.7 - 1.8 httpsnoop-1.0.3/LICENSE.txt000066400000000000000000000021151423126150400153710ustar00rootroot00000000000000Copyright (c) 2016 Felix Geisendörfer (felix@debuggable.com) Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. httpsnoop-1.0.3/Makefile000066400000000000000000000001721423126150400152070ustar00rootroot00000000000000.PHONY: ci generate clean ci: clean generate go test -v ./... generate: go generate . clean: rm -rf *_generated*.go httpsnoop-1.0.3/README.md000066400000000000000000000076641423126150400150430ustar00rootroot00000000000000# httpsnoop Package httpsnoop provides an easy way to capture http related metrics (i.e. response time, bytes written, and http status code) from your application's http.Handlers. Doing this requires non-trivial wrapping of the http.ResponseWriter interface, which is also exposed for users interested in a more low-level API. [![GoDoc](https://godoc.org/github.com/felixge/httpsnoop?status.svg)](https://godoc.org/github.com/felixge/httpsnoop) [![Build Status](https://travis-ci.org/felixge/httpsnoop.svg?branch=master)](https://travis-ci.org/felixge/httpsnoop) ## Usage Example ```go // myH is your app's http handler, perhaps a http.ServeMux or similar. var myH http.Handler // wrappedH wraps myH in order to log every request. wrappedH := http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { m := httpsnoop.CaptureMetrics(myH, w, r) log.Printf( "%s %s (code=%d dt=%s written=%d)", r.Method, r.URL, m.Code, m.Duration, m.Written, ) }) http.ListenAndServe(":8080", wrappedH) ``` ## Why this package exists Instrumenting an application's http.Handler is surprisingly difficult. However if you google for e.g. "capture ResponseWriter status code" you'll find lots of advise and code examples that suggest it to be a fairly trivial undertaking. Unfortunately everything I've seen so far has a high chance of breaking your application. The main problem is that a `http.ResponseWriter` often implements additional interfaces such as `http.Flusher`, `http.CloseNotifier`, `http.Hijacker`, `http.Pusher`, and `io.ReaderFrom`. So the naive approach of just wrapping `http.ResponseWriter` in your own struct that also implements the `http.ResponseWriter` interface will hide the additional interfaces mentioned above. This has a high change of introducing subtle bugs into any non-trivial application. Another approach I've seen people take is to return a struct that implements all of the interfaces above. However, that's also problematic, because it's difficult to fake some of these interfaces behaviors when the underlying `http.ResponseWriter` doesn't have an implementation. It's also dangerous, because an application may choose to operate differently, merely because it detects the presence of these additional interfaces. This package solves this problem by checking which additional interfaces a `http.ResponseWriter` implements, returning a wrapped version implementing the exact same set of interfaces. Additionally this package properly handles edge cases such as `WriteHeader` not being called, or called more than once, as well as concurrent calls to `http.ResponseWriter` methods, and even calls happening after the wrapped `ServeHTTP` has already returned. Unfortunately this package is not perfect either. It's possible that it is still missing some interfaces provided by the go core (let me know if you find one), and it won't work for applications adding their own interfaces into the mix. You can however use `httpsnoop.Unwrap(w)` to access the underlying `http.ResponseWriter` and type-assert the result to its other interfaces. However, hopefully the explanation above has sufficiently scared you of rolling your own solution to this problem. httpsnoop may still break your application, but at least it tries to avoid it as much as possible. Anyway, the real problem here is that smuggling additional interfaces inside `http.ResponseWriter` is a problematic design choice, but it probably goes as deep as the Go language specification itself. But that's okay, I still prefer Go over the alternatives ;). ## Performance ``` BenchmarkBaseline-8 20000 94912 ns/op BenchmarkCaptureMetrics-8 20000 95461 ns/op ``` As you can see, using `CaptureMetrics` on a vanilla http.Handler introduces an overhead of ~500 ns per http request on my machine. However, the margin of error appears to be larger than that, therefor it should be reasonable to assume that the overhead introduced by `CaptureMetrics` is absolutely negligible. ## License MIT httpsnoop-1.0.3/bench_test.go000066400000000000000000000020011423126150400162050ustar00rootroot00000000000000package httpsnoop import ( "net/http" "net/http/httptest" "testing" ) func BenchmarkBaseline(b *testing.B) { benchmark(b, false) } func BenchmarkCaptureMetrics(b *testing.B) { benchmark(b, true) } func BenchmarkWrap(b *testing.B) { b.StopTimer() doneCh := make(chan struct{}, 1) h := http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { b.StartTimer() for i := 0; i < b.N; i++ { Wrap(w, Hooks{}) } doneCh <- struct{}{} }) s := httptest.NewServer(h) defer s.Close() if _, err := http.Get(s.URL); err != nil { b.Fatal(err) } <-doneCh } func benchmark(b *testing.B, captureMetrics bool) { b.StopTimer() dummyH := http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {}) h := dummyH if captureMetrics { h = http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { CaptureMetrics(dummyH, w, r) }) } s := httptest.NewServer(h) defer s.Close() b.StartTimer() for i := 0; i < b.N; i++ { _, err := http.Get(s.URL) if err != nil { b.Fatal(err) } } } httpsnoop-1.0.3/capture_metrics.go000066400000000000000000000047261423126150400173000ustar00rootroot00000000000000package httpsnoop import ( "io" "net/http" "time" ) // Metrics holds metrics captured from CaptureMetrics. type Metrics struct { // Code is the first http response code passed to the WriteHeader func of // the ResponseWriter. If no such call is made, a default code of 200 is // assumed instead. Code int // Duration is the time it took to execute the handler. Duration time.Duration // Written is the number of bytes successfully written by the Write or // ReadFrom function of the ResponseWriter. ResponseWriters may also write // data to their underlaying connection directly (e.g. headers), but those // are not tracked. Therefor the number of Written bytes will usually match // the size of the response body. Written int64 } // CaptureMetrics wraps the given hnd, executes it with the given w and r, and // returns the metrics it captured from it. func CaptureMetrics(hnd http.Handler, w http.ResponseWriter, r *http.Request) Metrics { return CaptureMetricsFn(w, func(ww http.ResponseWriter) { hnd.ServeHTTP(ww, r) }) } // CaptureMetricsFn wraps w and calls fn with the wrapped w and returns the // resulting metrics. This is very similar to CaptureMetrics (which is just // sugar on top of this func), but is a more usable interface if your // application doesn't use the Go http.Handler interface. func CaptureMetricsFn(w http.ResponseWriter, fn func(http.ResponseWriter)) Metrics { m := Metrics{Code: http.StatusOK} m.CaptureMetrics(w, fn) return m } // CaptureMetrics wraps w and calls fn with the wrapped w and updates // Metrics m with the resulting metrics. This is similar to CaptureMetricsFn, // but allows one to customize starting Metrics object. func (m *Metrics) CaptureMetrics(w http.ResponseWriter, fn func(http.ResponseWriter)) { var ( start = time.Now() headerWritten bool hooks = Hooks{ WriteHeader: func(next WriteHeaderFunc) WriteHeaderFunc { return func(code int) { next(code) if !headerWritten { m.Code = code headerWritten = true } } }, Write: func(next WriteFunc) WriteFunc { return func(p []byte) (int, error) { n, err := next(p) m.Written += int64(n) headerWritten = true return n, err } }, ReadFrom: func(next ReadFromFunc) ReadFromFunc { return func(src io.Reader) (int64, error) { n, err := next(src) headerWritten = true m.Written += n return n, err } }, } ) fn(Wrap(w, hooks)) m.Duration += time.Since(start) } httpsnoop-1.0.3/capture_metrics_test.go000066400000000000000000000047601423126150400203350ustar00rootroot00000000000000package httpsnoop import ( "io" "io/ioutil" "log" "net/http" "net/http/httptest" "os" "strings" "testing" "time" ) func TestCaptureMetrics(t *testing.T) { // Some of the edge cases tested below cause the net/http pkg to log some // messages that add a lot of noise to the `go test -v` output, so we discard // the log here. log.SetOutput(ioutil.Discard) defer log.SetOutput(os.Stderr) tests := []struct { Handler http.Handler WantDuration time.Duration WantWritten int64 WantCode int WantErr string }{ { Handler: http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {}), WantCode: http.StatusOK, }, { Handler: http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { w.WriteHeader(http.StatusBadRequest) w.WriteHeader(http.StatusNotFound) w.Write([]byte("foo")) w.Write([]byte("bar")) time.Sleep(25 * time.Millisecond) }), WantCode: http.StatusBadRequest, WantWritten: 6, WantDuration: 25 * time.Millisecond, }, { Handler: http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { w.Write([]byte("foo")) w.WriteHeader(http.StatusNotFound) }), WantCode: http.StatusOK, }, { Handler: http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { rrf := w.(io.ReaderFrom) rrf.ReadFrom(strings.NewReader("reader from is ok")) }), WantWritten: 17, WantCode: http.StatusOK, }, { Handler: http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { panic("oh no") }), WantErr: "EOF", }, } for i, test := range tests { func() { ch := make(chan Metrics, 1) h := http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { ch <- CaptureMetrics(test.Handler, w, r) }) s := httptest.NewServer(h) defer s.Close() res, err := http.Get(s.URL) if !errContains(err, test.WantErr) { t.Errorf("test %d: got=%s want=%s", i, err, test.WantErr) } if err != nil { return } defer res.Body.Close() m := <-ch if m.Code != test.WantCode { t.Errorf("test %d: got=%d want=%d", i, m.Code, test.WantCode) } else if m.Duration < test.WantDuration { t.Errorf("test %d: got=%s want=%s", i, m.Duration, test.WantDuration) } else if m.Written < test.WantWritten { t.Errorf("test %d: got=%d want=%d", i, m.Written, test.WantWritten) } }() } } func errContains(err error, s string) bool { var errS string if err == nil { errS = "" } else { errS = err.Error() } return strings.Contains(errS, s) } httpsnoop-1.0.3/codegen/000077500000000000000000000000001423126150400151535ustar00rootroot00000000000000httpsnoop-1.0.3/codegen/main.go000066400000000000000000000203631423126150400164320ustar00rootroot00000000000000package main import ( "bytes" "fmt" "go/format" "io/ioutil" "os" "strings" ) type Build struct { Suffix string Tags string Interfaces Interfaces } func (b *Build) MustBuild() { prefix := "wrap_generated_" b.Implementation().MustWriteFile(prefix + b.Suffix + ".go") b.Tests().MustWriteFile(prefix + b.Suffix + "_test.go") } func (b *Build) writeHeader(g *Generator) { g.Printf(` // +build %s // Code generated by "httpsnoop/codegen"; DO NOT EDIT package httpsnoop `, b.Tags) } func (b *Build) Implementation() *Generator { ifaces := b.Interfaces // subIfaces has all interfaces except http.ResponseWriter subIfaces := ifaces[1:] var g Generator // Package header b.writeHeader(&g) g.Printf("import (\n") g.Printf(`"net/http"` + "\n") g.Printf(`"io"` + "\n") g.Printf(`"net"` + "\n") g.Printf(`"bufio"` + "\n") g.Printf(")\n") g.Printf("\n") // Hook funcs for _, iface := range ifaces { for _, fn := range iface.Funcs { g.Printf("// %s is part of the %s interface.\n", fn.Type(), iface.Name) g.Printf("type %s func(%s) (%s)\n", fn.Type(), fn.Args, fn.Returns) g.Printf("\n") } } // Hooks struct g.Printf(` // Hooks defines a set of method interceptors for methods included in // http.ResponseWriter as well as some others. You can think of them as // middleware for the function calls they target. See Wrap for more details. type Hooks struct { `) for _, iface := range ifaces { for _, fn := range iface.Funcs { g.Printf("%s func(%s) %s\n", fn.Name, fn.Type(), fn.Type()) } } g.Printf("}\n") // Wrap func docList := make([]string, len(subIfaces)) for i, iface := range subIfaces { docList[i] = "// - " + iface.Name } g.Printf(` // Wrap returns a wrapped version of w that provides the exact same interface // as w. Specifically if w implements any combination of: // %s // // The wrapped version will implement the exact same combination. If no hooks // are set, the wrapped version also behaves exactly as w. Hooks targeting // methods not supported by w are ignored. Any other hooks will intercept the // method they target and may modify the call's arguments and/or return values. // The CaptureMetrics implementation serves as a working example for how the // hooks can be used. `, strings.Join(docList, "\n")) g.Printf("func Wrap(w http.ResponseWriter, hooks Hooks) http.ResponseWriter {\n") g.Printf("rw := &rw{w: w, h: hooks}\n") for i, iface := range subIfaces { g.Printf("_, i%d := w.(%s)\n", i, iface.Name) } g.Printf("switch {\n") combinations := 1 << uint(len(subIfaces)) for i := 0; i < combinations; i++ { conditions := make([]string, len(subIfaces)) fields := make([]string, 0, len(subIfaces)) fields = append(fields, "Unwrapper", "http.ResponseWriter") for j, iface := range subIfaces { ok := i&(1< 0 if !ok { conditions[j] = "!" } else { fields = append(fields, iface.Name) } conditions[j] += fmt.Sprintf("i%d", j) } values := make([]string, len(fields)) for i, _ := range fields { values[i] = "rw" } g.Printf("// combination %d/%d\n", i+1, combinations) g.Printf("case %s:\n", strings.Join(conditions, "&&")) fieldsS, valuesS := strings.Join(fields, "\n"), strings.Join(values, ",") g.Printf("return struct{\n%s\n}{%s}\n", fieldsS, valuesS) } g.Printf("}\n") g.Printf("panic(\"unreachable\")") g.Printf("}\n") // rw struct g.Printf(` type rw struct { w http.ResponseWriter h Hooks } func (w *rw) Unwrap() http.ResponseWriter { return w.w } `) for _, iface := range ifaces { for _, fn := range iface.Funcs { g.Printf("func (w *rw) %s(%s) (%s) {\n", fn.Name, fn.Args, fn.Returns) g.Printf("f := w.w.(%s).%s\n", iface.Name, fn.Name) g.Printf("if w.h.%s != nil {\n", fn.Name) g.Printf("f = w.h.%s(f)\n", fn.Name) g.Printf("}\n") if fn.Returns != "" { g.Printf("return ") } g.Printf("f(%s)\n", fn.Args.Names()) g.Printf("}\n") g.Printf("\n") } } g.Printf(` type Unwrapper interface { Unwrap() http.ResponseWriter } // Unwrap returns the underlying http.ResponseWriter from within zero or more // layers of httpsnoop wrappers. func Unwrap(w http.ResponseWriter) http.ResponseWriter { if rw, ok := w.(Unwrapper); ok { // recurse until rw.Unwrap() returns a non-Unwrapper return Unwrap(rw.Unwrap()) } else { return w } } `) return &g } func (b *Build) Tests() *Generator { ifaces := b.Interfaces // @TODO dedupe // subIfaces has all interfaces except http.ResponseWriter subIfaces := ifaces[1:] var g Generator // Package header b.writeHeader(&g) g.Printf("import (\n") g.Printf(`"net/http"` + "\n") g.Printf(`"io"` + "\n") g.Printf(`"testing"` + "\n") g.Printf(")\n") g.Printf("\n") // TestWrap func g.Printf("func TestWrap(t *testing.T) {\n") combinations := 1 << uint(len(subIfaces)) for i := 0; i < combinations; i++ { fields := make([]string, 0, len(subIfaces)) fields = append(fields, "http.ResponseWriter") expected := make([]bool, len(ifaces)) expected[0] = true for j, iface := range subIfaces { ok := i&(1< 0 expected[j+1] = ok if ok { fields = append(fields, iface.Name) } } g.Printf("// combination %d/%d\n", i+1, combinations) g.Printf("{\n") g.Printf(`t.Log("%s")`+"\n", strings.Join(fields, ", ")) g.Printf("inner := struct{\n%s\n}{}\n", strings.Join(fields, "\n")) g.Printf("w := Wrap(inner, Hooks{})\n") for i, iface := range ifaces { g.Printf("if _, ok := w.(%s); ok != %t {\n", iface.Name, expected[i]) g.Printf("t.Error(\"unexpected interface\");\n") g.Printf("}\n") } g.Printf(` if w, ok := w.(Unwrapper); ok { if w.Unwrap() != inner { t.Error("w.Unwrap() failed") } } else { t.Error("Unwrapper interface not implemented") }`) g.Printf("}\n") g.Printf("\n") } g.Printf("}\n") return &g } type Interfaces []*Interface type Interface struct { Name string Funcs []*InterfaceFunc } type InterfaceFunc struct { Name string Args FuncArgs Returns string } type FuncArgs []*FuncArg func (fa FuncArgs) String() string { args := make([]string, len(fa)) for i, a := range fa { args[i] = a.Name + " " + a.Type } return strings.Join(args, ", ") } func (fa FuncArgs) Names() string { args := make([]string, len(fa)) for i, a := range fa { args[i] = a.Name } return strings.Join(args, ", ") } type FuncArg struct { Name string Type string } func (fn *InterfaceFunc) Type() string { return fn.Name + "Func" } type Generator struct { buf bytes.Buffer } func (g *Generator) Printf(s string, args ...interface{}) { fmt.Fprintf(&g.buf, s, args...) } func (g *Generator) WriteFile(name string) error { src, err := g.Format() if err != nil { return fmt.Errorf("format: %s: %s:\n\n%s\n", name, err, g.Bytes()) } else if err := ioutil.WriteFile(name, src, 0644); err != nil { return err } return nil } func (g *Generator) MustWriteFile(name string) { if err := g.WriteFile(name); err != nil { fatalf("%s", err) } } func (g *Generator) Bytes() []byte { return g.buf.Bytes() } func (g *Generator) Format() ([]byte, error) { return format.Source(g.Bytes()) } func main() { ifaces := Interfaces{ { Name: "http.ResponseWriter", Funcs: []*InterfaceFunc{ {"Header", nil, "http.Header"}, {"WriteHeader", FuncArgs{{"code", "int"}}, ""}, {"Write", FuncArgs{{"b", "[]byte"}}, "int, error"}, }, }, { Name: "http.Flusher", Funcs: []*InterfaceFunc{ {"Flush", nil, ""}, }, }, { Name: "http.CloseNotifier", Funcs: []*InterfaceFunc{ {"CloseNotify", nil, "<-chan bool"}, }, }, { Name: "http.Hijacker", Funcs: []*InterfaceFunc{ {"Hijack", nil, "net.Conn, *bufio.ReadWriter, error"}, }, }, { Name: "io.ReaderFrom", Funcs: []*InterfaceFunc{ {"ReadFrom", FuncArgs{{"src", "io.Reader"}}, "int64, error"}, }, }, } builds := []Build{ { Suffix: "lt_1.8", Tags: "!go1.8", Interfaces: ifaces, }, { Suffix: "gteq_1.8", Tags: "go1.8", Interfaces: append(ifaces, &Interface{ Name: "http.Pusher", Funcs: []*InterfaceFunc{ {"Push", FuncArgs{ {"target", "string"}, {"opts", "*http.PushOptions"}, }, "error"}, }, }), }, } for _, build := range builds { build.MustBuild() } } func fatalf(s string, args ...interface{}) { fmt.Fprintf(os.Stderr, s+"\n", args...) os.Exit(1) } httpsnoop-1.0.3/docs.go000066400000000000000000000006101423126150400150230ustar00rootroot00000000000000// Package httpsnoop provides an easy way to capture http related metrics (i.e. // response time, bytes written, and http status code) from your application's // http.Handlers. // // Doing this requires non-trivial wrapping of the http.ResponseWriter // interface, which is also exposed for users interested in a more low-level // API. package httpsnoop //go:generate go run codegen/main.go httpsnoop-1.0.3/go.mod000066400000000000000000000000551423126150400146550ustar00rootroot00000000000000module github.com/felixge/httpsnoop go 1.13 httpsnoop-1.0.3/unwrap_test.go000066400000000000000000000011631423126150400164520ustar00rootroot00000000000000package httpsnoop import ( "net/http/httptest" "testing" ) func TestUnwrap(t *testing.T) { w := Wrap(httptest.NewRecorder(), Hooks{}) if _, ok := Unwrap(w).(*httptest.ResponseRecorder); !ok { t.Error("expected ResponseRecorder") } } func TestUnwrapWithoutWrap(t *testing.T) { w := httptest.NewRecorder() if _, ok := Unwrap(w).(*httptest.ResponseRecorder); !ok { t.Error("expected ResponseRecorder") } } func TestUnwrapMultipleLayers(t *testing.T) { w := Wrap(Wrap(httptest.NewRecorder(), Hooks{}), Hooks{}) if _, ok := Unwrap(w).(*httptest.ResponseRecorder); !ok { t.Error("expected ResponseRecorder") } } httpsnoop-1.0.3/wrap_generated_gteq_1.8.go000066400000000000000000000231201423126150400204710ustar00rootroot00000000000000// +build go1.8 // Code generated by "httpsnoop/codegen"; DO NOT EDIT package httpsnoop import ( "bufio" "io" "net" "net/http" ) // HeaderFunc is part of the http.ResponseWriter interface. type HeaderFunc func() http.Header // WriteHeaderFunc is part of the http.ResponseWriter interface. type WriteHeaderFunc func(code int) // WriteFunc is part of the http.ResponseWriter interface. type WriteFunc func(b []byte) (int, error) // FlushFunc is part of the http.Flusher interface. type FlushFunc func() // CloseNotifyFunc is part of the http.CloseNotifier interface. type CloseNotifyFunc func() <-chan bool // HijackFunc is part of the http.Hijacker interface. type HijackFunc func() (net.Conn, *bufio.ReadWriter, error) // ReadFromFunc is part of the io.ReaderFrom interface. type ReadFromFunc func(src io.Reader) (int64, error) // PushFunc is part of the http.Pusher interface. type PushFunc func(target string, opts *http.PushOptions) error // Hooks defines a set of method interceptors for methods included in // http.ResponseWriter as well as some others. You can think of them as // middleware for the function calls they target. See Wrap for more details. type Hooks struct { Header func(HeaderFunc) HeaderFunc WriteHeader func(WriteHeaderFunc) WriteHeaderFunc Write func(WriteFunc) WriteFunc Flush func(FlushFunc) FlushFunc CloseNotify func(CloseNotifyFunc) CloseNotifyFunc Hijack func(HijackFunc) HijackFunc ReadFrom func(ReadFromFunc) ReadFromFunc Push func(PushFunc) PushFunc } // Wrap returns a wrapped version of w that provides the exact same interface // as w. Specifically if w implements any combination of: // // - http.Flusher // - http.CloseNotifier // - http.Hijacker // - io.ReaderFrom // - http.Pusher // // The wrapped version will implement the exact same combination. If no hooks // are set, the wrapped version also behaves exactly as w. Hooks targeting // methods not supported by w are ignored. Any other hooks will intercept the // method they target and may modify the call's arguments and/or return values. // The CaptureMetrics implementation serves as a working example for how the // hooks can be used. func Wrap(w http.ResponseWriter, hooks Hooks) http.ResponseWriter { rw := &rw{w: w, h: hooks} _, i0 := w.(http.Flusher) _, i1 := w.(http.CloseNotifier) _, i2 := w.(http.Hijacker) _, i3 := w.(io.ReaderFrom) _, i4 := w.(http.Pusher) switch { // combination 1/32 case !i0 && !i1 && !i2 && !i3 && !i4: return struct { Unwrapper http.ResponseWriter }{rw, rw} // combination 2/32 case !i0 && !i1 && !i2 && !i3 && i4: return struct { Unwrapper http.ResponseWriter http.Pusher }{rw, rw, rw} // combination 3/32 case !i0 && !i1 && !i2 && i3 && !i4: return struct { Unwrapper http.ResponseWriter io.ReaderFrom }{rw, rw, rw} // combination 4/32 case !i0 && !i1 && !i2 && i3 && i4: return struct { Unwrapper http.ResponseWriter io.ReaderFrom http.Pusher }{rw, rw, rw, rw} // combination 5/32 case !i0 && !i1 && i2 && !i3 && !i4: return struct { Unwrapper http.ResponseWriter http.Hijacker }{rw, rw, rw} // combination 6/32 case !i0 && !i1 && i2 && !i3 && i4: return struct { Unwrapper http.ResponseWriter http.Hijacker http.Pusher }{rw, rw, rw, rw} // combination 7/32 case !i0 && !i1 && i2 && i3 && !i4: return struct { Unwrapper http.ResponseWriter http.Hijacker io.ReaderFrom }{rw, rw, rw, rw} // combination 8/32 case !i0 && !i1 && i2 && i3 && i4: return struct { Unwrapper http.ResponseWriter http.Hijacker io.ReaderFrom http.Pusher }{rw, rw, rw, rw, rw} // combination 9/32 case !i0 && i1 && !i2 && !i3 && !i4: return struct { Unwrapper http.ResponseWriter http.CloseNotifier }{rw, rw, rw} // combination 10/32 case !i0 && i1 && !i2 && !i3 && i4: return struct { Unwrapper http.ResponseWriter http.CloseNotifier http.Pusher }{rw, rw, rw, rw} // combination 11/32 case !i0 && i1 && !i2 && i3 && !i4: return struct { Unwrapper http.ResponseWriter http.CloseNotifier io.ReaderFrom }{rw, rw, rw, rw} // combination 12/32 case !i0 && i1 && !i2 && i3 && i4: return struct { Unwrapper http.ResponseWriter http.CloseNotifier io.ReaderFrom http.Pusher }{rw, rw, rw, rw, rw} // combination 13/32 case !i0 && i1 && i2 && !i3 && !i4: return struct { Unwrapper http.ResponseWriter http.CloseNotifier http.Hijacker }{rw, rw, rw, rw} // combination 14/32 case !i0 && i1 && i2 && !i3 && i4: return struct { Unwrapper http.ResponseWriter http.CloseNotifier http.Hijacker http.Pusher }{rw, rw, rw, rw, rw} // combination 15/32 case !i0 && i1 && i2 && i3 && !i4: return struct { Unwrapper http.ResponseWriter http.CloseNotifier http.Hijacker io.ReaderFrom }{rw, rw, rw, rw, rw} // combination 16/32 case !i0 && i1 && i2 && i3 && i4: return struct { Unwrapper http.ResponseWriter http.CloseNotifier http.Hijacker io.ReaderFrom http.Pusher }{rw, rw, rw, rw, rw, rw} // combination 17/32 case i0 && !i1 && !i2 && !i3 && !i4: return struct { Unwrapper http.ResponseWriter http.Flusher }{rw, rw, rw} // combination 18/32 case i0 && !i1 && !i2 && !i3 && i4: return struct { Unwrapper http.ResponseWriter http.Flusher http.Pusher }{rw, rw, rw, rw} // combination 19/32 case i0 && !i1 && !i2 && i3 && !i4: return struct { Unwrapper http.ResponseWriter http.Flusher io.ReaderFrom }{rw, rw, rw, rw} // combination 20/32 case i0 && !i1 && !i2 && i3 && i4: return struct { Unwrapper http.ResponseWriter http.Flusher io.ReaderFrom http.Pusher }{rw, rw, rw, rw, rw} // combination 21/32 case i0 && !i1 && i2 && !i3 && !i4: return struct { Unwrapper http.ResponseWriter http.Flusher http.Hijacker }{rw, rw, rw, rw} // combination 22/32 case i0 && !i1 && i2 && !i3 && i4: return struct { Unwrapper http.ResponseWriter http.Flusher http.Hijacker http.Pusher }{rw, rw, rw, rw, rw} // combination 23/32 case i0 && !i1 && i2 && i3 && !i4: return struct { Unwrapper http.ResponseWriter http.Flusher http.Hijacker io.ReaderFrom }{rw, rw, rw, rw, rw} // combination 24/32 case i0 && !i1 && i2 && i3 && i4: return struct { Unwrapper http.ResponseWriter http.Flusher http.Hijacker io.ReaderFrom http.Pusher }{rw, rw, rw, rw, rw, rw} // combination 25/32 case i0 && i1 && !i2 && !i3 && !i4: return struct { Unwrapper http.ResponseWriter http.Flusher http.CloseNotifier }{rw, rw, rw, rw} // combination 26/32 case i0 && i1 && !i2 && !i3 && i4: return struct { Unwrapper http.ResponseWriter http.Flusher http.CloseNotifier http.Pusher }{rw, rw, rw, rw, rw} // combination 27/32 case i0 && i1 && !i2 && i3 && !i4: return struct { Unwrapper http.ResponseWriter http.Flusher http.CloseNotifier io.ReaderFrom }{rw, rw, rw, rw, rw} // combination 28/32 case i0 && i1 && !i2 && i3 && i4: return struct { Unwrapper http.ResponseWriter http.Flusher http.CloseNotifier io.ReaderFrom http.Pusher }{rw, rw, rw, rw, rw, rw} // combination 29/32 case i0 && i1 && i2 && !i3 && !i4: return struct { Unwrapper http.ResponseWriter http.Flusher http.CloseNotifier http.Hijacker }{rw, rw, rw, rw, rw} // combination 30/32 case i0 && i1 && i2 && !i3 && i4: return struct { Unwrapper http.ResponseWriter http.Flusher http.CloseNotifier http.Hijacker http.Pusher }{rw, rw, rw, rw, rw, rw} // combination 31/32 case i0 && i1 && i2 && i3 && !i4: return struct { Unwrapper http.ResponseWriter http.Flusher http.CloseNotifier http.Hijacker io.ReaderFrom }{rw, rw, rw, rw, rw, rw} // combination 32/32 case i0 && i1 && i2 && i3 && i4: return struct { Unwrapper http.ResponseWriter http.Flusher http.CloseNotifier http.Hijacker io.ReaderFrom http.Pusher }{rw, rw, rw, rw, rw, rw, rw} } panic("unreachable") } type rw struct { w http.ResponseWriter h Hooks } func (w *rw) Unwrap() http.ResponseWriter { return w.w } func (w *rw) Header() http.Header { f := w.w.(http.ResponseWriter).Header if w.h.Header != nil { f = w.h.Header(f) } return f() } func (w *rw) WriteHeader(code int) { f := w.w.(http.ResponseWriter).WriteHeader if w.h.WriteHeader != nil { f = w.h.WriteHeader(f) } f(code) } func (w *rw) Write(b []byte) (int, error) { f := w.w.(http.ResponseWriter).Write if w.h.Write != nil { f = w.h.Write(f) } return f(b) } func (w *rw) Flush() { f := w.w.(http.Flusher).Flush if w.h.Flush != nil { f = w.h.Flush(f) } f() } func (w *rw) CloseNotify() <-chan bool { f := w.w.(http.CloseNotifier).CloseNotify if w.h.CloseNotify != nil { f = w.h.CloseNotify(f) } return f() } func (w *rw) Hijack() (net.Conn, *bufio.ReadWriter, error) { f := w.w.(http.Hijacker).Hijack if w.h.Hijack != nil { f = w.h.Hijack(f) } return f() } func (w *rw) ReadFrom(src io.Reader) (int64, error) { f := w.w.(io.ReaderFrom).ReadFrom if w.h.ReadFrom != nil { f = w.h.ReadFrom(f) } return f(src) } func (w *rw) Push(target string, opts *http.PushOptions) error { f := w.w.(http.Pusher).Push if w.h.Push != nil { f = w.h.Push(f) } return f(target, opts) } type Unwrapper interface { Unwrap() http.ResponseWriter } // Unwrap returns the underlying http.ResponseWriter from within zero or more // layers of httpsnoop wrappers. func Unwrap(w http.ResponseWriter) http.ResponseWriter { if rw, ok := w.(Unwrapper); ok { // recurse until rw.Unwrap() returns a non-Unwrapper return Unwrap(rw.Unwrap()) } else { return w } } httpsnoop-1.0.3/wrap_generated_gteq_1.8_test.go000066400000000000000000000707121423126150400215410ustar00rootroot00000000000000// +build go1.8 // Code generated by "httpsnoop/codegen"; DO NOT EDIT package httpsnoop import ( "io" "net/http" "testing" ) func TestWrap(t *testing.T) { // combination 1/32 { t.Log("http.ResponseWriter") inner := struct { http.ResponseWriter }{} w := Wrap(inner, Hooks{}) if _, ok := w.(http.ResponseWriter); ok != true { t.Error("unexpected interface") } if _, ok := w.(http.Flusher); ok != false { t.Error("unexpected interface") } if _, ok := w.(http.CloseNotifier); ok != false { t.Error("unexpected interface") } if _, ok := w.(http.Hijacker); ok != false { t.Error("unexpected interface") } if _, ok := w.(io.ReaderFrom); ok != false { t.Error("unexpected interface") } if _, ok := w.(http.Pusher); ok != false { t.Error("unexpected interface") } if w, ok := w.(Unwrapper); ok { if w.Unwrap() != inner { t.Error("w.Unwrap() failed") } } else { t.Error("Unwrapper interface not implemented") } } // combination 2/32 { t.Log("http.ResponseWriter, http.Pusher") inner := struct { http.ResponseWriter http.Pusher }{} w := Wrap(inner, Hooks{}) if _, ok := w.(http.ResponseWriter); ok != true { t.Error("unexpected interface") } if _, ok := w.(http.Flusher); ok != false { t.Error("unexpected interface") } if _, ok := w.(http.CloseNotifier); ok != false { t.Error("unexpected interface") } if _, ok := w.(http.Hijacker); ok != false { t.Error("unexpected interface") } if _, ok := w.(io.ReaderFrom); ok != false { t.Error("unexpected interface") } if _, ok := w.(http.Pusher); ok != true { t.Error("unexpected interface") } if w, ok := w.(Unwrapper); ok { if w.Unwrap() != inner { t.Error("w.Unwrap() failed") } } else { t.Error("Unwrapper interface not implemented") } } // combination 3/32 { t.Log("http.ResponseWriter, io.ReaderFrom") inner := struct { http.ResponseWriter io.ReaderFrom }{} w := Wrap(inner, Hooks{}) if _, ok := w.(http.ResponseWriter); ok != true { t.Error("unexpected interface") } if _, ok := w.(http.Flusher); ok != false { t.Error("unexpected interface") } if _, ok := w.(http.CloseNotifier); ok != false { t.Error("unexpected interface") } if _, ok := w.(http.Hijacker); ok != false { t.Error("unexpected interface") } if _, ok := w.(io.ReaderFrom); ok != true { t.Error("unexpected interface") } if _, ok := w.(http.Pusher); ok != false { t.Error("unexpected interface") } if w, ok := w.(Unwrapper); ok { if w.Unwrap() != inner { t.Error("w.Unwrap() failed") } } else { t.Error("Unwrapper interface not implemented") } } // combination 4/32 { t.Log("http.ResponseWriter, io.ReaderFrom, http.Pusher") inner := struct { http.ResponseWriter io.ReaderFrom http.Pusher }{} w := Wrap(inner, Hooks{}) if _, ok := w.(http.ResponseWriter); ok != true { t.Error("unexpected interface") } if _, ok := w.(http.Flusher); ok != false { t.Error("unexpected interface") } if _, ok := w.(http.CloseNotifier); ok != false { t.Error("unexpected interface") } if _, ok := w.(http.Hijacker); ok != false { t.Error("unexpected interface") } if _, ok := w.(io.ReaderFrom); ok != true { t.Error("unexpected interface") } if _, ok := w.(http.Pusher); ok != true { t.Error("unexpected interface") } if w, ok := w.(Unwrapper); ok { if w.Unwrap() != inner { t.Error("w.Unwrap() failed") } } else { t.Error("Unwrapper interface not implemented") } } // combination 5/32 { t.Log("http.ResponseWriter, http.Hijacker") inner := struct { http.ResponseWriter http.Hijacker }{} w := Wrap(inner, Hooks{}) if _, ok := w.(http.ResponseWriter); ok != true { t.Error("unexpected interface") } if _, ok := w.(http.Flusher); ok != false { t.Error("unexpected interface") } if _, ok := w.(http.CloseNotifier); ok != false { t.Error("unexpected interface") } if _, ok := w.(http.Hijacker); ok != true { t.Error("unexpected interface") } if _, ok := w.(io.ReaderFrom); ok != false { t.Error("unexpected interface") } if _, ok := w.(http.Pusher); ok != false { t.Error("unexpected interface") } if w, ok := w.(Unwrapper); ok { if w.Unwrap() != inner { t.Error("w.Unwrap() failed") } } else { t.Error("Unwrapper interface not implemented") } } // combination 6/32 { t.Log("http.ResponseWriter, http.Hijacker, http.Pusher") inner := struct { http.ResponseWriter http.Hijacker http.Pusher }{} w := Wrap(inner, Hooks{}) if _, ok := w.(http.ResponseWriter); ok != true { t.Error("unexpected interface") } if _, ok := w.(http.Flusher); ok != false { t.Error("unexpected interface") } if _, ok := w.(http.CloseNotifier); ok != false { t.Error("unexpected interface") } if _, ok := w.(http.Hijacker); ok != true { t.Error("unexpected interface") } if _, ok := w.(io.ReaderFrom); ok != false { t.Error("unexpected interface") } if _, ok := w.(http.Pusher); ok != true { t.Error("unexpected interface") } if w, ok := w.(Unwrapper); ok { if w.Unwrap() != inner { t.Error("w.Unwrap() failed") } } else { t.Error("Unwrapper interface not implemented") } } // combination 7/32 { t.Log("http.ResponseWriter, http.Hijacker, io.ReaderFrom") inner := struct { http.ResponseWriter http.Hijacker io.ReaderFrom }{} w := Wrap(inner, Hooks{}) if _, ok := w.(http.ResponseWriter); ok != true { t.Error("unexpected interface") } if _, ok := w.(http.Flusher); ok != false { t.Error("unexpected interface") } if _, ok := w.(http.CloseNotifier); ok != false { t.Error("unexpected interface") } if _, ok := w.(http.Hijacker); ok != true { t.Error("unexpected interface") } if _, ok := w.(io.ReaderFrom); ok != true { t.Error("unexpected interface") } if _, ok := w.(http.Pusher); ok != false { t.Error("unexpected interface") } if w, ok := w.(Unwrapper); ok { if w.Unwrap() != inner { t.Error("w.Unwrap() failed") } } else { t.Error("Unwrapper interface not implemented") } } // combination 8/32 { t.Log("http.ResponseWriter, http.Hijacker, io.ReaderFrom, http.Pusher") inner := struct { http.ResponseWriter http.Hijacker io.ReaderFrom http.Pusher }{} w := Wrap(inner, Hooks{}) if _, ok := w.(http.ResponseWriter); ok != true { t.Error("unexpected interface") } if _, ok := w.(http.Flusher); ok != false { t.Error("unexpected interface") } if _, ok := w.(http.CloseNotifier); ok != false { t.Error("unexpected interface") } if _, ok := w.(http.Hijacker); ok != true { t.Error("unexpected interface") } if _, ok := w.(io.ReaderFrom); ok != true { t.Error("unexpected interface") } if _, ok := w.(http.Pusher); ok != true { t.Error("unexpected interface") } if w, ok := w.(Unwrapper); ok { if w.Unwrap() != inner { t.Error("w.Unwrap() failed") } } else { t.Error("Unwrapper interface not implemented") } } // combination 9/32 { t.Log("http.ResponseWriter, http.CloseNotifier") inner := struct { http.ResponseWriter http.CloseNotifier }{} w := Wrap(inner, Hooks{}) if _, ok := w.(http.ResponseWriter); ok != true { t.Error("unexpected interface") } if _, ok := w.(http.Flusher); ok != false { t.Error("unexpected interface") } if _, ok := w.(http.CloseNotifier); ok != true { t.Error("unexpected interface") } if _, ok := w.(http.Hijacker); ok != false { t.Error("unexpected interface") } if _, ok := w.(io.ReaderFrom); ok != false { t.Error("unexpected interface") } if _, ok := w.(http.Pusher); ok != false { t.Error("unexpected interface") } if w, ok := w.(Unwrapper); ok { if w.Unwrap() != inner { t.Error("w.Unwrap() failed") } } else { t.Error("Unwrapper interface not implemented") } } // combination 10/32 { t.Log("http.ResponseWriter, http.CloseNotifier, http.Pusher") inner := struct { http.ResponseWriter http.CloseNotifier http.Pusher }{} w := Wrap(inner, Hooks{}) if _, ok := w.(http.ResponseWriter); ok != true { t.Error("unexpected interface") } if _, ok := w.(http.Flusher); ok != false { t.Error("unexpected interface") } if _, ok := w.(http.CloseNotifier); ok != true { t.Error("unexpected interface") } if _, ok := w.(http.Hijacker); ok != false { t.Error("unexpected interface") } if _, ok := w.(io.ReaderFrom); ok != false { t.Error("unexpected interface") } if _, ok := w.(http.Pusher); ok != true { t.Error("unexpected interface") } if w, ok := w.(Unwrapper); ok { if w.Unwrap() != inner { t.Error("w.Unwrap() failed") } } else { t.Error("Unwrapper interface not implemented") } } // combination 11/32 { t.Log("http.ResponseWriter, http.CloseNotifier, io.ReaderFrom") inner := struct { http.ResponseWriter http.CloseNotifier io.ReaderFrom }{} w := Wrap(inner, Hooks{}) if _, ok := w.(http.ResponseWriter); ok != true { t.Error("unexpected interface") } if _, ok := w.(http.Flusher); ok != false { t.Error("unexpected interface") } if _, ok := w.(http.CloseNotifier); ok != true { t.Error("unexpected interface") } if _, ok := w.(http.Hijacker); ok != false { t.Error("unexpected interface") } if _, ok := w.(io.ReaderFrom); ok != true { t.Error("unexpected interface") } if _, ok := w.(http.Pusher); ok != false { t.Error("unexpected interface") } if w, ok := w.(Unwrapper); ok { if w.Unwrap() != inner { t.Error("w.Unwrap() failed") } } else { t.Error("Unwrapper interface not implemented") } } // combination 12/32 { t.Log("http.ResponseWriter, http.CloseNotifier, io.ReaderFrom, http.Pusher") inner := struct { http.ResponseWriter http.CloseNotifier io.ReaderFrom http.Pusher }{} w := Wrap(inner, Hooks{}) if _, ok := w.(http.ResponseWriter); ok != true { t.Error("unexpected interface") } if _, ok := w.(http.Flusher); ok != false { t.Error("unexpected interface") } if _, ok := w.(http.CloseNotifier); ok != true { t.Error("unexpected interface") } if _, ok := w.(http.Hijacker); ok != false { t.Error("unexpected interface") } if _, ok := w.(io.ReaderFrom); ok != true { t.Error("unexpected interface") } if _, ok := w.(http.Pusher); ok != true { t.Error("unexpected interface") } if w, ok := w.(Unwrapper); ok { if w.Unwrap() != inner { t.Error("w.Unwrap() failed") } } else { t.Error("Unwrapper interface not implemented") } } // combination 13/32 { t.Log("http.ResponseWriter, http.CloseNotifier, http.Hijacker") inner := struct { http.ResponseWriter http.CloseNotifier http.Hijacker }{} w := Wrap(inner, Hooks{}) if _, ok := w.(http.ResponseWriter); ok != true { t.Error("unexpected interface") } if _, ok := w.(http.Flusher); ok != false { t.Error("unexpected interface") } if _, ok := w.(http.CloseNotifier); ok != true { t.Error("unexpected interface") } if _, ok := w.(http.Hijacker); ok != true { t.Error("unexpected interface") } if _, ok := w.(io.ReaderFrom); ok != false { t.Error("unexpected interface") } if _, ok := w.(http.Pusher); ok != false { t.Error("unexpected interface") } if w, ok := w.(Unwrapper); ok { if w.Unwrap() != inner { t.Error("w.Unwrap() failed") } } else { t.Error("Unwrapper interface not implemented") } } // combination 14/32 { t.Log("http.ResponseWriter, http.CloseNotifier, http.Hijacker, http.Pusher") inner := struct { http.ResponseWriter http.CloseNotifier http.Hijacker http.Pusher }{} w := Wrap(inner, Hooks{}) if _, ok := w.(http.ResponseWriter); ok != true { t.Error("unexpected interface") } if _, ok := w.(http.Flusher); ok != false { t.Error("unexpected interface") } if _, ok := w.(http.CloseNotifier); ok != true { t.Error("unexpected interface") } if _, ok := w.(http.Hijacker); ok != true { t.Error("unexpected interface") } if _, ok := w.(io.ReaderFrom); ok != false { t.Error("unexpected interface") } if _, ok := w.(http.Pusher); ok != true { t.Error("unexpected interface") } if w, ok := w.(Unwrapper); ok { if w.Unwrap() != inner { t.Error("w.Unwrap() failed") } } else { t.Error("Unwrapper interface not implemented") } } // combination 15/32 { t.Log("http.ResponseWriter, http.CloseNotifier, http.Hijacker, io.ReaderFrom") inner := struct { http.ResponseWriter http.CloseNotifier http.Hijacker io.ReaderFrom }{} w := Wrap(inner, Hooks{}) if _, ok := w.(http.ResponseWriter); ok != true { t.Error("unexpected interface") } if _, ok := w.(http.Flusher); ok != false { t.Error("unexpected interface") } if _, ok := w.(http.CloseNotifier); ok != true { t.Error("unexpected interface") } if _, ok := w.(http.Hijacker); ok != true { t.Error("unexpected interface") } if _, ok := w.(io.ReaderFrom); ok != true { t.Error("unexpected interface") } if _, ok := w.(http.Pusher); ok != false { t.Error("unexpected interface") } if w, ok := w.(Unwrapper); ok { if w.Unwrap() != inner { t.Error("w.Unwrap() failed") } } else { t.Error("Unwrapper interface not implemented") } } // combination 16/32 { t.Log("http.ResponseWriter, http.CloseNotifier, http.Hijacker, io.ReaderFrom, http.Pusher") inner := struct { http.ResponseWriter http.CloseNotifier http.Hijacker io.ReaderFrom http.Pusher }{} w := Wrap(inner, Hooks{}) if _, ok := w.(http.ResponseWriter); ok != true { t.Error("unexpected interface") } if _, ok := w.(http.Flusher); ok != false { t.Error("unexpected interface") } if _, ok := w.(http.CloseNotifier); ok != true { t.Error("unexpected interface") } if _, ok := w.(http.Hijacker); ok != true { t.Error("unexpected interface") } if _, ok := w.(io.ReaderFrom); ok != true { t.Error("unexpected interface") } if _, ok := w.(http.Pusher); ok != true { t.Error("unexpected interface") } if w, ok := w.(Unwrapper); ok { if w.Unwrap() != inner { t.Error("w.Unwrap() failed") } } else { t.Error("Unwrapper interface not implemented") } } // combination 17/32 { t.Log("http.ResponseWriter, http.Flusher") inner := struct { http.ResponseWriter http.Flusher }{} w := Wrap(inner, Hooks{}) if _, ok := w.(http.ResponseWriter); ok != true { t.Error("unexpected interface") } if _, ok := w.(http.Flusher); ok != true { t.Error("unexpected interface") } if _, ok := w.(http.CloseNotifier); ok != false { t.Error("unexpected interface") } if _, ok := w.(http.Hijacker); ok != false { t.Error("unexpected interface") } if _, ok := w.(io.ReaderFrom); ok != false { t.Error("unexpected interface") } if _, ok := w.(http.Pusher); ok != false { t.Error("unexpected interface") } if w, ok := w.(Unwrapper); ok { if w.Unwrap() != inner { t.Error("w.Unwrap() failed") } } else { t.Error("Unwrapper interface not implemented") } } // combination 18/32 { t.Log("http.ResponseWriter, http.Flusher, http.Pusher") inner := struct { http.ResponseWriter http.Flusher http.Pusher }{} w := Wrap(inner, Hooks{}) if _, ok := w.(http.ResponseWriter); ok != true { t.Error("unexpected interface") } if _, ok := w.(http.Flusher); ok != true { t.Error("unexpected interface") } if _, ok := w.(http.CloseNotifier); ok != false { t.Error("unexpected interface") } if _, ok := w.(http.Hijacker); ok != false { t.Error("unexpected interface") } if _, ok := w.(io.ReaderFrom); ok != false { t.Error("unexpected interface") } if _, ok := w.(http.Pusher); ok != true { t.Error("unexpected interface") } if w, ok := w.(Unwrapper); ok { if w.Unwrap() != inner { t.Error("w.Unwrap() failed") } } else { t.Error("Unwrapper interface not implemented") } } // combination 19/32 { t.Log("http.ResponseWriter, http.Flusher, io.ReaderFrom") inner := struct { http.ResponseWriter http.Flusher io.ReaderFrom }{} w := Wrap(inner, Hooks{}) if _, ok := w.(http.ResponseWriter); ok != true { t.Error("unexpected interface") } if _, ok := w.(http.Flusher); ok != true { t.Error("unexpected interface") } if _, ok := w.(http.CloseNotifier); ok != false { t.Error("unexpected interface") } if _, ok := w.(http.Hijacker); ok != false { t.Error("unexpected interface") } if _, ok := w.(io.ReaderFrom); ok != true { t.Error("unexpected interface") } if _, ok := w.(http.Pusher); ok != false { t.Error("unexpected interface") } if w, ok := w.(Unwrapper); ok { if w.Unwrap() != inner { t.Error("w.Unwrap() failed") } } else { t.Error("Unwrapper interface not implemented") } } // combination 20/32 { t.Log("http.ResponseWriter, http.Flusher, io.ReaderFrom, http.Pusher") inner := struct { http.ResponseWriter http.Flusher io.ReaderFrom http.Pusher }{} w := Wrap(inner, Hooks{}) if _, ok := w.(http.ResponseWriter); ok != true { t.Error("unexpected interface") } if _, ok := w.(http.Flusher); ok != true { t.Error("unexpected interface") } if _, ok := w.(http.CloseNotifier); ok != false { t.Error("unexpected interface") } if _, ok := w.(http.Hijacker); ok != false { t.Error("unexpected interface") } if _, ok := w.(io.ReaderFrom); ok != true { t.Error("unexpected interface") } if _, ok := w.(http.Pusher); ok != true { t.Error("unexpected interface") } if w, ok := w.(Unwrapper); ok { if w.Unwrap() != inner { t.Error("w.Unwrap() failed") } } else { t.Error("Unwrapper interface not implemented") } } // combination 21/32 { t.Log("http.ResponseWriter, http.Flusher, http.Hijacker") inner := struct { http.ResponseWriter http.Flusher http.Hijacker }{} w := Wrap(inner, Hooks{}) if _, ok := w.(http.ResponseWriter); ok != true { t.Error("unexpected interface") } if _, ok := w.(http.Flusher); ok != true { t.Error("unexpected interface") } if _, ok := w.(http.CloseNotifier); ok != false { t.Error("unexpected interface") } if _, ok := w.(http.Hijacker); ok != true { t.Error("unexpected interface") } if _, ok := w.(io.ReaderFrom); ok != false { t.Error("unexpected interface") } if _, ok := w.(http.Pusher); ok != false { t.Error("unexpected interface") } if w, ok := w.(Unwrapper); ok { if w.Unwrap() != inner { t.Error("w.Unwrap() failed") } } else { t.Error("Unwrapper interface not implemented") } } // combination 22/32 { t.Log("http.ResponseWriter, http.Flusher, http.Hijacker, http.Pusher") inner := struct { http.ResponseWriter http.Flusher http.Hijacker http.Pusher }{} w := Wrap(inner, Hooks{}) if _, ok := w.(http.ResponseWriter); ok != true { t.Error("unexpected interface") } if _, ok := w.(http.Flusher); ok != true { t.Error("unexpected interface") } if _, ok := w.(http.CloseNotifier); ok != false { t.Error("unexpected interface") } if _, ok := w.(http.Hijacker); ok != true { t.Error("unexpected interface") } if _, ok := w.(io.ReaderFrom); ok != false { t.Error("unexpected interface") } if _, ok := w.(http.Pusher); ok != true { t.Error("unexpected interface") } if w, ok := w.(Unwrapper); ok { if w.Unwrap() != inner { t.Error("w.Unwrap() failed") } } else { t.Error("Unwrapper interface not implemented") } } // combination 23/32 { t.Log("http.ResponseWriter, http.Flusher, http.Hijacker, io.ReaderFrom") inner := struct { http.ResponseWriter http.Flusher http.Hijacker io.ReaderFrom }{} w := Wrap(inner, Hooks{}) if _, ok := w.(http.ResponseWriter); ok != true { t.Error("unexpected interface") } if _, ok := w.(http.Flusher); ok != true { t.Error("unexpected interface") } if _, ok := w.(http.CloseNotifier); ok != false { t.Error("unexpected interface") } if _, ok := w.(http.Hijacker); ok != true { t.Error("unexpected interface") } if _, ok := w.(io.ReaderFrom); ok != true { t.Error("unexpected interface") } if _, ok := w.(http.Pusher); ok != false { t.Error("unexpected interface") } if w, ok := w.(Unwrapper); ok { if w.Unwrap() != inner { t.Error("w.Unwrap() failed") } } else { t.Error("Unwrapper interface not implemented") } } // combination 24/32 { t.Log("http.ResponseWriter, http.Flusher, http.Hijacker, io.ReaderFrom, http.Pusher") inner := struct { http.ResponseWriter http.Flusher http.Hijacker io.ReaderFrom http.Pusher }{} w := Wrap(inner, Hooks{}) if _, ok := w.(http.ResponseWriter); ok != true { t.Error("unexpected interface") } if _, ok := w.(http.Flusher); ok != true { t.Error("unexpected interface") } if _, ok := w.(http.CloseNotifier); ok != false { t.Error("unexpected interface") } if _, ok := w.(http.Hijacker); ok != true { t.Error("unexpected interface") } if _, ok := w.(io.ReaderFrom); ok != true { t.Error("unexpected interface") } if _, ok := w.(http.Pusher); ok != true { t.Error("unexpected interface") } if w, ok := w.(Unwrapper); ok { if w.Unwrap() != inner { t.Error("w.Unwrap() failed") } } else { t.Error("Unwrapper interface not implemented") } } // combination 25/32 { t.Log("http.ResponseWriter, http.Flusher, http.CloseNotifier") inner := struct { http.ResponseWriter http.Flusher http.CloseNotifier }{} w := Wrap(inner, Hooks{}) if _, ok := w.(http.ResponseWriter); ok != true { t.Error("unexpected interface") } if _, ok := w.(http.Flusher); ok != true { t.Error("unexpected interface") } if _, ok := w.(http.CloseNotifier); ok != true { t.Error("unexpected interface") } if _, ok := w.(http.Hijacker); ok != false { t.Error("unexpected interface") } if _, ok := w.(io.ReaderFrom); ok != false { t.Error("unexpected interface") } if _, ok := w.(http.Pusher); ok != false { t.Error("unexpected interface") } if w, ok := w.(Unwrapper); ok { if w.Unwrap() != inner { t.Error("w.Unwrap() failed") } } else { t.Error("Unwrapper interface not implemented") } } // combination 26/32 { t.Log("http.ResponseWriter, http.Flusher, http.CloseNotifier, http.Pusher") inner := struct { http.ResponseWriter http.Flusher http.CloseNotifier http.Pusher }{} w := Wrap(inner, Hooks{}) if _, ok := w.(http.ResponseWriter); ok != true { t.Error("unexpected interface") } if _, ok := w.(http.Flusher); ok != true { t.Error("unexpected interface") } if _, ok := w.(http.CloseNotifier); ok != true { t.Error("unexpected interface") } if _, ok := w.(http.Hijacker); ok != false { t.Error("unexpected interface") } if _, ok := w.(io.ReaderFrom); ok != false { t.Error("unexpected interface") } if _, ok := w.(http.Pusher); ok != true { t.Error("unexpected interface") } if w, ok := w.(Unwrapper); ok { if w.Unwrap() != inner { t.Error("w.Unwrap() failed") } } else { t.Error("Unwrapper interface not implemented") } } // combination 27/32 { t.Log("http.ResponseWriter, http.Flusher, http.CloseNotifier, io.ReaderFrom") inner := struct { http.ResponseWriter http.Flusher http.CloseNotifier io.ReaderFrom }{} w := Wrap(inner, Hooks{}) if _, ok := w.(http.ResponseWriter); ok != true { t.Error("unexpected interface") } if _, ok := w.(http.Flusher); ok != true { t.Error("unexpected interface") } if _, ok := w.(http.CloseNotifier); ok != true { t.Error("unexpected interface") } if _, ok := w.(http.Hijacker); ok != false { t.Error("unexpected interface") } if _, ok := w.(io.ReaderFrom); ok != true { t.Error("unexpected interface") } if _, ok := w.(http.Pusher); ok != false { t.Error("unexpected interface") } if w, ok := w.(Unwrapper); ok { if w.Unwrap() != inner { t.Error("w.Unwrap() failed") } } else { t.Error("Unwrapper interface not implemented") } } // combination 28/32 { t.Log("http.ResponseWriter, http.Flusher, http.CloseNotifier, io.ReaderFrom, http.Pusher") inner := struct { http.ResponseWriter http.Flusher http.CloseNotifier io.ReaderFrom http.Pusher }{} w := Wrap(inner, Hooks{}) if _, ok := w.(http.ResponseWriter); ok != true { t.Error("unexpected interface") } if _, ok := w.(http.Flusher); ok != true { t.Error("unexpected interface") } if _, ok := w.(http.CloseNotifier); ok != true { t.Error("unexpected interface") } if _, ok := w.(http.Hijacker); ok != false { t.Error("unexpected interface") } if _, ok := w.(io.ReaderFrom); ok != true { t.Error("unexpected interface") } if _, ok := w.(http.Pusher); ok != true { t.Error("unexpected interface") } if w, ok := w.(Unwrapper); ok { if w.Unwrap() != inner { t.Error("w.Unwrap() failed") } } else { t.Error("Unwrapper interface not implemented") } } // combination 29/32 { t.Log("http.ResponseWriter, http.Flusher, http.CloseNotifier, http.Hijacker") inner := struct { http.ResponseWriter http.Flusher http.CloseNotifier http.Hijacker }{} w := Wrap(inner, Hooks{}) if _, ok := w.(http.ResponseWriter); ok != true { t.Error("unexpected interface") } if _, ok := w.(http.Flusher); ok != true { t.Error("unexpected interface") } if _, ok := w.(http.CloseNotifier); ok != true { t.Error("unexpected interface") } if _, ok := w.(http.Hijacker); ok != true { t.Error("unexpected interface") } if _, ok := w.(io.ReaderFrom); ok != false { t.Error("unexpected interface") } if _, ok := w.(http.Pusher); ok != false { t.Error("unexpected interface") } if w, ok := w.(Unwrapper); ok { if w.Unwrap() != inner { t.Error("w.Unwrap() failed") } } else { t.Error("Unwrapper interface not implemented") } } // combination 30/32 { t.Log("http.ResponseWriter, http.Flusher, http.CloseNotifier, http.Hijacker, http.Pusher") inner := struct { http.ResponseWriter http.Flusher http.CloseNotifier http.Hijacker http.Pusher }{} w := Wrap(inner, Hooks{}) if _, ok := w.(http.ResponseWriter); ok != true { t.Error("unexpected interface") } if _, ok := w.(http.Flusher); ok != true { t.Error("unexpected interface") } if _, ok := w.(http.CloseNotifier); ok != true { t.Error("unexpected interface") } if _, ok := w.(http.Hijacker); ok != true { t.Error("unexpected interface") } if _, ok := w.(io.ReaderFrom); ok != false { t.Error("unexpected interface") } if _, ok := w.(http.Pusher); ok != true { t.Error("unexpected interface") } if w, ok := w.(Unwrapper); ok { if w.Unwrap() != inner { t.Error("w.Unwrap() failed") } } else { t.Error("Unwrapper interface not implemented") } } // combination 31/32 { t.Log("http.ResponseWriter, http.Flusher, http.CloseNotifier, http.Hijacker, io.ReaderFrom") inner := struct { http.ResponseWriter http.Flusher http.CloseNotifier http.Hijacker io.ReaderFrom }{} w := Wrap(inner, Hooks{}) if _, ok := w.(http.ResponseWriter); ok != true { t.Error("unexpected interface") } if _, ok := w.(http.Flusher); ok != true { t.Error("unexpected interface") } if _, ok := w.(http.CloseNotifier); ok != true { t.Error("unexpected interface") } if _, ok := w.(http.Hijacker); ok != true { t.Error("unexpected interface") } if _, ok := w.(io.ReaderFrom); ok != true { t.Error("unexpected interface") } if _, ok := w.(http.Pusher); ok != false { t.Error("unexpected interface") } if w, ok := w.(Unwrapper); ok { if w.Unwrap() != inner { t.Error("w.Unwrap() failed") } } else { t.Error("Unwrapper interface not implemented") } } // combination 32/32 { t.Log("http.ResponseWriter, http.Flusher, http.CloseNotifier, http.Hijacker, io.ReaderFrom, http.Pusher") inner := struct { http.ResponseWriter http.Flusher http.CloseNotifier http.Hijacker io.ReaderFrom http.Pusher }{} w := Wrap(inner, Hooks{}) if _, ok := w.(http.ResponseWriter); ok != true { t.Error("unexpected interface") } if _, ok := w.(http.Flusher); ok != true { t.Error("unexpected interface") } if _, ok := w.(http.CloseNotifier); ok != true { t.Error("unexpected interface") } if _, ok := w.(http.Hijacker); ok != true { t.Error("unexpected interface") } if _, ok := w.(io.ReaderFrom); ok != true { t.Error("unexpected interface") } if _, ok := w.(http.Pusher); ok != true { t.Error("unexpected interface") } if w, ok := w.(Unwrapper); ok { if w.Unwrap() != inner { t.Error("w.Unwrap() failed") } } else { t.Error("Unwrapper interface not implemented") } } } httpsnoop-1.0.3/wrap_generated_lt_1.8.go000066400000000000000000000143121423126150400201530ustar00rootroot00000000000000// +build !go1.8 // Code generated by "httpsnoop/codegen"; DO NOT EDIT package httpsnoop import ( "bufio" "io" "net" "net/http" ) // HeaderFunc is part of the http.ResponseWriter interface. type HeaderFunc func() http.Header // WriteHeaderFunc is part of the http.ResponseWriter interface. type WriteHeaderFunc func(code int) // WriteFunc is part of the http.ResponseWriter interface. type WriteFunc func(b []byte) (int, error) // FlushFunc is part of the http.Flusher interface. type FlushFunc func() // CloseNotifyFunc is part of the http.CloseNotifier interface. type CloseNotifyFunc func() <-chan bool // HijackFunc is part of the http.Hijacker interface. type HijackFunc func() (net.Conn, *bufio.ReadWriter, error) // ReadFromFunc is part of the io.ReaderFrom interface. type ReadFromFunc func(src io.Reader) (int64, error) // Hooks defines a set of method interceptors for methods included in // http.ResponseWriter as well as some others. You can think of them as // middleware for the function calls they target. See Wrap for more details. type Hooks struct { Header func(HeaderFunc) HeaderFunc WriteHeader func(WriteHeaderFunc) WriteHeaderFunc Write func(WriteFunc) WriteFunc Flush func(FlushFunc) FlushFunc CloseNotify func(CloseNotifyFunc) CloseNotifyFunc Hijack func(HijackFunc) HijackFunc ReadFrom func(ReadFromFunc) ReadFromFunc } // Wrap returns a wrapped version of w that provides the exact same interface // as w. Specifically if w implements any combination of: // // - http.Flusher // - http.CloseNotifier // - http.Hijacker // - io.ReaderFrom // // The wrapped version will implement the exact same combination. If no hooks // are set, the wrapped version also behaves exactly as w. Hooks targeting // methods not supported by w are ignored. Any other hooks will intercept the // method they target and may modify the call's arguments and/or return values. // The CaptureMetrics implementation serves as a working example for how the // hooks can be used. func Wrap(w http.ResponseWriter, hooks Hooks) http.ResponseWriter { rw := &rw{w: w, h: hooks} _, i0 := w.(http.Flusher) _, i1 := w.(http.CloseNotifier) _, i2 := w.(http.Hijacker) _, i3 := w.(io.ReaderFrom) switch { // combination 1/16 case !i0 && !i1 && !i2 && !i3: return struct { Unwrapper http.ResponseWriter }{rw, rw} // combination 2/16 case !i0 && !i1 && !i2 && i3: return struct { Unwrapper http.ResponseWriter io.ReaderFrom }{rw, rw, rw} // combination 3/16 case !i0 && !i1 && i2 && !i3: return struct { Unwrapper http.ResponseWriter http.Hijacker }{rw, rw, rw} // combination 4/16 case !i0 && !i1 && i2 && i3: return struct { Unwrapper http.ResponseWriter http.Hijacker io.ReaderFrom }{rw, rw, rw, rw} // combination 5/16 case !i0 && i1 && !i2 && !i3: return struct { Unwrapper http.ResponseWriter http.CloseNotifier }{rw, rw, rw} // combination 6/16 case !i0 && i1 && !i2 && i3: return struct { Unwrapper http.ResponseWriter http.CloseNotifier io.ReaderFrom }{rw, rw, rw, rw} // combination 7/16 case !i0 && i1 && i2 && !i3: return struct { Unwrapper http.ResponseWriter http.CloseNotifier http.Hijacker }{rw, rw, rw, rw} // combination 8/16 case !i0 && i1 && i2 && i3: return struct { Unwrapper http.ResponseWriter http.CloseNotifier http.Hijacker io.ReaderFrom }{rw, rw, rw, rw, rw} // combination 9/16 case i0 && !i1 && !i2 && !i3: return struct { Unwrapper http.ResponseWriter http.Flusher }{rw, rw, rw} // combination 10/16 case i0 && !i1 && !i2 && i3: return struct { Unwrapper http.ResponseWriter http.Flusher io.ReaderFrom }{rw, rw, rw, rw} // combination 11/16 case i0 && !i1 && i2 && !i3: return struct { Unwrapper http.ResponseWriter http.Flusher http.Hijacker }{rw, rw, rw, rw} // combination 12/16 case i0 && !i1 && i2 && i3: return struct { Unwrapper http.ResponseWriter http.Flusher http.Hijacker io.ReaderFrom }{rw, rw, rw, rw, rw} // combination 13/16 case i0 && i1 && !i2 && !i3: return struct { Unwrapper http.ResponseWriter http.Flusher http.CloseNotifier }{rw, rw, rw, rw} // combination 14/16 case i0 && i1 && !i2 && i3: return struct { Unwrapper http.ResponseWriter http.Flusher http.CloseNotifier io.ReaderFrom }{rw, rw, rw, rw, rw} // combination 15/16 case i0 && i1 && i2 && !i3: return struct { Unwrapper http.ResponseWriter http.Flusher http.CloseNotifier http.Hijacker }{rw, rw, rw, rw, rw} // combination 16/16 case i0 && i1 && i2 && i3: return struct { Unwrapper http.ResponseWriter http.Flusher http.CloseNotifier http.Hijacker io.ReaderFrom }{rw, rw, rw, rw, rw, rw} } panic("unreachable") } type rw struct { w http.ResponseWriter h Hooks } func (w *rw) Unwrap() http.ResponseWriter { return w.w } func (w *rw) Header() http.Header { f := w.w.(http.ResponseWriter).Header if w.h.Header != nil { f = w.h.Header(f) } return f() } func (w *rw) WriteHeader(code int) { f := w.w.(http.ResponseWriter).WriteHeader if w.h.WriteHeader != nil { f = w.h.WriteHeader(f) } f(code) } func (w *rw) Write(b []byte) (int, error) { f := w.w.(http.ResponseWriter).Write if w.h.Write != nil { f = w.h.Write(f) } return f(b) } func (w *rw) Flush() { f := w.w.(http.Flusher).Flush if w.h.Flush != nil { f = w.h.Flush(f) } f() } func (w *rw) CloseNotify() <-chan bool { f := w.w.(http.CloseNotifier).CloseNotify if w.h.CloseNotify != nil { f = w.h.CloseNotify(f) } return f() } func (w *rw) Hijack() (net.Conn, *bufio.ReadWriter, error) { f := w.w.(http.Hijacker).Hijack if w.h.Hijack != nil { f = w.h.Hijack(f) } return f() } func (w *rw) ReadFrom(src io.Reader) (int64, error) { f := w.w.(io.ReaderFrom).ReadFrom if w.h.ReadFrom != nil { f = w.h.ReadFrom(f) } return f(src) } type Unwrapper interface { Unwrap() http.ResponseWriter } // Unwrap returns the underlying http.ResponseWriter from within zero or more // layers of httpsnoop wrappers. func Unwrap(w http.ResponseWriter) http.ResponseWriter { if rw, ok := w.(Unwrapper); ok { // recurse until rw.Unwrap() returns a non-Unwrapper return Unwrap(rw.Unwrap()) } else { return w } } httpsnoop-1.0.3/wrap_generated_lt_1.8_test.go000066400000000000000000000314331423126150400212150ustar00rootroot00000000000000// +build !go1.8 // Code generated by "httpsnoop/codegen"; DO NOT EDIT package httpsnoop import ( "io" "net/http" "testing" ) func TestWrap(t *testing.T) { // combination 1/16 { t.Log("http.ResponseWriter") inner := struct { http.ResponseWriter }{} w := Wrap(inner, Hooks{}) if _, ok := w.(http.ResponseWriter); ok != true { t.Error("unexpected interface") } if _, ok := w.(http.Flusher); ok != false { t.Error("unexpected interface") } if _, ok := w.(http.CloseNotifier); ok != false { t.Error("unexpected interface") } if _, ok := w.(http.Hijacker); ok != false { t.Error("unexpected interface") } if _, ok := w.(io.ReaderFrom); ok != false { t.Error("unexpected interface") } if w, ok := w.(Unwrapper); ok { if w.Unwrap() != inner { t.Error("w.Unwrap() failed") } } else { t.Error("Unwrapper interface not implemented") } } // combination 2/16 { t.Log("http.ResponseWriter, io.ReaderFrom") inner := struct { http.ResponseWriter io.ReaderFrom }{} w := Wrap(inner, Hooks{}) if _, ok := w.(http.ResponseWriter); ok != true { t.Error("unexpected interface") } if _, ok := w.(http.Flusher); ok != false { t.Error("unexpected interface") } if _, ok := w.(http.CloseNotifier); ok != false { t.Error("unexpected interface") } if _, ok := w.(http.Hijacker); ok != false { t.Error("unexpected interface") } if _, ok := w.(io.ReaderFrom); ok != true { t.Error("unexpected interface") } if w, ok := w.(Unwrapper); ok { if w.Unwrap() != inner { t.Error("w.Unwrap() failed") } } else { t.Error("Unwrapper interface not implemented") } } // combination 3/16 { t.Log("http.ResponseWriter, http.Hijacker") inner := struct { http.ResponseWriter http.Hijacker }{} w := Wrap(inner, Hooks{}) if _, ok := w.(http.ResponseWriter); ok != true { t.Error("unexpected interface") } if _, ok := w.(http.Flusher); ok != false { t.Error("unexpected interface") } if _, ok := w.(http.CloseNotifier); ok != false { t.Error("unexpected interface") } if _, ok := w.(http.Hijacker); ok != true { t.Error("unexpected interface") } if _, ok := w.(io.ReaderFrom); ok != false { t.Error("unexpected interface") } if w, ok := w.(Unwrapper); ok { if w.Unwrap() != inner { t.Error("w.Unwrap() failed") } } else { t.Error("Unwrapper interface not implemented") } } // combination 4/16 { t.Log("http.ResponseWriter, http.Hijacker, io.ReaderFrom") inner := struct { http.ResponseWriter http.Hijacker io.ReaderFrom }{} w := Wrap(inner, Hooks{}) if _, ok := w.(http.ResponseWriter); ok != true { t.Error("unexpected interface") } if _, ok := w.(http.Flusher); ok != false { t.Error("unexpected interface") } if _, ok := w.(http.CloseNotifier); ok != false { t.Error("unexpected interface") } if _, ok := w.(http.Hijacker); ok != true { t.Error("unexpected interface") } if _, ok := w.(io.ReaderFrom); ok != true { t.Error("unexpected interface") } if w, ok := w.(Unwrapper); ok { if w.Unwrap() != inner { t.Error("w.Unwrap() failed") } } else { t.Error("Unwrapper interface not implemented") } } // combination 5/16 { t.Log("http.ResponseWriter, http.CloseNotifier") inner := struct { http.ResponseWriter http.CloseNotifier }{} w := Wrap(inner, Hooks{}) if _, ok := w.(http.ResponseWriter); ok != true { t.Error("unexpected interface") } if _, ok := w.(http.Flusher); ok != false { t.Error("unexpected interface") } if _, ok := w.(http.CloseNotifier); ok != true { t.Error("unexpected interface") } if _, ok := w.(http.Hijacker); ok != false { t.Error("unexpected interface") } if _, ok := w.(io.ReaderFrom); ok != false { t.Error("unexpected interface") } if w, ok := w.(Unwrapper); ok { if w.Unwrap() != inner { t.Error("w.Unwrap() failed") } } else { t.Error("Unwrapper interface not implemented") } } // combination 6/16 { t.Log("http.ResponseWriter, http.CloseNotifier, io.ReaderFrom") inner := struct { http.ResponseWriter http.CloseNotifier io.ReaderFrom }{} w := Wrap(inner, Hooks{}) if _, ok := w.(http.ResponseWriter); ok != true { t.Error("unexpected interface") } if _, ok := w.(http.Flusher); ok != false { t.Error("unexpected interface") } if _, ok := w.(http.CloseNotifier); ok != true { t.Error("unexpected interface") } if _, ok := w.(http.Hijacker); ok != false { t.Error("unexpected interface") } if _, ok := w.(io.ReaderFrom); ok != true { t.Error("unexpected interface") } if w, ok := w.(Unwrapper); ok { if w.Unwrap() != inner { t.Error("w.Unwrap() failed") } } else { t.Error("Unwrapper interface not implemented") } } // combination 7/16 { t.Log("http.ResponseWriter, http.CloseNotifier, http.Hijacker") inner := struct { http.ResponseWriter http.CloseNotifier http.Hijacker }{} w := Wrap(inner, Hooks{}) if _, ok := w.(http.ResponseWriter); ok != true { t.Error("unexpected interface") } if _, ok := w.(http.Flusher); ok != false { t.Error("unexpected interface") } if _, ok := w.(http.CloseNotifier); ok != true { t.Error("unexpected interface") } if _, ok := w.(http.Hijacker); ok != true { t.Error("unexpected interface") } if _, ok := w.(io.ReaderFrom); ok != false { t.Error("unexpected interface") } if w, ok := w.(Unwrapper); ok { if w.Unwrap() != inner { t.Error("w.Unwrap() failed") } } else { t.Error("Unwrapper interface not implemented") } } // combination 8/16 { t.Log("http.ResponseWriter, http.CloseNotifier, http.Hijacker, io.ReaderFrom") inner := struct { http.ResponseWriter http.CloseNotifier http.Hijacker io.ReaderFrom }{} w := Wrap(inner, Hooks{}) if _, ok := w.(http.ResponseWriter); ok != true { t.Error("unexpected interface") } if _, ok := w.(http.Flusher); ok != false { t.Error("unexpected interface") } if _, ok := w.(http.CloseNotifier); ok != true { t.Error("unexpected interface") } if _, ok := w.(http.Hijacker); ok != true { t.Error("unexpected interface") } if _, ok := w.(io.ReaderFrom); ok != true { t.Error("unexpected interface") } if w, ok := w.(Unwrapper); ok { if w.Unwrap() != inner { t.Error("w.Unwrap() failed") } } else { t.Error("Unwrapper interface not implemented") } } // combination 9/16 { t.Log("http.ResponseWriter, http.Flusher") inner := struct { http.ResponseWriter http.Flusher }{} w := Wrap(inner, Hooks{}) if _, ok := w.(http.ResponseWriter); ok != true { t.Error("unexpected interface") } if _, ok := w.(http.Flusher); ok != true { t.Error("unexpected interface") } if _, ok := w.(http.CloseNotifier); ok != false { t.Error("unexpected interface") } if _, ok := w.(http.Hijacker); ok != false { t.Error("unexpected interface") } if _, ok := w.(io.ReaderFrom); ok != false { t.Error("unexpected interface") } if w, ok := w.(Unwrapper); ok { if w.Unwrap() != inner { t.Error("w.Unwrap() failed") } } else { t.Error("Unwrapper interface not implemented") } } // combination 10/16 { t.Log("http.ResponseWriter, http.Flusher, io.ReaderFrom") inner := struct { http.ResponseWriter http.Flusher io.ReaderFrom }{} w := Wrap(inner, Hooks{}) if _, ok := w.(http.ResponseWriter); ok != true { t.Error("unexpected interface") } if _, ok := w.(http.Flusher); ok != true { t.Error("unexpected interface") } if _, ok := w.(http.CloseNotifier); ok != false { t.Error("unexpected interface") } if _, ok := w.(http.Hijacker); ok != false { t.Error("unexpected interface") } if _, ok := w.(io.ReaderFrom); ok != true { t.Error("unexpected interface") } if w, ok := w.(Unwrapper); ok { if w.Unwrap() != inner { t.Error("w.Unwrap() failed") } } else { t.Error("Unwrapper interface not implemented") } } // combination 11/16 { t.Log("http.ResponseWriter, http.Flusher, http.Hijacker") inner := struct { http.ResponseWriter http.Flusher http.Hijacker }{} w := Wrap(inner, Hooks{}) if _, ok := w.(http.ResponseWriter); ok != true { t.Error("unexpected interface") } if _, ok := w.(http.Flusher); ok != true { t.Error("unexpected interface") } if _, ok := w.(http.CloseNotifier); ok != false { t.Error("unexpected interface") } if _, ok := w.(http.Hijacker); ok != true { t.Error("unexpected interface") } if _, ok := w.(io.ReaderFrom); ok != false { t.Error("unexpected interface") } if w, ok := w.(Unwrapper); ok { if w.Unwrap() != inner { t.Error("w.Unwrap() failed") } } else { t.Error("Unwrapper interface not implemented") } } // combination 12/16 { t.Log("http.ResponseWriter, http.Flusher, http.Hijacker, io.ReaderFrom") inner := struct { http.ResponseWriter http.Flusher http.Hijacker io.ReaderFrom }{} w := Wrap(inner, Hooks{}) if _, ok := w.(http.ResponseWriter); ok != true { t.Error("unexpected interface") } if _, ok := w.(http.Flusher); ok != true { t.Error("unexpected interface") } if _, ok := w.(http.CloseNotifier); ok != false { t.Error("unexpected interface") } if _, ok := w.(http.Hijacker); ok != true { t.Error("unexpected interface") } if _, ok := w.(io.ReaderFrom); ok != true { t.Error("unexpected interface") } if w, ok := w.(Unwrapper); ok { if w.Unwrap() != inner { t.Error("w.Unwrap() failed") } } else { t.Error("Unwrapper interface not implemented") } } // combination 13/16 { t.Log("http.ResponseWriter, http.Flusher, http.CloseNotifier") inner := struct { http.ResponseWriter http.Flusher http.CloseNotifier }{} w := Wrap(inner, Hooks{}) if _, ok := w.(http.ResponseWriter); ok != true { t.Error("unexpected interface") } if _, ok := w.(http.Flusher); ok != true { t.Error("unexpected interface") } if _, ok := w.(http.CloseNotifier); ok != true { t.Error("unexpected interface") } if _, ok := w.(http.Hijacker); ok != false { t.Error("unexpected interface") } if _, ok := w.(io.ReaderFrom); ok != false { t.Error("unexpected interface") } if w, ok := w.(Unwrapper); ok { if w.Unwrap() != inner { t.Error("w.Unwrap() failed") } } else { t.Error("Unwrapper interface not implemented") } } // combination 14/16 { t.Log("http.ResponseWriter, http.Flusher, http.CloseNotifier, io.ReaderFrom") inner := struct { http.ResponseWriter http.Flusher http.CloseNotifier io.ReaderFrom }{} w := Wrap(inner, Hooks{}) if _, ok := w.(http.ResponseWriter); ok != true { t.Error("unexpected interface") } if _, ok := w.(http.Flusher); ok != true { t.Error("unexpected interface") } if _, ok := w.(http.CloseNotifier); ok != true { t.Error("unexpected interface") } if _, ok := w.(http.Hijacker); ok != false { t.Error("unexpected interface") } if _, ok := w.(io.ReaderFrom); ok != true { t.Error("unexpected interface") } if w, ok := w.(Unwrapper); ok { if w.Unwrap() != inner { t.Error("w.Unwrap() failed") } } else { t.Error("Unwrapper interface not implemented") } } // combination 15/16 { t.Log("http.ResponseWriter, http.Flusher, http.CloseNotifier, http.Hijacker") inner := struct { http.ResponseWriter http.Flusher http.CloseNotifier http.Hijacker }{} w := Wrap(inner, Hooks{}) if _, ok := w.(http.ResponseWriter); ok != true { t.Error("unexpected interface") } if _, ok := w.(http.Flusher); ok != true { t.Error("unexpected interface") } if _, ok := w.(http.CloseNotifier); ok != true { t.Error("unexpected interface") } if _, ok := w.(http.Hijacker); ok != true { t.Error("unexpected interface") } if _, ok := w.(io.ReaderFrom); ok != false { t.Error("unexpected interface") } if w, ok := w.(Unwrapper); ok { if w.Unwrap() != inner { t.Error("w.Unwrap() failed") } } else { t.Error("Unwrapper interface not implemented") } } // combination 16/16 { t.Log("http.ResponseWriter, http.Flusher, http.CloseNotifier, http.Hijacker, io.ReaderFrom") inner := struct { http.ResponseWriter http.Flusher http.CloseNotifier http.Hijacker io.ReaderFrom }{} w := Wrap(inner, Hooks{}) if _, ok := w.(http.ResponseWriter); ok != true { t.Error("unexpected interface") } if _, ok := w.(http.Flusher); ok != true { t.Error("unexpected interface") } if _, ok := w.(http.CloseNotifier); ok != true { t.Error("unexpected interface") } if _, ok := w.(http.Hijacker); ok != true { t.Error("unexpected interface") } if _, ok := w.(io.ReaderFrom); ok != true { t.Error("unexpected interface") } if w, ok := w.(Unwrapper); ok { if w.Unwrap() != inner { t.Error("w.Unwrap() failed") } } else { t.Error("Unwrapper interface not implemented") } } } httpsnoop-1.0.3/wrap_test.go000066400000000000000000000054451423126150400161160ustar00rootroot00000000000000package httpsnoop import ( "bytes" "io" "io/ioutil" "net/http" "net/http/httptest" "testing" ) func TestWrap_integration(t *testing.T) { tests := []struct { Name string Handler http.Handler Hooks Hooks WantCode int WantBody []byte }{ { Name: "WriteHeader (no hook)", Handler: http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { w.WriteHeader(http.StatusNotFound) }), WantCode: http.StatusNotFound, }, { Name: "WriteHeader", Handler: http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { w.WriteHeader(http.StatusNotFound) }), Hooks: Hooks{ WriteHeader: func(next WriteHeaderFunc) WriteHeaderFunc { return func(code int) { if code != http.StatusNotFound { t.Errorf("got=%d want=%d", code, http.StatusNotFound) } next(http.StatusForbidden) } }, }, WantCode: http.StatusForbidden, }, { Name: "Write (no hook)", Handler: http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { w.Write([]byte("foo")) }), WantCode: http.StatusOK, WantBody: []byte("foo"), }, { Name: "Write (rewrite hook)", Handler: http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { if n, err := w.Write([]byte("foo")); err != nil { t.Errorf("got=%s", err) } else if got, want := n, len("foobar"); got != want { t.Errorf("got=%d want=%d", got, want) } }), Hooks: Hooks{ Write: func(next WriteFunc) WriteFunc { return func(p []byte) (int, error) { if string(p) != "foo" { t.Errorf("%s", p) } return next([]byte("foobar")) } }, }, WantCode: http.StatusOK, WantBody: []byte("foobar"), }, { Name: "Write (error hook)", Handler: http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { if n, err := w.Write([]byte("foo")); n != 0 { t.Errorf("got=%d want=%d", n, 0) } else if err != io.EOF { t.Errorf("got=%s want=%s", err, io.EOF) } }), Hooks: Hooks{ Write: func(next WriteFunc) WriteFunc { return func(p []byte) (int, error) { if string(p) != "foo" { t.Errorf("%s", p) } return 0, io.EOF } }, }, WantCode: http.StatusOK, }, } for _, test := range tests { func() { h := http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { sw := Wrap(w, test.Hooks) test.Handler.ServeHTTP(sw, r) }) s := httptest.NewServer(h) defer s.Close() res, err := http.Get(s.URL) if err != nil { t.Fatal(err) } defer res.Body.Close() gotBody, err := ioutil.ReadAll(res.Body) if res.StatusCode != test.WantCode { t.Errorf("got=%d want=%d", res.StatusCode, test.WantCode) } else if !bytes.Equal(gotBody, test.WantBody) { t.Errorf("got=%s want=%s", gotBody, test.WantBody) } }() } }