Skip to content
Permalink

Comparing changes

Choose two branches to see what’s changed or to start a new pull request. If you need to, you can also or learn more about diff comparisons.

Open a pull request

Create a new pull request by comparing changes across two branches. If you need to, you can also . Learn more about diff comparisons here.
base repository: go-chi/chi
Failed to load repositories. Confirm that selected base ref is valid, then try again.
Loading
base: v5.0.2
Choose a base ref
...
head repository: go-chi/chi
Failed to load repositories. Confirm that selected head ref is valid, then try again.
Loading
compare: v5.0.3
Choose a head ref
  • 8 commits
  • 9 files changed
  • 5 contributors

Commits on Apr 16, 2021

  1. Update README.md

    pkieltyka authored Apr 16, 2021
    Copy the full SHA
    fcd7dfa View commit details
  2. Update README.md

    pkieltyka authored Apr 16, 2021
    Copy the full SHA
    d32a834 View commit details

Commits on Apr 25, 2021

  1. Copy the full SHA
    25eb15c View commit details
  2. Copy the full SHA
    f71cd7d View commit details
  3. Copy the full SHA
    fd503d9 View commit details
  4. Copy the full SHA
    248d06c View commit details

Commits on Apr 29, 2021

  1. Copy the full SHA
    9f4d884 View commit details
  2. v5.0.3

    pkieltyka committed Apr 29, 2021
    Copy the full SHA
    f16f870 View commit details
Showing with 124 additions and 26 deletions.
  1. +5 −0 CHANGELOG.md
  2. +2 −13 README.md
  3. +17 −0 middleware/logger_test.go
  4. +7 −0 middleware/profiler.go
  5. +1 −1 middleware/realip.go
  6. +25 −0 middleware/realip_test.go
  7. +3 −2 middleware/throttle_test.go
  8. +63 −9 middleware/wrap_writer.go
  9. +1 −1 middleware/wrap_writer_test.go
5 changes: 5 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,10 @@
# Changelog

## v5.0.3 (2021-04-29)

- History of changes: see https://github.com/go-chi/chi/compare/v5.0.2...v5.0.3


## v5.0.2 (2021-03-25)

