From 645562d74829b4631fd041078b32c2f4d26cd5f8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=89tienne=20Michon?= Date: Mon, 23 Dec 2024 11:40:21 +0100 Subject: [PATCH 1/4] build: update Go from 1.22.5 to 1.22.10 --- Dockerfile | 2 +- go.mod | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/Dockerfile b/Dockerfile index 305d769..d2fd072 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,4 +1,4 @@ -FROM golang:1.22.5 +FROM golang:1.22.10 LABEL maintainer="IST " RUN go install github.com/cespare/reflex@latest diff --git a/go.mod b/go.mod index d66f713..327ba8b 100644 --- a/go.mod +++ b/go.mod @@ -1,6 +1,6 @@ module github.com/Scalingo/acadock-monitoring -go 1.22.5 +go 1.22.10 require ( github.com/Scalingo/go-handlers v1.8.2 From 55119cd48d90040e3550b3c23ef1e64f3f83dfb5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=89tienne=20Michon?= Date: Mon, 23 Dec 2024 11:41:54 +0100 Subject: [PATCH 2/4] build(go.mod): update 'github.com/urfave/negroni' from v1 to v2 --- cmd/acadock-monitoring/main.go | 2 +- go.mod | 3 +- go.sum | 2 + .../github.com/urfave/negroni/v2/.gitignore | 1 + .../github.com/urfave/negroni/v2/.travis.yml | 30 + .../github.com/urfave/negroni/v2/CHANGELOG.md | 100 ++++ vendor/github.com/urfave/negroni/v2/LICENSE | 21 + vendor/github.com/urfave/negroni/v2/README.md | 551 ++++++++++++++++++ vendor/github.com/urfave/negroni/v2/doc.go | 25 + vendor/github.com/urfave/negroni/v2/logger.go | 77 +++ .../github.com/urfave/negroni/v2/negroni.go | 181 ++++++ .../github.com/urfave/negroni/v2/recovery.go | 211 +++++++ .../urfave/negroni/v2/response_writer.go | 117 ++++ .../negroni/v2/response_writer_pusher.go | 16 + vendor/github.com/urfave/negroni/v2/static.go | 88 +++ vendor/modules.txt | 3 + 16 files changed, 1426 insertions(+), 2 deletions(-) create mode 100644 vendor/github.com/urfave/negroni/v2/.gitignore create mode 100644 vendor/github.com/urfave/negroni/v2/.travis.yml create mode 100644 vendor/github.com/urfave/negroni/v2/CHANGELOG.md create mode 100644 vendor/github.com/urfave/negroni/v2/LICENSE create mode 100644 vendor/github.com/urfave/negroni/v2/README.md create mode 100644 vendor/github.com/urfave/negroni/v2/doc.go create mode 100644 vendor/github.com/urfave/negroni/v2/logger.go create mode 100644 vendor/github.com/urfave/negroni/v2/negroni.go create mode 100644 vendor/github.com/urfave/negroni/v2/recovery.go create mode 100644 vendor/github.com/urfave/negroni/v2/response_writer.go create mode 100644 vendor/github.com/urfave/negroni/v2/response_writer_pusher.go create mode 100644 vendor/github.com/urfave/negroni/v2/static.go diff --git a/cmd/acadock-monitoring/main.go b/cmd/acadock-monitoring/main.go index 74584e3..ad0523d 100644 --- a/cmd/acadock-monitoring/main.go +++ b/cmd/acadock-monitoring/main.go @@ -9,7 +9,7 @@ import ( "os" "github.com/gorilla/mux" - "github.com/urfave/negroni" + "github.com/urfave/negroni/v2" "github.com/Scalingo/acadock-monitoring/config" "github.com/Scalingo/acadock-monitoring/cpu" diff --git a/go.mod b/go.mod index 327ba8b..311b25a 100644 --- a/go.mod +++ b/go.mod @@ -15,7 +15,7 @@ require ( github.com/sirupsen/logrus v1.9.3 github.com/stretchr/testify v1.10.0 github.com/tklauser/go-sysconf v0.3.14 - github.com/urfave/negroni v1.0.0 + github.com/urfave/negroni/v2 v2.0.2 ) require ( @@ -46,6 +46,7 @@ require ( github.com/opencontainers/image-spec v1.1.0 // indirect github.com/pmezard/go-difflib v1.0.0 // indirect github.com/tklauser/numcpus v0.9.0 // indirect + github.com/urfave/negroni v1.0.0 // indirect golang.org/x/sys v0.27.0 // indirect gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c // indirect gopkg.in/errgo.v1 v1.0.1 // indirect diff --git a/go.sum b/go.sum index dbe9ce3..208da76 100644 --- a/go.sum +++ b/go.sum @@ -102,6 +102,8 @@ github.com/tklauser/numcpus v0.9.0 h1:lmyCHtANi8aRUgkckBgoDk1nHCux3n2cgkJLXdQGPD github.com/tklauser/numcpus v0.9.0/go.mod h1:SN6Nq1O3VychhC1npsWostA+oW+VOQTxZrS604NSRyI= github.com/urfave/negroni v1.0.0 h1:kIimOitoypq34K7TG7DUaJ9kq/N4Ofuwi1sjz0KipXc= github.com/urfave/negroni v1.0.0/go.mod h1:Meg73S6kFm/4PpbYdq35yYWoCZ9mS/YSx+lKnmiohz4= +github.com/urfave/negroni/v2 v2.0.2 h1:27gJcVxYJ2a/ytEoCHoJ7ybvyhymV4cAhGuMxkyCsrU= +github.com/urfave/negroni/v2 v2.0.2/go.mod h1:SjdApKzYrObukpN/NnlejbQiZWIUjfDFzQltScGYigI= github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= github.com/yuin/goldmark v1.3.5/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k= diff --git a/vendor/github.com/urfave/negroni/v2/.gitignore b/vendor/github.com/urfave/negroni/v2/.gitignore new file mode 100644 index 0000000..3f2bc47 --- /dev/null +++ b/vendor/github.com/urfave/negroni/v2/.gitignore @@ -0,0 +1 @@ +/coverage.txt diff --git a/vendor/github.com/urfave/negroni/v2/.travis.yml b/vendor/github.com/urfave/negroni/v2/.travis.yml new file mode 100644 index 0000000..b6cb89f --- /dev/null +++ b/vendor/github.com/urfave/negroni/v2/.travis.yml @@ -0,0 +1,30 @@ +language: go + +sudo: false +dist: trusty + +go: +- 1.x +- 1.2.x +- 1.3.x +- 1.4.x +- 1.5.x +- 1.6.x +- 1.7.x +- 1.8.x +- 1.9.x +- 1.10.x +- 1.11.x +- master + +before_install: +- find "${GOPATH%%:*}" -name '*.a' -delete +- rm -rf "${GOPATH%%:*}/src/golang.org" +- go get golang.org/x/tools/cover +- go get golang.org/x/tools/cmd/cover + +script: +- go test -race -coverprofile=coverage.txt -covermode=atomic + +after_success: +- bash <(curl -s "https://codecov.io/bash") diff --git a/vendor/github.com/urfave/negroni/v2/CHANGELOG.md b/vendor/github.com/urfave/negroni/v2/CHANGELOG.md new file mode 100644 index 0000000..de086f2 --- /dev/null +++ b/vendor/github.com/urfave/negroni/v2/CHANGELOG.md @@ -0,0 +1,100 @@ +# Change Log + +**ATTN**: This project uses [semantic versioning](http://semver.org/). + +## [Unreleased] - + +## [2.0.2] - 2020-07-17 + +### Fixed + +- Fixed Go module name for v2 + +## [2.0.1] - 2020-05-25 + +### Fixed + +- Recovery middleware now checks that `Formatter` is not `nil` before calling + +## [2.0.0] - 2020-05-25 + +### Changed + +- `Recovery.PrintStack`, when false, now also supresses the panic message in + addition to supressing the stack trace + +### Fixed + +- `Negroni.With()` now copies handlers to avoid mutating the original `Negroni` + instance if `Use` is called on the new `Negroni` instance + +### Added + +- `Recovery.LogStack` was added to control whether the stacktrace is logged for + panics + +### Changed + +## [1.0.0] - 2018-09-01 + +### Fixed +- `Logger` middleware now correctly handles paths containing a `%` instead of trying to treat it as a format specifier + +## [0.3.0] - 2017-11-11 +### Added +- `With()` helper for building a new `Negroni` struct chaining handlers from + existing `Negroni` structs +- Format log output in `Logger` middleware via a configurable `text/template` + string injectable via `.SetFormat`. Added `LoggerDefaultFormat` and + `LoggerDefaultDateFormat` to configure the default template and date format + used by the `Logger` middleware. +- Support for HTTP/2 pusher support via `http.Pusher` interface for Go 1.8+. +- `WrapFunc` to convert `http.HandlerFunc` into a `negroni.Handler` +- `Formatter` field added to `Recovery` middleware to allow configuring how + `panic`s are output. Default of `TextFormatter` (how it was output in + `0.2.0`) used. `HTMLPanicFormatter` also added to allow easy outputing of + `panic`s as HTML. + +### Fixed +- `Written()` correct returns `false` if no response header has been written +- Only implement `http.CloseNotifier` with the `negroni.ResponseWriter` if the + underlying `http.ResponseWriter` implements it (previously would always + implement it and panic if the underlying `http.ResponseWriter` did not. + +### Changed +- Set default status to `0` in the case that no handler writes status -- was + previously `200` (in 0.2.0, before that it was `0` so this reestablishes that + behavior) +- Catch `panic`s thrown by callbacks provided to the `Recovery` handler +- Recovery middleware will set `text/plain` content-type if none is set +- `ALogger` interface to allow custom logger outputs to be used with the + `Logger` middleware. Changes embeded field in `negroni.Logger` from `Logger` + to `ALogger`. +- Default `Logger` middleware output changed to be more structure and verbose + (also now configurable, see `Added`) +- Automatically bind to port specified in `$PORT` in `.Run()` if an address is + not passed in. Fall back to binding to `:8080` if no address specified + (configuable via `DefaultAddress`). +- `PanicHandlerFunc` added to `Recovery` middleware to enhance custom handling + of `panic`s by providing additional information to the handler including the + stack and the `http.Request`. `Recovery.ErrorHandlerFunc` was also added, but + deprecated in favor of the new `PanicHandlerFunc`. + +## [0.2.0] - 2016-05-10 +### Added +- Support for variadic handlers in `New()` +- Added `Negroni.Handlers()` to fetch all of the handlers for a given chain +- Allowed size in `Recovery` handler was bumped to 8k +- `Negroni.UseFunc` to push another handler onto the chain + +### Changed +- Set the status before calling `beforeFuncs` so the information is available to them +- Set default status to `200` in the case that no handler writes status -- was previously `0` +- Panic if `nil` handler is given to `negroni.Use` + +## 0.1.0 - 2013-07-22 +### Added +- Initial implementation. + +[Unreleased]: https://github.com/urfave/negroni/compare/v0.2.0...HEAD +[0.2.0]: https://github.com/urfave/negroni/compare/v0.1.0...v0.2.0 diff --git a/vendor/github.com/urfave/negroni/v2/LICENSE b/vendor/github.com/urfave/negroni/v2/LICENSE new file mode 100644 index 0000000..08b5e20 --- /dev/null +++ b/vendor/github.com/urfave/negroni/v2/LICENSE @@ -0,0 +1,21 @@ +The MIT License (MIT) + +Copyright (c) 2014 Jeremy Saenz + +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. diff --git a/vendor/github.com/urfave/negroni/v2/README.md b/vendor/github.com/urfave/negroni/v2/README.md new file mode 100644 index 0000000..13b2e6d --- /dev/null +++ b/vendor/github.com/urfave/negroni/v2/README.md @@ -0,0 +1,551 @@ +# Negroni +[![GoDoc](https://godoc.org/github.com/urfave/negroni?status.svg)](http://godoc.org/github.com/urfave/negroni) +[![Build Status](https://travis-ci.org/urfave/negroni.svg?branch=master)](https://travis-ci.org/urfave/negroni) +[![codebeat](https://codebeat.co/badges/47d320b1-209e-45e8-bd99-9094bc5111e2)](https://codebeat.co/projects/github-com-urfave-negroni) +[![codecov](https://codecov.io/gh/urfave/negroni/branch/master/graph/badge.svg)](https://codecov.io/gh/urfave/negroni) + +**Notice:** This is the library formerly known as +`github.com/codegangsta/negroni` -- Github will automatically redirect requests +to this repository, but we recommend updating your references for clarity. + +Negroni is an idiomatic approach to web middleware in Go. It is tiny, +non-intrusive, and encourages use of `net/http` Handlers. + +If you like the idea of [Martini](https://github.com/go-martini/martini), but +you think it contains too much magic, then Negroni is a great fit. + +Language Translations: +* [Deutsch (de_DE)](translations/README_de_de.md) +* [Português Brasileiro (pt_BR)](translations/README_pt_br.md) +* [简体中文 (zh_CN)](translations/README_zh_CN.md) +* [繁體中文 (zh_TW)](translations/README_zh_tw.md) +* [日本語 (ja_JP)](translations/README_ja_JP.md) +* [Français (fr_FR)](translations/README_fr_FR.md) +* [한국어 (ko_KR)](translations/README_ko_KR.md) + +## Getting Started + +After installing Go and setting up your +[GOPATH](http://golang.org/doc/code.html#GOPATH), create your first `.go` file. +We'll call it `server.go`. + + +``` go +package main + +import ( + "fmt" + "net/http" + + "github.com/urfave/negroni" +) + +func main() { + mux := http.NewServeMux() + mux.HandleFunc("/", func(w http.ResponseWriter, req *http.Request) { + fmt.Fprintf(w, "Welcome to the home page!") + }) + + n := negroni.Classic() // Includes some default middlewares + n.UseHandler(mux) + + http.ListenAndServe(":3000", n) +} +``` + +Then install the Negroni package (**NOTE**: >= **go 1.1** is required): + +``` +go get github.com/urfave/negroni +``` + +Then run your server: + +``` +go run server.go +``` + +You will now have a Go `net/http` webserver running on `localhost:3000`. + +### Packaging + +If you are on Debian, `negroni` is also available as [a +package](https://packages.debian.org/sid/golang-github-urfave-negroni-dev) that +you can install via `apt install golang-github-urfave-negroni-dev` (at the time +of writing, it is in the `sid` repositories). + +## Is Negroni a Framework? + +Negroni is **not** a framework. It is a middleware-focused library that is +designed to work directly with `net/http`. + +## Routing? + +Negroni is BYOR (Bring your own Router). The Go community already has a number +of great http routers available, and Negroni tries to play well with all of them +by fully supporting `net/http`. For instance, integrating with [Gorilla Mux] +looks like so: + +``` go +router := mux.NewRouter() +router.HandleFunc("/", HomeHandler) + +n := negroni.New(Middleware1, Middleware2) +// Or use a middleware with the Use() function +n.Use(Middleware3) +// router goes last +n.UseHandler(router) + +http.ListenAndServe(":3001", n) +``` + +## `negroni.Classic()` + +`negroni.Classic()` provides some default middleware that is useful for most +applications: + +* [`negroni.Recovery`](#recovery) - Panic Recovery Middleware. +* [`negroni.Logger`](#logger) - Request/Response Logger Middleware. +* [`negroni.Static`](#static) - Static File serving under the "public" + directory. + +This makes it really easy to get started with some useful features from Negroni. + +## Handlers + +Negroni provides a bidirectional middleware flow. This is done through the +`negroni.Handler` interface: + +``` go +type Handler interface { + ServeHTTP(rw http.ResponseWriter, r *http.Request, next http.HandlerFunc) +} +``` + +If a middleware hasn't already written to the `ResponseWriter`, it should call +the next `http.HandlerFunc` in the chain to yield to the next middleware +handler. This can be used for great good: + +``` go +func MyMiddleware(rw http.ResponseWriter, r *http.Request, next http.HandlerFunc) { + // do some stuff before + next(rw, r) + // do some stuff after +} +``` + +And you can map it to the handler chain with the `Use` function: + +``` go +n := negroni.New() +n.Use(negroni.HandlerFunc(MyMiddleware)) +``` + +You can also map plain old `http.Handler`s: + +``` go +n := negroni.New() + +mux := http.NewServeMux() +// map your routes + +n.UseHandler(mux) + +http.ListenAndServe(":3000", n) +``` + +## `With()` + +Negroni has a convenience function called `With`. `With` takes one or more +`Handler` instances and returns a new `Negroni` with the combination of the +receiver's handlers and the new handlers. + +```go +// middleware we want to reuse +common := negroni.New() +common.Use(MyMiddleware1) +common.Use(MyMiddleware2) + +// `specific` is a new negroni with the handlers from `common` combined with the +// the handlers passed in +specific := common.With( + SpecificMiddleware1, + SpecificMiddleware2 +) +``` + +## `Run()` + +Negroni has a convenience function called `Run`. `Run` takes an addr string +identical to [`http.ListenAndServe`](https://godoc.org/net/http#ListenAndServe). + + +``` go +package main + +import ( + "github.com/urfave/negroni" +) + +func main() { + n := negroni.Classic() + n.Run(":8080") +} +``` +If no address is provided, the `PORT` environment variable is used instead. +If the `PORT` environment variable is not defined, the default address will be used. +See [Run](https://godoc.org/github.com/urfave/negroni#Negroni.Run) for a complete description. + +In general, you will want to use `net/http` methods and pass `negroni` as a +`Handler`, as this is more flexible, e.g.: + + +``` go +package main + +import ( + "fmt" + "log" + "net/http" + "time" + + "github.com/urfave/negroni" +) + +func main() { + mux := http.NewServeMux() + mux.HandleFunc("/", func(w http.ResponseWriter, req *http.Request) { + fmt.Fprintf(w, "Welcome to the home page!") + }) + + n := negroni.Classic() // Includes some default middlewares + n.UseHandler(mux) + + s := &http.Server{ + Addr: ":8080", + Handler: n, + ReadTimeout: 10 * time.Second, + WriteTimeout: 10 * time.Second, + MaxHeaderBytes: 1 << 20, + } + log.Fatal(s.ListenAndServe()) +} +``` + +## Route Specific Middleware + +If you have a route group of routes that need specific middleware to be +executed, you can simply create a new Negroni instance and use it as your route +handler. + +``` go +router := mux.NewRouter() +adminRoutes := mux.NewRouter() +// add admin routes here + +// Create a new negroni for the admin middleware +router.PathPrefix("/admin").Handler(negroni.New( + Middleware1, + Middleware2, + negroni.Wrap(adminRoutes), +)) +``` + +If you are using [Gorilla Mux], here is an example using a subrouter: + +``` go +router := mux.NewRouter() +subRouter := mux.NewRouter().PathPrefix("/subpath").Subrouter().StrictSlash(true) +subRouter.HandleFunc("/", someSubpathHandler) // "/subpath/" +subRouter.HandleFunc("/:id", someSubpathHandler) // "/subpath/:id" + +// "/subpath" is necessary to ensure the subRouter and main router linkup +router.PathPrefix("/subpath").Handler(negroni.New( + Middleware1, + Middleware2, + negroni.Wrap(subRouter), +)) +``` + +`With()` can be used to eliminate redundancy for middlewares shared across +routes. + +``` go +router := mux.NewRouter() +apiRoutes := mux.NewRouter() +// add api routes here +webRoutes := mux.NewRouter() +// add web routes here + +// create common middleware to be shared across routes +common := negroni.New( + Middleware1, + Middleware2, +) + +// create a new negroni for the api middleware +// using the common middleware as a base +router.PathPrefix("/api").Handler(common.With( + APIMiddleware1, + negroni.Wrap(apiRoutes), +)) +// create a new negroni for the web middleware +// using the common middleware as a base +router.PathPrefix("/web").Handler(common.With( + WebMiddleware1, + negroni.Wrap(webRoutes), +)) +``` + +## Bundled Middleware + +### Static + +This middleware will serve files on the filesystem. If the files do not exist, +it proxies the request to the next middleware. If you want the requests for +non-existent files to return a `404 File Not Found` to the user you should look +at using [http.FileServer](https://golang.org/pkg/net/http/#FileServer) as +a handler. + +Example: + + +``` go +package main + +import ( + "fmt" + "net/http" + + "github.com/urfave/negroni" +) + +func main() { + mux := http.NewServeMux() + mux.HandleFunc("/", func(w http.ResponseWriter, req *http.Request) { + fmt.Fprintf(w, "Welcome to the home page!") + }) + + // Example of using a http.FileServer if you want "server-like" rather than "middleware" behavior + // mux.Handle("/public", http.FileServer(http.Dir("/home/public"))) + + n := negroni.New() + n.Use(negroni.NewStatic(http.Dir("/tmp"))) + n.UseHandler(mux) + + http.ListenAndServe(":3002", n) +} +``` + +Will serve files from the `/tmp` directory first, but proxy calls to the next +handler if the request does not match a file on the filesystem. + +### Recovery + +This middleware catches `panic`s and responds with a `500` response code. If +any other middleware has written a response code or body, this middleware will +fail to properly send a 500 to the client, as the client has already received +the HTTP response code. Additionally, an `PanicHandlerFunc` can be attached +to report 500's to an error reporting service such as Sentry or Airbrake. + +Example: + + +``` go +package main + +import ( + "net/http" + + "github.com/urfave/negroni" +) + +func main() { + mux := http.NewServeMux() + mux.HandleFunc("/", func(w http.ResponseWriter, req *http.Request) { + panic("oh no") + }) + + n := negroni.New() + n.Use(negroni.NewRecovery()) + n.UseHandler(mux) + + http.ListenAndServe(":3003", n) +} +``` + +Will return a `500 Internal Server Error` to each request. It will also log the +stack traces as well as print the stack trace to the requester if `PrintStack` +is set to `true` (the default). + +Example with error handler: + +``` go +package main + +import ( + "net/http" + + "github.com/urfave/negroni" +) + +func main() { + mux := http.NewServeMux() + mux.HandleFunc("/", func(w http.ResponseWriter, req *http.Request) { + panic("oh no") + }) + + n := negroni.New() + recovery := negroni.NewRecovery() + recovery.PanicHandlerFunc = reportToSentry + n.Use(recovery) + n.UseHandler(mux) + + http.ListenAndServe(":3003", n) +} + +func reportToSentry(info *negroni.PanicInformation) { + // write code here to report error to Sentry +} +``` + +The middleware simply output the informations on STDOUT by default. +You can customize the output process by using the `SetFormatter()` function. + +You can use also the `HTMLPanicFormatter` to display a pretty HTML when a crash occurs. + + +``` go +package main + +import ( + "net/http" + + "github.com/urfave/negroni" +) + +func main() { + mux := http.NewServeMux() + mux.HandleFunc("/", func(w http.ResponseWriter, req *http.Request) { + panic("oh no") + }) + + n := negroni.New() + recovery := negroni.NewRecovery() + recovery.Formatter = &negroni.HTMLPanicFormatter{} + n.Use(recovery) + n.UseHandler(mux) + + http.ListenAndServe(":3003", n) +} +``` + +## Logger + +This middleware logs each incoming request and response. + +Example: + + +``` go +package main + +import ( + "fmt" + "net/http" + + "github.com/urfave/negroni" +) + +func main() { + mux := http.NewServeMux() + mux.HandleFunc("/", func(w http.ResponseWriter, req *http.Request) { + fmt.Fprintf(w, "Welcome to the home page!") + }) + + n := negroni.New() + n.Use(negroni.NewLogger()) + n.UseHandler(mux) + + http.ListenAndServe(":3004", n) +} +``` + +Will print a log similar to: + +``` +[negroni] 2017-10-04T14:56:25+02:00 | 200 | 378µs | localhost:3004 | GET / +``` + +on each request. + +You can also set your own log format by calling the `SetFormat` function. The format is a template string with fields as mentioned in the `LoggerEntry` struct. So, as an example - + +```go +l.SetFormat("[{{.Status}} {{.Duration}}] - {{.Request.UserAgent}}") +``` + +will show something like - `[200 18.263µs] - Go-User-Agent/1.1 ` + +## Third Party Middleware + +Here is a current list of Negroni compatible middlware. Feel free to put up a PR +linking your middleware if you have built one: + +| Middleware | Author | Description | +| -----------|--------|-------------| +| [authz](https://github.com/casbin/negroni-authz) | [Yang Luo](https://github.com/hsluoyz) | ACL, RBAC, ABAC Authorization middlware based on [Casbin](https://github.com/casbin/casbin) | +| [binding](https://github.com/mholt/binding) | [Matt Holt](https://github.com/mholt) | Data binding from HTTP requests into structs | +| [cloudwatch](https://github.com/cvillecsteele/negroni-cloudwatch) | [Colin Steele](https://github.com/cvillecsteele) | AWS cloudwatch metrics middleware | +| [cors](https://github.com/rs/cors) | [Olivier Poitrey](https://github.com/rs) | [Cross Origin Resource Sharing](http://www.w3.org/TR/cors/) (CORS) support | +| [csp](https://github.com/awakenetworks/csp) | [Awake Networks](https://github.com/awakenetworks) | [Content Security Policy](https://www.w3.org/TR/CSP2/) (CSP) support | +| [delay](https://github.com/jeffbmartinez/delay) | [Jeff Martinez](https://github.com/jeffbmartinez) | Add delays/latency to endpoints. Useful when testing effects of high latency | +| [New Relic Go Agent](https://github.com/yadvendar/negroni-newrelic-go-agent) | [Yadvendar Champawat](https://github.com/yadvendar) | Official [New Relic Go Agent](https://github.com/newrelic/go-agent) (currently in beta) | +| [gorelic](https://github.com/jingweno/negroni-gorelic) | [Jingwen Owen Ou](https://github.com/jingweno) | New Relic agent for Go runtime | +| [Graceful](https://github.com/tylerb/graceful) | [Tyler Bunnell](https://github.com/tylerb) | Graceful HTTP Shutdown | +| [gzip](https://github.com/phyber/negroni-gzip) | [phyber](https://github.com/phyber) | GZIP response compression | +| [JWT Middleware](https://github.com/auth0/go-jwt-middleware) | [Auth0](https://github.com/auth0) | Middleware checks for a JWT on the `Authorization` header on incoming requests and decodes it| +| [JWT Middleware](https://github.com/mfuentesg/go-jwtmiddleware) | [Marcelo Fuentes](https://github.com/mfuentesg) | JWT middleware for golang | +| [logrus](https://github.com/meatballhat/negroni-logrus) | [Dan Buch](https://github.com/meatballhat) | Logrus-based logger | +| [oauth2](https://github.com/goincremental/negroni-oauth2) | [David Bochenski](https://github.com/bochenski) | oAuth2 middleware | +| [onthefly](https://github.com/xyproto/onthefly) | [Alexander Rødseth](https://github.com/xyproto) | Generate TinySVG, HTML and CSS on the fly | +| [permissions2](https://github.com/xyproto/permissions2) | [Alexander Rødseth](https://github.com/xyproto) | Cookies, users and permissions | +| [prometheus](https://github.com/zbindenren/negroni-prometheus) | [Rene Zbinden](https://github.com/zbindenren) | Easily create metrics endpoint for the [prometheus](http://prometheus.io) instrumentation tool | +| [prometheus](https://github.com/slok/go-prometheus-middleware) | [Xabier Larrakoetxea](https://github.com/slok) | [Prometheus](http://prometheus.io) metrics with multiple options that follow standards and try to be measured in a efficent way | +| [render](https://github.com/unrolled/render) | [Cory Jacobsen](https://github.com/unrolled) | Render JSON, XML and HTML templates | +| [RestGate](https://github.com/pjebs/restgate) | [Prasanga Siripala](https://github.com/pjebs) | Secure authentication for REST API endpoints | +| [secure](https://github.com/unrolled/secure) | [Cory Jacobsen](https://github.com/unrolled) | Middleware that implements a few quick security wins | +| [sessions](https://github.com/goincremental/negroni-sessions) | [David Bochenski](https://github.com/bochenski) | Session Management | +| [stats](https://github.com/thoas/stats) | [Florent Messa](https://github.com/thoas) | Store information about your web application (response time, etc.) | +| [VanGoH](https://github.com/auroratechnologies/vangoh) | [Taylor Wrobel](https://github.com/twrobel3) | Configurable [AWS-Style](http://docs.aws.amazon.com/AmazonS3/latest/dev/RESTAuthentication.html) HMAC authentication middleware | +| [xrequestid](https://github.com/pilu/xrequestid) | [Andrea Franz](https://github.com/pilu) | Middleware that assigns a random X-Request-Id header to each request | +| [mgo session](https://github.com/joeljames/nigroni-mgo-session) | [Joel James](https://github.com/joeljames) | Middleware that handles creating and closing mgo sessions per request | +| [digits](https://github.com/bamarni/digits) | [Bilal Amarni](https://github.com/bamarni) | Middleware that handles [Twitter Digits](https://get.digits.com/) authentication | +| [stats](https://github.com/guptachirag/stats) | [Chirag Gupta](https://github.com/guptachirag/stats) | Middleware that manages qps and latency stats for your endpoints and asynchronously flushes them to influx db | +| [Chaos](https://github.com/falzm/chaos) | [Marc Falzon](https://github.com/falzm) | Middleware for injecting chaotic behavior into application in a programmatic way | + +## Examples + +[Alexander Rødseth](https://github.com/xyproto) created +[mooseware](https://github.com/xyproto/mooseware), a skeleton for writing a +Negroni middleware handler. + +[Prasanga Siripala](https://github.com/pjebs) created an effective skeleton structure for web-based Go/Negroni projects: [Go-Skeleton](https://github.com/pjebs/go-skeleton) + +## Live code reload? + +[gin](https://github.com/codegangsta/gin) and +[fresh](https://github.com/pilu/fresh) both live reload negroni apps. + +## Essential Reading for Beginners of Go & Negroni + +* [Using a Context to pass information from middleware to end handler](http://elithrar.github.io/article/map-string-interface/) +* [Understanding middleware](https://mattstauffer.co/blog/laravel-5.0-middleware-filter-style) + +## About + +Negroni is obsessively designed by none other than the [Code +Gangsta](https://codegangsta.io/) + +[Gorilla Mux]: https://github.com/gorilla/mux +[`http.FileSystem`]: https://godoc.org/net/http#FileSystem diff --git a/vendor/github.com/urfave/negroni/v2/doc.go b/vendor/github.com/urfave/negroni/v2/doc.go new file mode 100644 index 0000000..add1ed9 --- /dev/null +++ b/vendor/github.com/urfave/negroni/v2/doc.go @@ -0,0 +1,25 @@ +// Package negroni is an idiomatic approach to web middleware in Go. It is tiny, non-intrusive, and encourages use of net/http Handlers. +// +// If you like the idea of Martini, but you think it contains too much magic, then Negroni is a great fit. +// +// For a full guide visit http://github.com/urfave/negroni +// +// package main +// +// import ( +// "github.com/urfave/negroni" +// "net/http" +// "fmt" +// ) +// +// func main() { +// mux := http.NewServeMux() +// mux.HandleFunc("/", func(w http.ResponseWriter, req *http.Request) { +// fmt.Fprintf(w, "Welcome to the home page!") +// }) +// +// n := negroni.Classic() +// n.UseHandler(mux) +// n.Run(":3000") +// } +package negroni diff --git a/vendor/github.com/urfave/negroni/v2/logger.go b/vendor/github.com/urfave/negroni/v2/logger.go new file mode 100644 index 0000000..023bd83 --- /dev/null +++ b/vendor/github.com/urfave/negroni/v2/logger.go @@ -0,0 +1,77 @@ +package negroni + +import ( + "bytes" + "log" + "net/http" + "os" + "text/template" + "time" +) + +// LoggerEntry is the structure passed to the template. +type LoggerEntry struct { + StartTime string + Status int + Duration time.Duration + Hostname string + Method string + Path string + Request *http.Request +} + +// LoggerDefaultFormat is the format logged used by the default Logger instance. +var LoggerDefaultFormat = "{{.StartTime}} | {{.Status}} | \t {{.Duration}} | {{.Hostname}} | {{.Method}} {{.Path}}" + +// LoggerDefaultDateFormat is the format used for date by the default Logger instance. +var LoggerDefaultDateFormat = time.RFC3339 + +// ALogger interface +type ALogger interface { + Println(v ...interface{}) + Printf(format string, v ...interface{}) +} + +// Logger is a middleware handler that logs the request as it goes in and the response as it goes out. +type Logger struct { + // ALogger implements just enough log.Logger interface to be compatible with other implementations + ALogger + dateFormat string + template *template.Template +} + +// NewLogger returns a new Logger instance +func NewLogger() *Logger { + logger := &Logger{ALogger: log.New(os.Stdout, "[negroni] ", 0), dateFormat: LoggerDefaultDateFormat} + logger.SetFormat(LoggerDefaultFormat) + return logger +} + +func (l *Logger) SetFormat(format string) { + l.template = template.Must(template.New("negroni_parser").Parse(format)) +} + +func (l *Logger) SetDateFormat(format string) { + l.dateFormat = format +} + +func (l *Logger) ServeHTTP(rw http.ResponseWriter, r *http.Request, next http.HandlerFunc) { + start := time.Now() + + next(rw, r) + + res := rw.(ResponseWriter) + log := LoggerEntry{ + StartTime: start.Format(l.dateFormat), + Status: res.Status(), + Duration: time.Since(start), + Hostname: r.Host, + Method: r.Method, + Path: r.URL.Path, + Request: r, + } + + buff := &bytes.Buffer{} + l.template.Execute(buff, log) + l.Println(buff.String()) +} diff --git a/vendor/github.com/urfave/negroni/v2/negroni.go b/vendor/github.com/urfave/negroni/v2/negroni.go new file mode 100644 index 0000000..c0fa2d4 --- /dev/null +++ b/vendor/github.com/urfave/negroni/v2/negroni.go @@ -0,0 +1,181 @@ +package negroni + +import ( + "log" + "net/http" + "os" +) + +const ( + // DefaultAddress is used if no other is specified. + DefaultAddress = ":8080" +) + +// Handler handler is an interface that objects can implement to be registered to serve as middleware +// in the Negroni middleware stack. +// ServeHTTP should yield to the next middleware in the chain by invoking the next http.HandlerFunc +// passed in. +// +// If the Handler writes to the ResponseWriter, the next http.HandlerFunc should not be invoked. +type Handler interface { + ServeHTTP(rw http.ResponseWriter, r *http.Request, next http.HandlerFunc) +} + +// HandlerFunc is an adapter to allow the use of ordinary functions as Negroni handlers. +// If f is a function with the appropriate signature, HandlerFunc(f) is a Handler object that calls f. +type HandlerFunc func(rw http.ResponseWriter, r *http.Request, next http.HandlerFunc) + +func (h HandlerFunc) ServeHTTP(rw http.ResponseWriter, r *http.Request, next http.HandlerFunc) { + h(rw, r, next) +} + +type middleware struct { + handler Handler + + // nextfn stores the next.ServeHTTP to reduce memory allocate + nextfn func(rw http.ResponseWriter, r *http.Request) +} + +func newMiddleware(handler Handler, next *middleware) middleware { + return middleware{ + handler: handler, + nextfn: next.ServeHTTP, + } +} + +func (m middleware) ServeHTTP(rw http.ResponseWriter, r *http.Request) { + m.handler.ServeHTTP(rw, r, m.nextfn) +} + +// Wrap converts a http.Handler into a negroni.Handler so it can be used as a Negroni +// middleware. The next http.HandlerFunc is automatically called after the Handler +// is executed. +func Wrap(handler http.Handler) Handler { + return HandlerFunc(func(rw http.ResponseWriter, r *http.Request, next http.HandlerFunc) { + handler.ServeHTTP(rw, r) + next(rw, r) + }) +} + +// WrapFunc converts a http.HandlerFunc into a negroni.Handler so it can be used as a Negroni +// middleware. The next http.HandlerFunc is automatically called after the Handler +// is executed. +func WrapFunc(handlerFunc http.HandlerFunc) Handler { + return HandlerFunc(func(rw http.ResponseWriter, r *http.Request, next http.HandlerFunc) { + handlerFunc(rw, r) + next(rw, r) + }) +} + +// Negroni is a stack of Middleware Handlers that can be invoked as an http.Handler. +// Negroni middleware is evaluated in the order that they are added to the stack using +// the Use and UseHandler methods. +type Negroni struct { + middleware middleware + handlers []Handler +} + +// New returns a new Negroni instance with no middleware preconfigured. +func New(handlers ...Handler) *Negroni { + return &Negroni{ + handlers: handlers, + middleware: build(handlers), + } +} + +// With returns a new Negroni instance that is a combination of the negroni +// receiver's handlers and the provided handlers. +func (n *Negroni) With(handlers ...Handler) *Negroni { + currentHandlers := make([]Handler, len(n.handlers)) + copy(currentHandlers, n.handlers) + return New( + append(currentHandlers, handlers...)..., + ) +} + +// Classic returns a new Negroni instance with the default middleware already +// in the stack. +// +// Recovery - Panic Recovery Middleware +// Logger - Request/Response Logging +// Static - Static File Serving +func Classic() *Negroni { + return New(NewRecovery(), NewLogger(), NewStatic(http.Dir("public"))) +} + +func (n *Negroni) ServeHTTP(rw http.ResponseWriter, r *http.Request) { + n.middleware.ServeHTTP(NewResponseWriter(rw), r) +} + +// Use adds a Handler onto the middleware stack. Handlers are invoked in the order they are added to a Negroni. +func (n *Negroni) Use(handler Handler) { + if handler == nil { + panic("handler cannot be nil") + } + + n.handlers = append(n.handlers, handler) + n.middleware = build(n.handlers) +} + +// UseFunc adds a Negroni-style handler function onto the middleware stack. +func (n *Negroni) UseFunc(handlerFunc func(rw http.ResponseWriter, r *http.Request, next http.HandlerFunc)) { + n.Use(HandlerFunc(handlerFunc)) +} + +// UseHandler adds a http.Handler onto the middleware stack. Handlers are invoked in the order they are added to a Negroni. +func (n *Negroni) UseHandler(handler http.Handler) { + n.Use(Wrap(handler)) +} + +// UseHandlerFunc adds a http.HandlerFunc-style handler function onto the middleware stack. +func (n *Negroni) UseHandlerFunc(handlerFunc func(rw http.ResponseWriter, r *http.Request)) { + n.UseHandler(http.HandlerFunc(handlerFunc)) +} + +// Run is a convenience function that runs the negroni stack as an HTTP +// server. The addr string, if provided, takes the same format as http.ListenAndServe. +// If no address is provided but the PORT environment variable is set, the PORT value is used. +// If neither is provided, the address' value will equal the DefaultAddress constant. +func (n *Negroni) Run(addr ...string) { + l := log.New(os.Stdout, "[negroni] ", 0) + finalAddr := detectAddress(addr...) + l.Printf("listening on %s", finalAddr) + l.Fatal(http.ListenAndServe(finalAddr, n)) +} + +func detectAddress(addr ...string) string { + if len(addr) > 0 { + return addr[0] + } + if port := os.Getenv("PORT"); port != "" { + return ":" + port + } + return DefaultAddress +} + +// Returns a list of all the handlers in the current Negroni middleware chain. +func (n *Negroni) Handlers() []Handler { + return n.handlers +} + +func build(handlers []Handler) middleware { + var next middleware + + switch { + case len(handlers) == 0: + return voidMiddleware() + case len(handlers) > 1: + next = build(handlers[1:]) + default: + next = voidMiddleware() + } + + return newMiddleware(handlers[0], &next) +} + +func voidMiddleware() middleware { + return newMiddleware( + HandlerFunc(func(rw http.ResponseWriter, r *http.Request, next http.HandlerFunc) {}), + &middleware{}, + ) +} diff --git a/vendor/github.com/urfave/negroni/v2/recovery.go b/vendor/github.com/urfave/negroni/v2/recovery.go new file mode 100644 index 0000000..d3ff802 --- /dev/null +++ b/vendor/github.com/urfave/negroni/v2/recovery.go @@ -0,0 +1,211 @@ +package negroni + +import ( + "fmt" + "log" + "net/http" + "os" + "runtime" + "runtime/debug" + "text/template" +) + +const ( + // NoPrintStackBodyString is the body content returned when HTTP stack printing is suppressed + NoPrintStackBodyString = "500 Internal Server Error" + + panicText = "PANIC: %s\n%s" + panicHTML = ` +PANIC: {{.RecoveredPanic}} + + +

Negroni - PANIC

+ +
+

{{.RequestDescription}}

+ Runtime error: {{.RecoveredPanic}} +
+ +{{ if .Stack }} +
+

Runtime Stack

+
{{.StackAsString}}
+
+{{ end }} + + +` + nilRequestMessage = "Request is nil" +) + +var panicHTMLTemplate = template.Must(template.New("PanicPage").Parse(panicHTML)) + +// PanicInformation contains all +// elements for printing stack informations. +type PanicInformation struct { + RecoveredPanic interface{} + Stack []byte + Request *http.Request +} + +// StackAsString returns a printable version of the stack +func (p *PanicInformation) StackAsString() string { + return string(p.Stack) +} + +// RequestDescription returns a printable description of the url +func (p *PanicInformation) RequestDescription() string { + + if p.Request == nil { + return nilRequestMessage + } + + var queryOutput string + if p.Request.URL.RawQuery != "" { + queryOutput = "?" + p.Request.URL.RawQuery + } + return fmt.Sprintf("%s %s%s", p.Request.Method, p.Request.URL.Path, queryOutput) +} + +// PanicFormatter is an interface on object can implement +// to be able to output the stack trace +type PanicFormatter interface { + // FormatPanicError output the stack for a given answer/response. + // In case the the middleware should not output the stack trace, + // the field `Stack` of the passed `PanicInformation` instance equals `[]byte{}`. + FormatPanicError(rw http.ResponseWriter, r *http.Request, infos *PanicInformation) +} + +// TextPanicFormatter output the stack +// as simple text on os.Stdout. If no `Content-Type` is set, +// it will output the data as `text/plain; charset=utf-8`. +// Otherwise, the origin `Content-Type` is kept. +type TextPanicFormatter struct{} + +func (t *TextPanicFormatter) FormatPanicError(rw http.ResponseWriter, r *http.Request, infos *PanicInformation) { + if rw.Header().Get("Content-Type") == "" { + rw.Header().Set("Content-Type", "text/plain; charset=utf-8") + } + fmt.Fprintf(rw, panicText, infos.RecoveredPanic, infos.Stack) +} + +// HTMLPanicFormatter output the stack inside +// an HTML page. This has been largely inspired by +// https://github.com/go-martini/martini/pull/156/commits. +type HTMLPanicFormatter struct{} + +func (t *HTMLPanicFormatter) FormatPanicError(rw http.ResponseWriter, r *http.Request, infos *PanicInformation) { + if rw.Header().Get("Content-Type") == "" { + rw.Header().Set("Content-Type", "text/html; charset=utf-8") + } + panicHTMLTemplate.Execute(rw, infos) +} + +// Recovery is a Negroni middleware that recovers from any panics and writes a 500 if there was one. +type Recovery struct { + Logger ALogger + PrintStack bool + LogStack bool + PanicHandlerFunc func(*PanicInformation) + StackAll bool + StackSize int + Formatter PanicFormatter + + // Deprecated: Use PanicHandlerFunc instead to receive panic + // error with additional information (see PanicInformation) + ErrorHandlerFunc func(interface{}) +} + +// NewRecovery returns a new instance of Recovery +func NewRecovery() *Recovery { + return &Recovery{ + Logger: log.New(os.Stdout, "[negroni] ", 0), + PrintStack: true, + LogStack: true, + StackAll: false, + StackSize: 1024 * 8, + Formatter: &TextPanicFormatter{}, + } +} + +func (rec *Recovery) ServeHTTP(rw http.ResponseWriter, r *http.Request, next http.HandlerFunc) { + defer func() { + if err := recover(); err != nil { + rw.WriteHeader(http.StatusInternalServerError) + + infos := &PanicInformation{ + RecoveredPanic: err, + Request: r, + Stack: make([]byte, rec.StackSize), + } + infos.Stack = infos.Stack[:runtime.Stack(infos.Stack, rec.StackAll)] + + // PrintStack will write stack trace info to the ResponseWriter if set to true! + // If set to false it will respond with the standard response documented here https://httpstat.us/500 + if rec.PrintStack && rec.Formatter != nil { + rec.Formatter.FormatPanicError(rw, r, infos) + } else { + if rw.Header().Get("Content-Type") == "" { + rw.Header().Set("Content-Type", "text/plain; charset=utf-8") + } + fmt.Fprint(rw, NoPrintStackBodyString) + } + + if rec.LogStack { + rec.Logger.Printf(panicText, err, infos.Stack) + } + + if rec.ErrorHandlerFunc != nil { + func() { + defer func() { + if err := recover(); err != nil { + rec.Logger.Printf("provided ErrorHandlerFunc panic'd: %s, trace:\n%s", err, debug.Stack()) + rec.Logger.Printf("%s\n", debug.Stack()) + } + }() + rec.ErrorHandlerFunc(err) + }() + } + if rec.PanicHandlerFunc != nil { + func() { + defer func() { + if err := recover(); err != nil { + rec.Logger.Printf("provided PanicHandlerFunc panic'd: %s, trace:\n%s", err, debug.Stack()) + rec.Logger.Printf("%s\n", debug.Stack()) + } + }() + rec.PanicHandlerFunc(infos) + }() + } + } + }() + + next(rw, r) +} diff --git a/vendor/github.com/urfave/negroni/v2/response_writer.go b/vendor/github.com/urfave/negroni/v2/response_writer.go new file mode 100644 index 0000000..2066d5f --- /dev/null +++ b/vendor/github.com/urfave/negroni/v2/response_writer.go @@ -0,0 +1,117 @@ +package negroni + +import ( + "bufio" + "errors" + "net" + "net/http" +) + +// ResponseWriter is a wrapper around http.ResponseWriter that provides extra information about +// the response. It is recommended that middleware handlers use this construct to wrap a responsewriter +// if the functionality calls for it. +type ResponseWriter interface { + http.ResponseWriter + http.Flusher + // Status returns the status code of the response or 0 if the response has + // not been written + Status() int + // Written returns whether or not the ResponseWriter has been written. + Written() bool + // Size returns the size of the response body. + Size() int + // Before allows for a function to be called before the ResponseWriter has been written to. This is + // useful for setting headers or any other operations that must happen before a response has been written. + Before(func(ResponseWriter)) +} + +type beforeFunc func(ResponseWriter) + +// NewResponseWriter creates a ResponseWriter that wraps an http.ResponseWriter +func NewResponseWriter(rw http.ResponseWriter) ResponseWriter { + nrw := &responseWriter{ + ResponseWriter: rw, + } + + if _, ok := rw.(http.CloseNotifier); ok { + return &responseWriterCloseNotifer{nrw} + } + + return nrw +} + +type responseWriter struct { + http.ResponseWriter + status int + size int + beforeFuncs []beforeFunc +} + +func (rw *responseWriter) WriteHeader(s int) { + rw.status = s + rw.callBefore() + rw.ResponseWriter.WriteHeader(s) +} + +func (rw *responseWriter) Write(b []byte) (int, error) { + if !rw.Written() { + // The status will be StatusOK if WriteHeader has not been called yet + rw.WriteHeader(http.StatusOK) + } + size, err := rw.ResponseWriter.Write(b) + rw.size += size + return size, err +} + +func (rw *responseWriter) Status() int { + return rw.status +} + +func (rw *responseWriter) Size() int { + return rw.size +} + +func (rw *responseWriter) Written() bool { + return rw.status != 0 +} + +func (rw *responseWriter) Before(before func(ResponseWriter)) { + rw.beforeFuncs = append(rw.beforeFuncs, before) +} + +func (rw *responseWriter) Hijack() (net.Conn, *bufio.ReadWriter, error) { + hijacker, ok := rw.ResponseWriter.(http.Hijacker) + if !ok { + return nil, nil, errors.New("the ResponseWriter doesn't support the Hijacker interface") + } + return hijacker.Hijack() +} + +func (rw *responseWriter) callBefore() { + for i := len(rw.beforeFuncs) - 1; i >= 0; i-- { + rw.beforeFuncs[i](rw) + } +} + +func (rw *responseWriter) Flush() { + flusher, ok := rw.ResponseWriter.(http.Flusher) + if ok { + if !rw.Written() { + // The status will be StatusOK if WriteHeader has not been called yet + rw.WriteHeader(http.StatusOK) + } + flusher.Flush() + } +} + +// Deprecated: the CloseNotifier interface predates Go's context package. +// New code should use Request.Context instead. +// +// We still implement it for backwards compatibliity with older versions of Go +type responseWriterCloseNotifer struct { + *responseWriter +} + +func (rw *responseWriterCloseNotifer) CloseNotify() <-chan bool { + return rw.ResponseWriter.(http.CloseNotifier).CloseNotify() +} diff --git a/vendor/github.com/urfave/negroni/v2/response_writer_pusher.go b/vendor/github.com/urfave/negroni/v2/response_writer_pusher.go new file mode 100644 index 0000000..363e908 --- /dev/null +++ b/vendor/github.com/urfave/negroni/v2/response_writer_pusher.go @@ -0,0 +1,16 @@ +//+build go1.8 + +package negroni + +import ( + "errors" + "net/http" +) + +func (rw *responseWriter) Push(target string, opts *http.PushOptions) error { + pusher, ok := rw.ResponseWriter.(http.Pusher) + if ok { + return pusher.Push(target, opts) + } + return errors.New("the ResponseWriter doesn't support the Pusher interface") +} diff --git a/vendor/github.com/urfave/negroni/v2/static.go b/vendor/github.com/urfave/negroni/v2/static.go new file mode 100644 index 0000000..34be967 --- /dev/null +++ b/vendor/github.com/urfave/negroni/v2/static.go @@ -0,0 +1,88 @@ +package negroni + +import ( + "net/http" + "path" + "strings" +) + +// Static is a middleware handler that serves static files in the given +// directory/filesystem. If the file does not exist on the filesystem, it +// passes along to the next middleware in the chain. If you desire "fileserver" +// type behavior where it returns a 404 for unfound files, you should consider +// using http.FileServer from the Go stdlib. +type Static struct { + // Dir is the directory to serve static files from + Dir http.FileSystem + // Prefix is the optional prefix used to serve the static directory content + Prefix string + // IndexFile defines which file to serve as index if it exists. + IndexFile string +} + +// NewStatic returns a new instance of Static +func NewStatic(directory http.FileSystem) *Static { + return &Static{ + Dir: directory, + Prefix: "", + IndexFile: "index.html", + } +} + +func (s *Static) ServeHTTP(rw http.ResponseWriter, r *http.Request, next http.HandlerFunc) { + if r.Method != "GET" && r.Method != "HEAD" { + next(rw, r) + return + } + file := r.URL.Path + // if we have a prefix, filter requests by stripping the prefix + if s.Prefix != "" { + if !strings.HasPrefix(file, s.Prefix) { + next(rw, r) + return + } + file = file[len(s.Prefix):] + if file != "" && file[0] != '/' { + next(rw, r) + return + } + } + f, err := s.Dir.Open(file) + if err != nil { + // discard the error? + next(rw, r) + return + } + defer f.Close() + + fi, err := f.Stat() + if err != nil { + next(rw, r) + return + } + + // try to serve index file + if fi.IsDir() { + // redirect if missing trailing slash + if !strings.HasSuffix(r.URL.Path, "/") { + http.Redirect(rw, r, r.URL.Path+"/", http.StatusFound) + return + } + + file = path.Join(file, s.IndexFile) + f, err = s.Dir.Open(file) + if err != nil { + next(rw, r) + return + } + defer f.Close() + + fi, err = f.Stat() + if err != nil || fi.IsDir() { + next(rw, r) + return + } + } + + http.ServeContent(rw, r, file, fi.ModTime(), f) +} diff --git a/vendor/modules.txt b/vendor/modules.txt index 60c2a0a..318c20a 100644 --- a/vendor/modules.txt +++ b/vendor/modules.txt @@ -149,6 +149,9 @@ github.com/tklauser/numcpus # github.com/urfave/negroni v1.0.0 ## explicit github.com/urfave/negroni +# github.com/urfave/negroni/v2 v2.0.2 +## explicit +github.com/urfave/negroni/v2 # golang.org/x/sys v0.27.0 ## explicit; go 1.18 golang.org/x/sys/unix From 8703251d1fec7a013dfdadcaa78dea068e08c047 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=89tienne=20Michon?= Date: Mon, 23 Dec 2024 11:42:50 +0100 Subject: [PATCH 3/4] build(go.mod): update 'github.com/urfave/negroni' from v2 to v3 --- cmd/acadock-monitoring/main.go | 5 +- go.mod | 2 +- go.sum | 4 +- .../github.com/urfave/negroni/v2/.travis.yml | 30 ----- .../urfave/negroni/{v2 => v3}/.gitignore | 0 .../github.com/urfave/negroni/v3/.travis.yml | 56 +++++++++ .../urfave/negroni/{v2 => v3}/CHANGELOG.md | 40 ++++++- .../urfave/negroni/{v2 => v3}/LICENSE | 0 .../urfave/negroni/{v2 => v3}/README.md | 63 ++++++----- .../urfave/negroni/{v2 => v3}/doc.go | 0 .../urfave/negroni/{v2 => v3}/logger.go | 0 .../urfave/negroni/{v2 => v3}/negroni.go | 4 + .../urfave/negroni/{v2 => v3}/recovery.go | 0 .../negroni/{v2 => v3}/response_writer.go | 100 ++++++++-------- .../negroni/v3/response_writer_feature.go | 107 ++++++++++++++++++ .../{v2 => v3}/response_writer_pusher.go | 0 .../urfave/negroni/{v2 => v3}/static.go | 3 + vendor/modules.txt | 4 +- 18 files changed, 303 insertions(+), 115 deletions(-) delete mode 100644 vendor/github.com/urfave/negroni/v2/.travis.yml rename vendor/github.com/urfave/negroni/{v2 => v3}/.gitignore (100%) create mode 100644 vendor/github.com/urfave/negroni/v3/.travis.yml rename vendor/github.com/urfave/negroni/{v2 => v3}/CHANGELOG.md (76%) rename vendor/github.com/urfave/negroni/{v2 => v3}/LICENSE (100%) rename vendor/github.com/urfave/negroni/{v2 => v3}/README.md (64%) rename vendor/github.com/urfave/negroni/{v2 => v3}/doc.go (100%) rename vendor/github.com/urfave/negroni/{v2 => v3}/logger.go (100%) rename vendor/github.com/urfave/negroni/{v2 => v3}/negroni.go (99%) rename vendor/github.com/urfave/negroni/{v2 => v3}/recovery.go (100%) rename vendor/github.com/urfave/negroni/{v2 => v3}/response_writer.go (54%) create mode 100644 vendor/github.com/urfave/negroni/v3/response_writer_feature.go rename vendor/github.com/urfave/negroni/{v2 => v3}/response_writer_pusher.go (100%) rename vendor/github.com/urfave/negroni/{v2 => v3}/static.go (94%) diff --git a/cmd/acadock-monitoring/main.go b/cmd/acadock-monitoring/main.go index ad0523d..0730e80 100644 --- a/cmd/acadock-monitoring/main.go +++ b/cmd/acadock-monitoring/main.go @@ -9,7 +9,7 @@ import ( "os" "github.com/gorilla/mux" - "github.com/urfave/negroni/v2" + "github.com/urfave/negroni/v3" "github.com/Scalingo/acadock-monitoring/config" "github.com/Scalingo/acadock-monitoring/cpu" @@ -116,8 +116,7 @@ func main() { s := graceful.NewService() - err = s.ListenAndServe(ctx, "tcp", - ":"+config.ENV["PORT"], n) + err = s.ListenAndServe(ctx, "tcp", ":"+config.ENV["PORT"], n) if err != nil { log.WithError(err).Error("fail to stop http server") } diff --git a/go.mod b/go.mod index 311b25a..508dc11 100644 --- a/go.mod +++ b/go.mod @@ -15,7 +15,7 @@ require ( github.com/sirupsen/logrus v1.9.3 github.com/stretchr/testify v1.10.0 github.com/tklauser/go-sysconf v0.3.14 - github.com/urfave/negroni/v2 v2.0.2 + github.com/urfave/negroni/v3 v3.1.1 ) require ( diff --git a/go.sum b/go.sum index 208da76..70da4e2 100644 --- a/go.sum +++ b/go.sum @@ -102,8 +102,8 @@ github.com/tklauser/numcpus v0.9.0 h1:lmyCHtANi8aRUgkckBgoDk1nHCux3n2cgkJLXdQGPD github.com/tklauser/numcpus v0.9.0/go.mod h1:SN6Nq1O3VychhC1npsWostA+oW+VOQTxZrS604NSRyI= github.com/urfave/negroni v1.0.0 h1:kIimOitoypq34K7TG7DUaJ9kq/N4Ofuwi1sjz0KipXc= github.com/urfave/negroni v1.0.0/go.mod h1:Meg73S6kFm/4PpbYdq35yYWoCZ9mS/YSx+lKnmiohz4= -github.com/urfave/negroni/v2 v2.0.2 h1:27gJcVxYJ2a/ytEoCHoJ7ybvyhymV4cAhGuMxkyCsrU= -github.com/urfave/negroni/v2 v2.0.2/go.mod h1:SjdApKzYrObukpN/NnlejbQiZWIUjfDFzQltScGYigI= +github.com/urfave/negroni/v3 v3.1.1 h1:6MS4nG9Jk/UuCACaUlNXCbiKa0ywF9LXz5dGu09v8hw= +github.com/urfave/negroni/v3 v3.1.1/go.mod h1:jWvnX03kcSjDBl/ShB0iHvx5uOs7mAzZXW+JvJ5XYAs= github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= github.com/yuin/goldmark v1.3.5/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k= diff --git a/vendor/github.com/urfave/negroni/v2/.travis.yml b/vendor/github.com/urfave/negroni/v2/.travis.yml deleted file mode 100644 index b6cb89f..0000000 --- a/vendor/github.com/urfave/negroni/v2/.travis.yml +++ /dev/null @@ -1,30 +0,0 @@ -language: go - -sudo: false -dist: trusty - -go: -- 1.x -- 1.2.x -- 1.3.x -- 1.4.x -- 1.5.x -- 1.6.x -- 1.7.x -- 1.8.x -- 1.9.x -- 1.10.x -- 1.11.x -- master - -before_install: -- find "${GOPATH%%:*}" -name '*.a' -delete -- rm -rf "${GOPATH%%:*}/src/golang.org" -- go get golang.org/x/tools/cover -- go get golang.org/x/tools/cmd/cover - -script: -- go test -race -coverprofile=coverage.txt -covermode=atomic - -after_success: -- bash <(curl -s "https://codecov.io/bash") diff --git a/vendor/github.com/urfave/negroni/v2/.gitignore b/vendor/github.com/urfave/negroni/v3/.gitignore similarity index 100% rename from vendor/github.com/urfave/negroni/v2/.gitignore rename to vendor/github.com/urfave/negroni/v3/.gitignore diff --git a/vendor/github.com/urfave/negroni/v3/.travis.yml b/vendor/github.com/urfave/negroni/v3/.travis.yml new file mode 100644 index 0000000..4168bbf --- /dev/null +++ b/vendor/github.com/urfave/negroni/v3/.travis.yml @@ -0,0 +1,56 @@ +language: go + +sudo: false +dist: trusty +arch: + - AMD64 + - ppc64le + +go: +- 1.x +- 1.2.x +- 1.3.x +- 1.4.x +- 1.5.x +- 1.6.x +- 1.7.x +- 1.8.x +- 1.9.x +- 1.10.x +- 1.11.x +- master + +# Disable version 1.x, 1.2.x, 1.3.x, 1.4.x, 1.5.x, 1.6.x, 1.7.x, 1.8.x, 1.9.x, 1.10.x +jobs: + exclude: + - arch: ppc64le + go: 1.x + - arch: ppc64le + go: 1.2.x + - arch: ppc64le + go: 1.3.x + - arch: ppc64le + go: 1.4.x + - arch: ppc64le + go: 1.5.x + - arch: ppc64le + go: 1.6.x + - arch: ppc64le + go: 1.7.x + - arch: ppc64le + go: 1.8.x + - arch: ppc64le + go: 1.9.x + - arch: ppc64le + go: 1.10.x +before_install: +- find "${GOPATH%%:*}" -name '*.a' -delete +- rm -rf "${GOPATH%%:*}/src/golang.org" +- go get golang.org/x/tools/cover +- go get golang.org/x/tools/cmd/cover + +script: +- go test -race -coverprofile=coverage.txt -covermode=atomic + +after_success: +- bash <(curl -s "https://codecov.io/bash") diff --git a/vendor/github.com/urfave/negroni/v2/CHANGELOG.md b/vendor/github.com/urfave/negroni/v3/CHANGELOG.md similarity index 76% rename from vendor/github.com/urfave/negroni/v2/CHANGELOG.md rename to vendor/github.com/urfave/negroni/v3/CHANGELOG.md index de086f2..74cb729 100644 --- a/vendor/github.com/urfave/negroni/v2/CHANGELOG.md +++ b/vendor/github.com/urfave/negroni/v3/CHANGELOG.md @@ -2,7 +2,45 @@ **ATTN**: This project uses [semantic versioning](http://semver.org/). -## [Unreleased] - +## [3.1.1] - [2024-06-04] + +### Fixed + +- Writing an HTTP 1xx status codes no longer results in a 200 being sent in + addition given the expectation is that a follow-up status code will be written + later. The exception is `101 Switching Protocols` since this is terminal. This + matches `net/http` behavior. + +## [3.1.0] - [2023-10-07] + +### Fixed + +- `WriteHeader` can again be used in the `ResponseWriter.Before` callback to + set HTTP status codes + +### Added + +- Satisfy `http.ResponseController` (Go 1.20+) + +## [3.0.0] - [2022-09-18] + +### Fixed + +- Replace multiple slashes at the beginning of a path with a single one to avoid + open redirects +- Avoid updating `ResponseWriter.Status()` if the status has already been + written when `ResponseWriter.WriteHeader()` is called twice + +### Changed + +- `ResponseWriter` now only implements `http` interfaces (`Flusher`, `Hijacker`, + `CloseNotifier`) if the wrapped `http.ResponseWriter` does. This is a breaking + change to make `ResponseWriter`'s interface support more accurate + +### Added + +- `ResponseWriter` now implements `io.ReaderFrom` to more efficiently send + responses via `io.Copy` ## [2.0.2] - 2020-07-17 diff --git a/vendor/github.com/urfave/negroni/v2/LICENSE b/vendor/github.com/urfave/negroni/v3/LICENSE similarity index 100% rename from vendor/github.com/urfave/negroni/v2/LICENSE rename to vendor/github.com/urfave/negroni/v3/LICENSE diff --git a/vendor/github.com/urfave/negroni/v2/README.md b/vendor/github.com/urfave/negroni/v3/README.md similarity index 64% rename from vendor/github.com/urfave/negroni/v2/README.md rename to vendor/github.com/urfave/negroni/v3/README.md index 13b2e6d..6691519 100644 --- a/vendor/github.com/urfave/negroni/v2/README.md +++ b/vendor/github.com/urfave/negroni/v3/README.md @@ -192,6 +192,7 @@ func main() { n.Run(":8080") } ``` + If no address is provided, the `PORT` environment variable is used instead. If the `PORT` environment variable is not defined, the default address will be used. See [Run](https://godoc.org/github.com/urfave/negroni#Negroni.Run) for a complete description. @@ -492,37 +493,37 @@ will show something like - `[200 18.263µs] - Go-User-Agent/1.1 ` Here is a current list of Negroni compatible middlware. Feel free to put up a PR linking your middleware if you have built one: -| Middleware | Author | Description | -| -----------|--------|-------------| -| [authz](https://github.com/casbin/negroni-authz) | [Yang Luo](https://github.com/hsluoyz) | ACL, RBAC, ABAC Authorization middlware based on [Casbin](https://github.com/casbin/casbin) | -| [binding](https://github.com/mholt/binding) | [Matt Holt](https://github.com/mholt) | Data binding from HTTP requests into structs | -| [cloudwatch](https://github.com/cvillecsteele/negroni-cloudwatch) | [Colin Steele](https://github.com/cvillecsteele) | AWS cloudwatch metrics middleware | -| [cors](https://github.com/rs/cors) | [Olivier Poitrey](https://github.com/rs) | [Cross Origin Resource Sharing](http://www.w3.org/TR/cors/) (CORS) support | -| [csp](https://github.com/awakenetworks/csp) | [Awake Networks](https://github.com/awakenetworks) | [Content Security Policy](https://www.w3.org/TR/CSP2/) (CSP) support | -| [delay](https://github.com/jeffbmartinez/delay) | [Jeff Martinez](https://github.com/jeffbmartinez) | Add delays/latency to endpoints. Useful when testing effects of high latency | -| [New Relic Go Agent](https://github.com/yadvendar/negroni-newrelic-go-agent) | [Yadvendar Champawat](https://github.com/yadvendar) | Official [New Relic Go Agent](https://github.com/newrelic/go-agent) (currently in beta) | -| [gorelic](https://github.com/jingweno/negroni-gorelic) | [Jingwen Owen Ou](https://github.com/jingweno) | New Relic agent for Go runtime | -| [Graceful](https://github.com/tylerb/graceful) | [Tyler Bunnell](https://github.com/tylerb) | Graceful HTTP Shutdown | -| [gzip](https://github.com/phyber/negroni-gzip) | [phyber](https://github.com/phyber) | GZIP response compression | -| [JWT Middleware](https://github.com/auth0/go-jwt-middleware) | [Auth0](https://github.com/auth0) | Middleware checks for a JWT on the `Authorization` header on incoming requests and decodes it| -| [JWT Middleware](https://github.com/mfuentesg/go-jwtmiddleware) | [Marcelo Fuentes](https://github.com/mfuentesg) | JWT middleware for golang | -| [logrus](https://github.com/meatballhat/negroni-logrus) | [Dan Buch](https://github.com/meatballhat) | Logrus-based logger | -| [oauth2](https://github.com/goincremental/negroni-oauth2) | [David Bochenski](https://github.com/bochenski) | oAuth2 middleware | -| [onthefly](https://github.com/xyproto/onthefly) | [Alexander Rødseth](https://github.com/xyproto) | Generate TinySVG, HTML and CSS on the fly | -| [permissions2](https://github.com/xyproto/permissions2) | [Alexander Rødseth](https://github.com/xyproto) | Cookies, users and permissions | -| [prometheus](https://github.com/zbindenren/negroni-prometheus) | [Rene Zbinden](https://github.com/zbindenren) | Easily create metrics endpoint for the [prometheus](http://prometheus.io) instrumentation tool | -| [prometheus](https://github.com/slok/go-prometheus-middleware) | [Xabier Larrakoetxea](https://github.com/slok) | [Prometheus](http://prometheus.io) metrics with multiple options that follow standards and try to be measured in a efficent way | -| [render](https://github.com/unrolled/render) | [Cory Jacobsen](https://github.com/unrolled) | Render JSON, XML and HTML templates | -| [RestGate](https://github.com/pjebs/restgate) | [Prasanga Siripala](https://github.com/pjebs) | Secure authentication for REST API endpoints | -| [secure](https://github.com/unrolled/secure) | [Cory Jacobsen](https://github.com/unrolled) | Middleware that implements a few quick security wins | -| [sessions](https://github.com/goincremental/negroni-sessions) | [David Bochenski](https://github.com/bochenski) | Session Management | -| [stats](https://github.com/thoas/stats) | [Florent Messa](https://github.com/thoas) | Store information about your web application (response time, etc.) | -| [VanGoH](https://github.com/auroratechnologies/vangoh) | [Taylor Wrobel](https://github.com/twrobel3) | Configurable [AWS-Style](http://docs.aws.amazon.com/AmazonS3/latest/dev/RESTAuthentication.html) HMAC authentication middleware | -| [xrequestid](https://github.com/pilu/xrequestid) | [Andrea Franz](https://github.com/pilu) | Middleware that assigns a random X-Request-Id header to each request | -| [mgo session](https://github.com/joeljames/nigroni-mgo-session) | [Joel James](https://github.com/joeljames) | Middleware that handles creating and closing mgo sessions per request | -| [digits](https://github.com/bamarni/digits) | [Bilal Amarni](https://github.com/bamarni) | Middleware that handles [Twitter Digits](https://get.digits.com/) authentication | -| [stats](https://github.com/guptachirag/stats) | [Chirag Gupta](https://github.com/guptachirag/stats) | Middleware that manages qps and latency stats for your endpoints and asynchronously flushes them to influx db | -| [Chaos](https://github.com/falzm/chaos) | [Marc Falzon](https://github.com/falzm) | Middleware for injecting chaotic behavior into application in a programmatic way | +| Middleware | Author | Description | +| ---------------------------------------------------------------------------- | ---------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------- | +| [authz](https://github.com/casbin/negroni-authz) | [Yang Luo](https://github.com/hsluoyz) | ACL, RBAC, ABAC Authorization middlware based on [Casbin](https://github.com/casbin/casbin) | +| [binding](https://github.com/mholt/binding) | [Matt Holt](https://github.com/mholt) | Data binding from HTTP requests into structs | +| [cloudwatch](https://github.com/cvillecsteele/negroni-cloudwatch) | [Colin Steele](https://github.com/cvillecsteele) | AWS cloudwatch metrics middleware | +| [cors](https://github.com/rs/cors) | [Olivier Poitrey](https://github.com/rs) | [Cross Origin Resource Sharing](http://www.w3.org/TR/cors/) (CORS) support | +| [csp](https://github.com/awakenetworks/csp) | [Awake Networks](https://github.com/awakenetworks) | [Content Security Policy](https://www.w3.org/TR/CSP2/) (CSP) support | +| [delay](https://github.com/jeffbmartinez/delay) | [Jeff Martinez](https://github.com/jeffbmartinez) | Add delays/latency to endpoints. Useful when testing effects of high latency | +| [New Relic Go Agent](https://github.com/yadvendar/negroni-newrelic-go-agent) | [Yadvendar Champawat](https://github.com/yadvendar) | Official [New Relic Go Agent](https://github.com/newrelic/go-agent) (currently in beta) | +| [gorelic](https://github.com/jingweno/negroni-gorelic) | [Jingwen Owen Ou](https://github.com/jingweno) | New Relic agent for Go runtime | +| [Graceful](https://github.com/tylerb/graceful) | [Tyler Bunnell](https://github.com/tylerb) | Graceful HTTP Shutdown | +| [gzip](https://github.com/phyber/negroni-gzip) | [phyber](https://github.com/phyber) | GZIP response compression | +| [JWT Middleware](https://github.com/auth0/go-jwt-middleware) | [Auth0](https://github.com/auth0) | Middleware checks for a JWT on the `Authorization` header on incoming requests and decodes it | +| [JWT Middleware](https://github.com/mfuentesg/go-jwtmiddleware) | [Marcelo Fuentes](https://github.com/mfuentesg) | JWT middleware for golang | +| [logrus](https://github.com/meatballhat/negroni-logrus) | [Dan Buch](https://github.com/meatballhat) | Logrus-based logger | +| [oauth2](https://github.com/goincremental/negroni-oauth2) | [David Bochenski](https://github.com/bochenski) | oAuth2 middleware | +| [onthefly](https://github.com/xyproto/onthefly) | [Alexander Rødseth](https://github.com/xyproto) | Generate TinySVG, HTML and CSS on the fly | +| [permissions2](https://github.com/xyproto/permissions2) | [Alexander Rødseth](https://github.com/xyproto) | Cookies, users and permissions | +| [prometheus](https://github.com/zbindenren/negroni-prometheus) | [Rene Zbinden](https://github.com/zbindenren) | Easily create metrics endpoint for the [prometheus](http://prometheus.io) instrumentation tool | +| [prometheus](https://github.com/slok/go-prometheus-middleware) | [Xabier Larrakoetxea](https://github.com/slok) | [Prometheus](http://prometheus.io) metrics with multiple options that follow standards and try to be measured in a efficient way | +| [render](https://github.com/unrolled/render) | [Cory Jacobsen](https://github.com/unrolled) | Render JSON, XML and HTML templates | +| [RestGate](https://github.com/pjebs/restgate) | [Prasanga Siripala](https://github.com/pjebs) | Secure authentication for REST API endpoints | +| [secure](https://github.com/unrolled/secure) | [Cory Jacobsen](https://github.com/unrolled) | Middleware that implements a few quick security wins | +| [sessions](https://github.com/goincremental/negroni-sessions) | [David Bochenski](https://github.com/bochenski) | Session Management | +| [stats](https://github.com/thoas/stats) | [Florent Messa](https://github.com/thoas) | Store information about your web application (response time, etc.) | +| [VanGoH](https://github.com/auroratechnologies/vangoh) | [Taylor Wrobel](https://github.com/twrobel3) | Configurable [AWS-Style](http://docs.aws.amazon.com/AmazonS3/latest/dev/RESTAuthentication.html) HMAC authentication middleware | +| [xrequestid](https://github.com/pilu/xrequestid) | [Andrea Franz](https://github.com/pilu) | Middleware that assigns a random X-Request-Id header to each request | +| [mgo session](https://github.com/joeljames/nigroni-mgo-session) | [Joel James](https://github.com/joeljames) | Middleware that handles creating and closing mgo sessions per request | +| [digits](https://github.com/bamarni/digits) | [Bilal Amarni](https://github.com/bamarni) | Middleware that handles [Twitter Digits](https://get.digits.com/) authentication | +| [stats](https://github.com/guptachirag/stats) | [Chirag Gupta](https://github.com/guptachirag/stats) | Middleware that manages qps and latency stats for your endpoints and asynchronously flushes them to influx db | +| [Chaos](https://github.com/falzm/chaos) | [Marc Falzon](https://github.com/falzm) | Middleware for injecting chaotic behavior into application in a programmatic way | ## Examples diff --git a/vendor/github.com/urfave/negroni/v2/doc.go b/vendor/github.com/urfave/negroni/v3/doc.go similarity index 100% rename from vendor/github.com/urfave/negroni/v2/doc.go rename to vendor/github.com/urfave/negroni/v3/doc.go diff --git a/vendor/github.com/urfave/negroni/v2/logger.go b/vendor/github.com/urfave/negroni/v3/logger.go similarity index 100% rename from vendor/github.com/urfave/negroni/v2/logger.go rename to vendor/github.com/urfave/negroni/v3/logger.go diff --git a/vendor/github.com/urfave/negroni/v2/negroni.go b/vendor/github.com/urfave/negroni/v3/negroni.go similarity index 99% rename from vendor/github.com/urfave/negroni/v2/negroni.go rename to vendor/github.com/urfave/negroni/v3/negroni.go index c0fa2d4..7471bbb 100644 --- a/vendor/github.com/urfave/negroni/v2/negroni.go +++ b/vendor/github.com/urfave/negroni/v3/negroni.go @@ -11,6 +11,10 @@ const ( DefaultAddress = ":8080" ) +func init() { + initFeaturePicker() +} + // Handler handler is an interface that objects can implement to be registered to serve as middleware // in the Negroni middleware stack. // ServeHTTP should yield to the next middleware in the chain by invoking the next http.HandlerFunc diff --git a/vendor/github.com/urfave/negroni/v2/recovery.go b/vendor/github.com/urfave/negroni/v3/recovery.go similarity index 100% rename from vendor/github.com/urfave/negroni/v2/recovery.go rename to vendor/github.com/urfave/negroni/v3/recovery.go diff --git a/vendor/github.com/urfave/negroni/v2/response_writer.go b/vendor/github.com/urfave/negroni/v3/response_writer.go similarity index 54% rename from vendor/github.com/urfave/negroni/v2/response_writer.go rename to vendor/github.com/urfave/negroni/v3/response_writer.go index 2066d5f..524956e 100644 --- a/vendor/github.com/urfave/negroni/v2/response_writer.go +++ b/vendor/github.com/urfave/negroni/v3/response_writer.go @@ -1,9 +1,7 @@ package negroni import ( - "bufio" - "errors" - "net" + "io" "net/http" ) @@ -12,7 +10,7 @@ import ( // if the functionality calls for it. type ResponseWriter interface { http.ResponseWriter - http.Flusher + // Status returns the status code of the response or 0 if the response has // not been written Status() int @@ -27,29 +25,39 @@ type ResponseWriter interface { type beforeFunc func(ResponseWriter) -// NewResponseWriter creates a ResponseWriter that wraps an http.ResponseWriter +// NewResponseWriter creates a ResponseWriter that wraps a http.ResponseWriter func NewResponseWriter(rw http.ResponseWriter) ResponseWriter { nrw := &responseWriter{ ResponseWriter: rw, } - if _, ok := rw.(http.CloseNotifier); ok { - return &responseWriterCloseNotifer{nrw} - } - - return nrw + return wrapFeature(nrw) } type responseWriter struct { http.ResponseWriter - status int - size int - beforeFuncs []beforeFunc + pendingStatus int + status int + size int + beforeFuncs []beforeFunc + callingBefores bool } func (rw *responseWriter) WriteHeader(s int) { - rw.status = s + if rw.Written() { + return + } + + rw.pendingStatus = s rw.callBefore() + + // Any of the rw.beforeFuncs may have written a header, + // so check again to see if any work is necessary. + if rw.Written() { + return + } + + rw.status = s rw.ResponseWriter.WriteHeader(s) } @@ -63,8 +71,30 @@ func (rw *responseWriter) Write(b []byte) (int, error) { return size, err } +// ReadFrom exposes underlying http.ResponseWriter to io.Copy and if it implements +// io.ReaderFrom, it can take advantage of optimizations such as sendfile, io.Copy +// with sync.Pool's buffer which is in http.(*response).ReadFrom and so on. +func (rw *responseWriter) ReadFrom(r io.Reader) (n int64, err error) { + if !rw.Written() { + // The status will be StatusOK if WriteHeader has not been called yet + rw.WriteHeader(http.StatusOK) + } + n, err = io.Copy(rw.ResponseWriter, r) + rw.size += int(n) + return +} + +// Satisfy http.ResponseController support (Go 1.20+) +func (rw *responseWriter) Unwrap() http.ResponseWriter { + return rw.ResponseWriter +} + func (rw *responseWriter) Status() int { - return rw.status + if rw.Written() { + return rw.status + } + + return rw.pendingStatus } func (rw *responseWriter) Size() int { @@ -72,46 +102,24 @@ func (rw *responseWriter) Size() int { } func (rw *responseWriter) Written() bool { - return rw.status != 0 + return rw.status >= http.StatusOK || rw.status == http.StatusSwitchingProtocols // treat all 1xx codes aside from SwitchingProtocols as non-terminal } func (rw *responseWriter) Before(before func(ResponseWriter)) { rw.beforeFuncs = append(rw.beforeFuncs, before) } -func (rw *responseWriter) Hijack() (net.Conn, *bufio.ReadWriter, error) { - hijacker, ok := rw.ResponseWriter.(http.Hijacker) - if !ok { - return nil, nil, errors.New("the ResponseWriter doesn't support the Hijacker interface") +func (rw *responseWriter) callBefore() { + // Don't recursively call before() functions, to avoid infinite looping if + // one of them calls rw.WriteHeader again. + if rw.callingBefores { + return } - return hijacker.Hijack() -} -func (rw *responseWriter) callBefore() { + rw.callingBefores = true + defer func() { rw.callingBefores = false }() + for i := len(rw.beforeFuncs) - 1; i >= 0; i-- { rw.beforeFuncs[i](rw) } } - -func (rw *responseWriter) Flush() { - flusher, ok := rw.ResponseWriter.(http.Flusher) - if ok { - if !rw.Written() { - // The status will be StatusOK if WriteHeader has not been called yet - rw.WriteHeader(http.StatusOK) - } - flusher.Flush() - } -} - -// Deprecated: the CloseNotifier interface predates Go's context package. -// New code should use Request.Context instead. -// -// We still implement it for backwards compatibliity with older versions of Go -type responseWriterCloseNotifer struct { - *responseWriter -} - -func (rw *responseWriterCloseNotifer) CloseNotify() <-chan bool { - return rw.ResponseWriter.(http.CloseNotifier).CloseNotify() -} diff --git a/vendor/github.com/urfave/negroni/v3/response_writer_feature.go b/vendor/github.com/urfave/negroni/v3/response_writer_feature.go new file mode 100644 index 0000000..96c9b33 --- /dev/null +++ b/vendor/github.com/urfave/negroni/v3/response_writer_feature.go @@ -0,0 +1,107 @@ +package negroni + +import ( + "bufio" + "net" + "net/http" +) + +const ( + flusher = 1 << iota + hijacker + closeNotifier +) + +type ( + flusherFeature struct{ *responseWriter } + hijackerFeature struct{ *responseWriter } + closeNotifierFeature struct{ *responseWriter } +) + +func (f flusherFeature) Flush() { + if !f.Written() { + // The status will be StatusOK if WriteHeader has not been called yet + f.WriteHeader(http.StatusOK) + } + f.ResponseWriter.(http.Flusher).Flush() +} + +func (f hijackerFeature) Hijack() (net.Conn, *bufio.ReadWriter, error) { + return f.ResponseWriter.(http.Hijacker).Hijack() +} + +func (f closeNotifierFeature) CloseNotify() <-chan bool { + return f.ResponseWriter.(http.CloseNotifier).CloseNotify() +} + +var featurePicker = make([]func(writer *responseWriter) ResponseWriter, 8) + +func initFeaturePicker() { + featurePicker[0] = func(w *responseWriter) ResponseWriter { + return w + } + featurePicker[flusher] = func(w *responseWriter) ResponseWriter { + return struct { + *responseWriter + http.Flusher + }{w, flusherFeature{w}} + } + featurePicker[hijacker] = func(w *responseWriter) ResponseWriter { + return struct { + *responseWriter + http.Hijacker + }{w, hijackerFeature{w}} + } + featurePicker[closeNotifier] = func(w *responseWriter) ResponseWriter { + return struct { + *responseWriter + http.Flusher + }{w, flusherFeature{w}} + } + featurePicker[flusher|hijacker] = func(w *responseWriter) ResponseWriter { + return struct { + *responseWriter + http.Flusher + http.Hijacker + }{w, flusherFeature{w}, hijackerFeature{w}} + } + featurePicker[flusher|closeNotifier] = func(w *responseWriter) ResponseWriter { + return struct { + *responseWriter + http.Flusher + http.CloseNotifier + }{w, flusherFeature{w}, closeNotifierFeature{w}} + } + featurePicker[hijacker|closeNotifier] = func(w *responseWriter) ResponseWriter { + return struct { + *responseWriter + http.Hijacker + http.CloseNotifier + }{w, hijackerFeature{w}, closeNotifierFeature{w}} + } + featurePicker[flusher|hijacker|closeNotifier] = func(w *responseWriter) ResponseWriter { + return struct { + *responseWriter + http.Flusher + http.Hijacker + http.CloseNotifier + }{w, flusherFeature{w}, hijackerFeature{w}, closeNotifierFeature{w}} + } +} + +func wrapFeature(w *responseWriter) ResponseWriter { + rw := w.ResponseWriter + + feature := 0 + if _, ok := rw.(http.Flusher); ok { + feature |= flusher + } + if _, ok := rw.(http.Hijacker); ok { + feature |= hijacker + } + if _, ok := rw.(http.CloseNotifier); ok { + feature |= closeNotifier + } + + return featurePicker[feature](w) +} diff --git a/vendor/github.com/urfave/negroni/v2/response_writer_pusher.go b/vendor/github.com/urfave/negroni/v3/response_writer_pusher.go similarity index 100% rename from vendor/github.com/urfave/negroni/v2/response_writer_pusher.go rename to vendor/github.com/urfave/negroni/v3/response_writer_pusher.go diff --git a/vendor/github.com/urfave/negroni/v2/static.go b/vendor/github.com/urfave/negroni/v3/static.go similarity index 94% rename from vendor/github.com/urfave/negroni/v2/static.go rename to vendor/github.com/urfave/negroni/v3/static.go index 34be967..3ce44f9 100644 --- a/vendor/github.com/urfave/negroni/v2/static.go +++ b/vendor/github.com/urfave/negroni/v3/static.go @@ -65,6 +65,9 @@ func (s *Static) ServeHTTP(rw http.ResponseWriter, r *http.Request, next http.Ha if fi.IsDir() { // redirect if missing trailing slash if !strings.HasSuffix(r.URL.Path, "/") { + if strings.HasPrefix(r.URL.Path, "//") { + r.URL.Path = "/" + strings.TrimLeft(r.URL.Path, "/") + } http.Redirect(rw, r, r.URL.Path+"/", http.StatusFound) return } diff --git a/vendor/modules.txt b/vendor/modules.txt index 318c20a..011b427 100644 --- a/vendor/modules.txt +++ b/vendor/modules.txt @@ -151,7 +151,9 @@ github.com/tklauser/numcpus github.com/urfave/negroni # github.com/urfave/negroni/v2 v2.0.2 ## explicit -github.com/urfave/negroni/v2 +# github.com/urfave/negroni/v3 v3.1.1 +## explicit; go 1.17 +github.com/urfave/negroni/v3 # golang.org/x/sys v0.27.0 ## explicit; go 1.18 golang.org/x/sys/unix From f00b063d2da4771189cedc99363a37fa838bdfd6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=89tienne=20Michon?= Date: Mon, 23 Dec 2024 11:44:56 +0100 Subject: [PATCH 4/4] docs(changelog): add missing entry --- CHANGELOG.md | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index aee7c55..a3429a1 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,7 +2,8 @@ ## To Be Released -* chore(go): use go 1.22.4 +* build(go.mod): update `github.com/urfave/negroni` from v1 to v3 +* chore(go): use Go 1.22.10 * use github.com/Scalingo/go-utils/graceful for graceful upgrades and shutdowns ## v1.2.1 - 2023-12-27