- History of changes: see https://github.com/go-chi/chi/compare/v5.0.1...v5.0.2
15 changes: 2 additions & 13 deletions README.md
Original file line number Diff line number Diff line change
@@ -32,7 +32,7 @@ and [docgen](https://github.com/go-chi/docgen). We hope you enjoy it too!
* **Context control** - built on new `context` package, providing value chaining, cancellations and timeouts
* **Robust** - in production at Pressly, CloudFlare, Heroku, 99Designs, and many others (see [discussion](https://github.com/go-chi/chi/issues/91))
* **Doc generation** - `docgen` auto-generates routing documentation from your source to JSON or Markdown
* **Go.mod support** - v1.x of chi (starting from v1.5.0), now has go.mod support (see [CHANGELOG](https://github.com/go-chi/chi/blob/master/CHANGELOG.md#v150-2020-11-12---now-with-gomod-support))
* **Go.mod support** - as of v5, go.mod support (see [CHANGELOG](https://github.com/go-chi/chi/blob/master/CHANGELOG.md))
* **No external dependencies** - plain ol' Go stdlib + net/http


@@ -347,7 +347,7 @@ with `net/http` can be used with chi's mux.
| [Logger] | Logs the start and end of each request with the elapsed processing time |
| [NoCache] | Sets response headers to prevent clients from caching |
| [Profiler] | Easily attach net/http/pprof to your routers |
| [RealIP] | Sets a http.Request's RemoteAddr to either X-Forwarded-For or X-Real-IP |
| [RealIP] | Sets a http.Request's RemoteAddr to either X-Real-IP or X-Forwarded-For |
| [Recoverer] | Gracefully absorb panics and prints the stack trace |
| [RequestID] | Injects a request ID into the context of each request |
| [RedirectSlashes] | Redirect slashes on routing paths |
@@ -463,17 +463,6 @@ on the duplicated (alloc'd) request and returns it the new request object. This
how setting context on a request in Go works.


## Go module support & note on chi's versioning

* Go.mod support means we reset our versioning starting from v1.5 (see [CHANGELOG](https://github.com/go-chi/chi/blob/master/CHANGELOG.md#v150-2020-11-12---now-with-gomod-support))
* All older tags are preserved, are backwards-compatible and will "just work" as they
* Brand new systems can run `go get -u github.com/go-chi/chi` as normal, or `go get -u github.com/go-chi/chi@latest`
to install chi, which will install v1.x+ built with go.mod support, starting from v1.5.0.
* For existing projects who want to upgrade to the latest go.mod version, run: `go get -u github.com/go-chi/chi@v1.5.0`,
which will get you on the go.mod version line (as Go's mod cache may still remember v4.x).
* Any breaking changes will bump a "minor" release and backwards-compatible improvements/fixes will bump a "tiny" release.


## Credits

* Carl Jackson for https://github.com/zenazn/goji
17 changes: 17 additions & 0 deletions middleware/logger_test.go
Original file line number Diff line number Diff line change
@@ -2,10 +2,12 @@ package middleware

import (
"bufio"
"bytes"
"net"
"net/http"
"net/http/httptest"
"testing"
"time"
)

type testLoggerWriter struct {
@@ -32,3 +34,18 @@ func TestRequestLogger(t *testing.T) {
handler := DefaultLogger(testHandler)
handler.ServeHTTP(w, r)
}

func TestRequestLoggerReadFrom(t *testing.T) {
data := []byte("file data")
testHandler := http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
http.ServeContent(w, r, "file", time.Time{}, bytes.NewReader(data))
})

r := httptest.NewRequest("GET", "/", nil)
w := httptest.NewRecorder()

handler := DefaultLogger(testHandler)
handler.ServeHTTP(w, r)

assertEqual(t, data, w.Body.Bytes())
}
7 changes: 7 additions & 0 deletions middleware/profiler.go
Original file line number Diff line number Diff line change
@@ -36,6 +36,13 @@ func Profiler() http.Handler {
r.HandleFunc("/pprof/trace", pprof.Trace)
r.HandleFunc("/vars", expVars)

r.Handle("/pprof/goroutine", pprof.Handler("goroutine"))
r.Handle("/pprof/threadcreate", pprof.Handler("threadcreate"))
r.Handle("/pprof/mutex", pprof.Handler("mutex"))
r.Handle("/pprof/heap", pprof.Handler("heap"))
r.Handle("/pprof/block", pprof.Handler("block"))
r.Handle("/pprof/allocs", pprof.Handler("allocs"))

return r
}

2 changes: 1 addition & 1 deletion middleware/realip.go
Original file line number Diff line number Diff line change
@@ -12,7 +12,7 @@ var xForwardedFor = http.CanonicalHeaderKey("X-Forwarded-For")
var xRealIP = http.CanonicalHeaderKey("X-Real-IP")

// RealIP is a middleware that sets a http.Request's RemoteAddr to the results
// of parsing either the X-Forwarded-For header or the X-Real-IP header (in that
// of parsing either the X-Real-IP header or the X-Forwarded-For header (in that
// order).
//
// This middleware should be inserted fairly early in the middleware stack to
25 changes: 25 additions & 0 deletions middleware/realip_test.go
Original file line number Diff line number Diff line change
@@ -55,3 +55,28 @@ func TestXForwardForIP(t *testing.T) {
t.Fatal("Test get real IP error.")
}
}

func TestXForwardForXRealIPPrecedence(t *testing.T) {
req, _ := http.NewRequest("GET", "/", nil)
req.Header.Add("X-Forwarded-For", "0.0.0.0")
req.Header.Add("X-Real-IP", "100.100.100.100")
w := httptest.NewRecorder()

r := chi.NewRouter()
r.Use(RealIP)

realIP := ""
r.Get("/", func(w http.ResponseWriter, r *http.Request) {
realIP = r.RemoteAddr
w.Write([]byte("Hello World"))
})
r.ServeHTTP(w, req)

if w.Code != 200 {
t.Fatal("Response Code should be 200")
}

if realIP != "100.100.100.100" {
t.Fatal("Test get real IP precedence error.")
}
}
5 changes: 3 additions & 2 deletions middleware/throttle_test.go
Original file line number Diff line number Diff line change
@@ -203,7 +203,8 @@ func TestThrottleMaximum(t *testing.T) {
wg.Wait()
}

func TestThrottleRetryAfter(t *testing.T) {
// NOTE: test is disabled as it requires some refactoring. It is prone to intermittent failure.
/*func TestThrottleRetryAfter(t *testing.T) {
r := chi.NewRouter()
retryAfterFn := func(ctxDone bool) time.Duration { return time.Hour * 1 }
@@ -250,4 +251,4 @@ func TestThrottleRetryAfter(t *testing.T) {
}
wg.Wait()
}
}*/
72 changes: 63 additions & 9 deletions middleware/wrap_writer.go
Original file line number Diff line number Diff line change
@@ -19,15 +19,25 @@ func NewWrapResponseWriter(w http.ResponseWriter, protoMajor int) WrapResponseWr

if protoMajor == 2 {
_, ps := w.(http.Pusher)
if fl || ps {
if fl && ps {
return &http2FancyWriter{bw}
}
} else {
_, hj := w.(http.Hijacker)
_, rf := w.(io.ReaderFrom)
if fl || hj || rf {
if fl && hj && rf {
return &httpFancyWriter{bw}
}
if fl && hj {
return &flushHijackWriter{bw}
}
if hj {
return &hijackWriter{bw}
}
}

if fl {
return &flushWriter{bw}
}

return &bw
@@ -57,10 +67,10 @@ type WrapResponseWriter interface {
// http.ResponseWriter interface.
type basicWriter struct {
http.ResponseWriter
tee io.Writer
wroteHeader bool
code int
bytes int
wroteHeader bool
tee io.Writer
}

func (b *basicWriter) WriteHeader(code int) {
@@ -107,6 +117,50 @@ func (b *basicWriter) Unwrap() http.ResponseWriter {
return b.ResponseWriter
}

// flushWriter ...
type flushWriter struct {
basicWriter
}

func (f *flushWriter) Flush() {
f.wroteHeader = true
fl := f.basicWriter.ResponseWriter.(http.Flusher)
fl.Flush()
}

var _ http.Flusher = &flushWriter{}

// hijackWriter ...
type hijackWriter struct {
basicWriter
}

func (f *hijackWriter) Hijack() (net.Conn, *bufio.ReadWriter, error) {
hj := f.basicWriter.ResponseWriter.(http.Hijacker)
return hj.Hijack()
}

var _ http.Hijacker = &hijackWriter{}

// flushHijackWriter ...
type flushHijackWriter struct {
basicWriter
}

func (f *flushHijackWriter) Flush() {
f.wroteHeader = true
fl := f.basicWriter.ResponseWriter.(http.Flusher)
fl.Flush()
}

func (f *flushHijackWriter) Hijack() (net.Conn, *bufio.ReadWriter, error) {
hj := f.basicWriter.ResponseWriter.(http.Hijacker)
return hj.Hijack()
}

var _ http.Flusher = &flushHijackWriter{}
var _ http.Hijacker = &flushHijackWriter{}

// httpFancyWriter is a HTTP writer that additionally satisfies
// http.Flusher, http.Hijacker, and io.ReaderFrom. It exists for the common case
// of wrapping the http.ResponseWriter that package http gives you, in order to
@@ -126,6 +180,10 @@ func (f *httpFancyWriter) Hijack() (net.Conn, *bufio.ReadWriter, error) {
return hj.Hijack()
}

func (f *http2FancyWriter) Push(target string, opts *http.PushOptions) error {
return f.basicWriter.ResponseWriter.(http.Pusher).Push(target, opts)
}

func (f *httpFancyWriter) ReadFrom(r io.Reader) (int64, error) {
if f.basicWriter.tee != nil {
n, err := io.Copy(&f.basicWriter, r)
@@ -141,6 +199,7 @@ func (f *httpFancyWriter) ReadFrom(r io.Reader) (int64, error) {

var _ http.Flusher = &httpFancyWriter{}
var _ http.Hijacker = &httpFancyWriter{}
var _ http.Pusher = &http2FancyWriter{}
var _ io.ReaderFrom = &httpFancyWriter{}

// http2FancyWriter is a HTTP2 writer that additionally satisfies
@@ -157,9 +216,4 @@ func (f *http2FancyWriter) Flush() {
fl.Flush()
}

func (f *http2FancyWriter) Push(target string, opts *http.PushOptions) error {
return f.basicWriter.ResponseWriter.(http.Pusher).Push(target, opts)
}

var _ http.Flusher = &http2FancyWriter{}
var _ http.Pusher = &http2FancyWriter{}
2 changes: 1 addition & 1 deletion middleware/wrap_writer_test.go
Original file line number Diff line number Diff line change
@@ -6,7 +6,7 @@ import (
)

func TestHttpFancyWriterRemembersWroteHeaderWhenFlushed(t *testing.T) {
f := &httpFancyWriter{basicWriter{ResponseWriter: httptest.NewRecorder()}}
f := &httpFancyWriter{basicWriter: basicWriter{ResponseWriter: httptest.NewRecorder()}}
f.Flush()

if !f.wroteHeader {