diff --git a/README.md b/README.md index ede2997bb..1f23f98ca 100644 --- a/README.md +++ b/README.md @@ -1,98 +1,97 @@ -[![Sourcegraph](https://sourcegraph.com/github.com/labstack/echo/-/badge.svg?style=flat-square)](https://sourcegraph.com/github.com/labstack/echo?badge) -[![GoDoc](http://img.shields.io/badge/go-documentation-blue.svg?style=flat-square)](https://pkg.go.dev/github.com/labstack/echo/v4) -[![Go Report Card](https://goreportcard.com/badge/github.com/labstack/echo?style=flat-square)](https://goreportcard.com/report/github.com/labstack/echo) -[![GitHub Workflow Status (with event)](https://img.shields.io/github/actions/workflow/status/labstack/echo/echo.yml?style=flat-square)](https://github.com/labstack/echo/actions) -[![Codecov](https://img.shields.io/codecov/c/github/labstack/echo.svg?style=flat-square)](https://codecov.io/gh/labstack/echo) -[![Forum](https://img.shields.io/badge/community-forum-00afd1.svg?style=flat-square)](https://github.com/labstack/echo/discussions) -[![Twitter](https://img.shields.io/badge/twitter-@labstack-55acee.svg?style=flat-square)](https://twitter.com/labstack) -[![License](http://img.shields.io/badge/license-mit-blue.svg?style=flat-square)](https://raw.githubusercontent.com/labstack/echo/master/LICENSE) +[![Go Reference](https://pkg.go.dev/badge/github.com/labstack/echo/v4.svg)](https://pkg.go.dev/github.com/labstack/echo/v4) +[![CI](https://img.shields.io/github/actions/workflow/status/labstack/echo/echo.yml?branch=v4&style=flat-square&label=ci)](https://github.com/labstack/echo/actions/workflows/echo.yml?query=branch%3Av4) +[![Codecov](https://img.shields.io/codecov/c/github/labstack/echo/v4.svg?style=flat-square)](https://codecov.io/gh/labstack/echo/tree/v4) +[![Discussions](https://img.shields.io/badge/community-discussions-00afd1.svg?style=flat-square)](https://github.com/labstack/echo/discussions) +[![X](https://img.shields.io/badge/x-@labstack-000000.svg?style=flat-square)](https://x.com/labstack) +[![License](https://img.shields.io/badge/license-mit-blue.svg?style=flat-square)](https://github.com/labstack/echo/blob/v4/LICENSE) -## Echo +## Echo v4 High performance, extensible, minimalist Go web framework. -* [Official website](https://echo.labstack.com) -* [Quick start](https://echo.labstack.com/docs/quick-start) -* [Middlewares](https://echo.labstack.com/docs/category/middleware) +This branch holds Echo v4, the maintenance line. Echo v5 is the current release; start new projects on [v5](https://github.com/labstack/echo). -Help and questions: [Github Discussions](https://github.com/labstack/echo/discussions) +- [v4 API reference](https://pkg.go.dev/github.com/labstack/echo/v4) +- [Upgrade from v4 to v5](https://github.com/labstack/echo/blob/master/API_CHANGES_V5.md) +- [Website](https://echo.labstack.com) (documents v5) +- Community help: [GitHub Discussions](https://github.com/labstack/echo/discussions) +- Commercial support: [Echo Support](https://echo.labstack.com/pro#support) +### Support -### Feature Overview +Echo v4 receives bug fixes until 2026-12-31 and free security fixes until 2027-12-31, on its latest release only. It gets no new features. See [SECURITY.md](https://github.com/labstack/echo/blob/master/SECURITY.md) for the full policy. -- Optimized HTTP router which smartly prioritize routes -- Build robust and scalable RESTful APIs -- Group APIs -- Extensible middleware framework -- Define middleware at root, group or route level -- Data binding for JSON, XML and form payload -- Handy functions to send variety of HTTP responses -- Centralized HTTP error handling -- Template rendering with any template engine -- Define your format for the logger -- Highly customizable -- Automatic TLS via Let’s Encrypt -- HTTP/2 support - -## Sponsors +Echo v4 requires Go 1.26 or later (since v4.16.1), to use patched `golang.org/x/` dependencies. -
- - Blacksmith logo - Blacksmith – faster, drop-in GitHub Actions runners - -
-
-
- - encore icon - Encore – the platform for building Go-based cloud backends - -
-
- -Click [here](https://github.com/sponsors/labstack) for more information on sponsorship. - -## [Guide](https://echo.labstack.com/guide) +[Echo Support](https://echo.labstack.com/pro#support) is a paid annual plan from LabStack for v4 and v5 applications. It includes a named contact, email support with a two-business-day response target, and an annual maintenance-status letter. -### Installation - -```sh -// go get github.com/labstack/echo/{version} -go get github.com/labstack/echo/v4 -``` -Echo v4.16.1 and later require Go 1.26 or later to use patched `golang.org/x/` dependencies. Use a supported, patched Go toolchain when building applications. - -Echo v4 receives bug fixes until 2026-12-31 and free security fixes until 2027-12-31, on its latest release. New projects should use [v5](https://github.com/labstack/echo). See [SECURITY.md](https://github.com/labstack/echo/blob/master/SECURITY.md) for the full policy. +## Upgrade notes ### Client IP security migration since v4.16.3 -Echo v4.16.3 changes client IP defaults: without `Echo#IPExtractor`, `Context.RealIP()` uses the connection peer and ignores `X-Forwarded-For` and `X-Real-IP`. Proxy middleware always replaces upstream `X-Real-IP` with this result. This fixes CVE-2026-118651 and CVE-2026-118653. +Echo v4.16.3 changes client IP defaults. Without `Echo#IPExtractor`, `Context.RealIP()` uses the connection peer and ignores `X-Forwarded-For` and `X-Real-IP`. Proxy middleware always replaces upstream `X-Real-IP` with this result. This fixes [CVE-2026-118651](https://github.com/labstack/echo/security/advisories/GHSA-99jh-6h7p-pp36) and [CVE-2026-118653](https://github.com/labstack/echo/security/advisories/GHSA-246p-cpwv-v3jq). Applications that already set `Echo#IPExtractor` keep their behavior. A custom rate-limit identifier that does not call `RealIP()` is also unaffected. -**Migration for applications behind proxies:** configure `Echo#IPExtractor` before starting the server. Otherwise, clients behind the same proxy share its IP address for rate limiting, access controls, and logging. Use `echo.ExtractIPDirect()` when there is no proxy. For XFF-based proxies, disable the broad default trust ranges and trust only your proxy addresses: +Behind a proxy, configure `Echo#IPExtractor` before starting the server. Otherwise, clients behind the same proxy share its IP address for rate limiting, access controls and logging. Use `echo.ExtractIPDirect()` when there is no proxy. For proxies that set `X-Forwarded-For`, turn off the broad default trust ranges and trust only your proxy addresses: ```go +// After e := echo.New(); imports "log" and "net". _, proxyRange, err := net.ParseCIDR("10.0.0.10/32") // replace with your proxy's address or CIDR if err != nil { - log.Fatal(err) + log.Fatal(err) } e.IPExtractor = echo.ExtractIPFromXFFHeader( - echo.TrustLoopback(false), - echo.TrustLinkLocal(false), - echo.TrustPrivateNet(false), - echo.TrustIPRange(proxyRange), + echo.TrustLoopback(false), + echo.TrustLinkLocal(false), + echo.TrustPrivateNet(false), + echo.TrustIPRange(proxyRange), ) ``` -If your proxy uses `X-Real-IP`, use `echo.ExtractIPFromRealIPHeader` with the same trust options. Configure the outermost proxy to replace client-supplied identity headers. Explicitly configured extractors and custom rate-limit identifiers retain their behavior. +If your proxy uses `X-Real-IP`, use `echo.ExtractIPFromRealIPHeader` with the same trust options. Configure the outermost proxy to replace client-supplied identity headers. ### Security defaults since v4.16.1 -`BodyDump` captures at most 5 MiB of the request and 5 MiB of the response by default. The application and client still receive the complete bodies. Configure `BodyDumpConfig.MaxRequestBytes` and `MaxResponseBytes` to change the capture limits; `-1` disables a limit. +See the [v4.16.1 release notes](https://github.com/labstack/echo/releases/tag/v4.16.1) for the advisories. + +`BodyDump` captures at most 5 MiB of the request and 5 MiB of the response by default. The application and client still receive the complete bodies. Set `BodyDumpConfig.MaxRequestBytes` and `MaxResponseBytes` to change the capture limits; `-1` removes a limit. + +`Decompress` limits decompressed request bodies to 100 MiB by default. Reading beyond the limit returns HTTP 413, including through JSON and XML binding. Set `DecompressConfig.MaxDecompressedSize` to change the limit; `-1` removes it. Apply any smaller application body limit after decompression. + +The proxy middleware validates WebSocket upgrade responses, closes both WebSocket connections when either side disconnects, and removes incoming `Forwarded` headers. Backends should trust only the forwarding headers the proxy sets and enforce their own authorization. + +### Request scheme since v4.16.0 + +`Context.Scheme()` uses `X-Forwarded-Proto` and related headers only when the request comes directly from a loopback, link-local or private network address, or a unix socket. If a proxy with a public address terminates TLS and forwards plain HTTP to Echo, `HTTPSRedirect` keeps redirecting until you set `Echo#SchemeExtractor` to trust that proxy. See the [v4.16.0 changelog](https://github.com/labstack/echo/blob/v4/CHANGELOG.md#v4160---2026-09-27) for this and the other fixes in that release. -`Decompress` limits decompressed request bodies to 100 MiB by default. Reading beyond the limit returns HTTP 413, including through JSON and XML binding. Configure `DecompressConfig.MaxDecompressedSize` to change the limit; `-1` disables it. Apply any smaller application body limit after decompression. +## Features -The proxy now validates WebSocket upgrade responses, closes both WebSocket connections when either side disconnects, and removes incoming `Forwarded` headers. Backends should use the proxy's validated forwarding headers and enforce their own authorization. +- Router with static, parameter and wildcard routes; static routes match first +- RESTful APIs with route groups +- Middleware at the root, group or route level +- Data binding for JSON, XML, form, query and path parameters +- Helpers for common HTTP responses +- Centralized HTTP error handling +- Template rendering with any template engine +- Customizable logging +- Automatic TLS through Let's Encrypt +- HTTP/2, including h2c + +## Sponsors + +| | Sponsor | +| --- | --- | +| Blacksmith logo | [Blacksmith](https://blacksmith.sh): faster, drop-in GitHub Actions runners | +| Encore logo | [Encore](https://encore.dev): the platform for building Go-based cloud backends | + +Echo is independent and community funded. If your company depends on Echo, please consider [sponsoring it](https://github.com/sponsors/labstack). + +## Getting started + +### Installation + +```sh +go get github.com/labstack/echo/v4 +``` ### Example @@ -100,87 +99,77 @@ The proxy now validates WebSocket upgrade responses, closes both WebSocket conne package main import ( - "github.com/labstack/echo/v4" - "github.com/labstack/echo/v4/middleware" - "log/slog" - "net/http" + "errors" + "log/slog" + "net/http" + + "github.com/labstack/echo/v4" + "github.com/labstack/echo/v4/middleware" ) func main() { - // Echo instance - e := echo.New() + e := echo.New() - // Middleware - e.Use(middleware.RequestLogger()) // use the default RequestLogger middleware with slog logger - e.Use(middleware.Recover()) // recover panics as errors for proper error handling + e.Use(middleware.RequestLogger()) // log requests with slog + e.Use(middleware.Recover()) // turn panics into errors - // Routes - e.GET("/", hello) + e.GET("/", hello) - // Start server - if err := e.Start(":8080"); err != nil && !errors.Is(err, http.ErrServerClosed) { - slog.Error("failed to start server", "error", err) - } + if err := e.Start(":8080"); err != nil && !errors.Is(err, http.ErrServerClosed) { + slog.Error("failed to start server", "error", err) + } } -// Handler func hello(c echo.Context) error { - return c.String(http.StatusOK, "Hello, World!") + return c.String(http.StatusOK, "Hello, World!") } ``` -# Official middleware repositories +## Official middleware -Following list of middleware is maintained by Echo team. +The Echo team maintains these repositories. -| Repository | Description | -|------------------------------------------------------------------------------|-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| -| [github.com/labstack/echo-jwt](https://github.com/labstack/echo-jwt) | [JWT](https://github.com/golang-jwt/jwt) middleware | -| [github.com/labstack/echo-contrib](https://github.com/labstack/echo-contrib) | [casbin](https://github.com/casbin/casbin), [gorilla/sessions](https://github.com/gorilla/sessions), [jaegertracing](https://github.com/uber/jaeger-client-go), [prometheus](https://github.com/prometheus/client_golang/), [pprof](https://pkg.go.dev/net/http/pprof), [zipkin](https://github.com/openzipkin/zipkin-go) middlewares | -| [github.com/labstack/echo-otel](https://github.com/labstack/echo-otel/tree/v4) | [OpenTelemetry](https://opentelemetry.io/) middleware for tracing and metrics (`github.com/labstack/echo-otel/v4`) | +| Repository | Description | +| --- | --- | +| [github.com/labstack/echo-jwt](https://github.com/labstack/echo-jwt) | [JWT](https://github.com/golang-jwt/jwt) middleware | +| [github.com/labstack/echo-contrib](https://github.com/labstack/echo-contrib) | [casbin](https://github.com/casbin/casbin), [gorilla/sessions](https://github.com/gorilla/sessions), [jaegertracing](https://github.com/uber/jaeger-client-go), [prometheus](https://github.com/prometheus/client_golang/), [pprof](https://pkg.go.dev/net/http/pprof) and [zipkin](https://github.com/openzipkin/zipkin-go) middleware | +| [github.com/labstack/echo-otel](https://github.com/labstack/echo-otel/tree/v4) | [OpenTelemetry](https://opentelemetry.io/) tracing and metrics middleware (`github.com/labstack/echo-otel/v4`) | -# Third-party middleware repositories +## Third-party middleware -Be careful when adding 3rd party middleware. Echo teams does not have time or manpower to guarantee safety and quality -of middlewares in this list. +The Echo team does not review or maintain these projects. Check their quality and security, and that each one supports v4, before you use them. -| Repository | Description | -|------------------------------------------------------------------------------------------------------|----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| -| [deepmap/oapi-codegen](https://github.com/deepmap/oapi-codegen) | Automatically generate RESTful API documentation with [OpenAPI](https://swagger.io/specification/) Client and Server Code Generator | -| [github.com/swaggo/echo-swagger](https://github.com/swaggo/echo-swagger) | Automatically generate RESTful API documentation with [Swagger](https://swagger.io/) 2.0. | -| [github.com/ziflex/lecho](https://github.com/ziflex/lecho) | [Zerolog](https://github.com/rs/zerolog) logging library wrapper for Echo logger interface. | -| [github.com/brpaz/echozap](https://github.com/brpaz/echozap) | Uber´s [Zap](https://github.com/uber-go/zap) logging library wrapper for Echo logger interface. | -| [github.com/samber/slog-echo](https://github.com/samber/slog-echo) | Go [slog](https://pkg.go.dev/golang.org/x/exp/slog) logging library wrapper for Echo logger interface. | -| [github.com/darkweak/souin/plugins/echo](https://github.com/darkweak/souin/tree/master/plugins/echo) | HTTP cache system based on [Souin](https://github.com/darkweak/souin) to automatically get your endpoints cached. It supports some distributed and non-distributed storage systems depending your needs. | -| [github.com/mikestefanello/pagoda](https://github.com/mikestefanello/pagoda) | Rapid, easy full-stack web development starter kit built with Echo. | -| [github.com/go-woo/protoc-gen-echo](https://github.com/go-woo/protoc-gen-echo) | ProtoBuf generate Echo server side code | +| Repository | Description | +| --- | --- | +| [oapi-codegen/oapi-codegen](https://github.com/oapi-codegen/oapi-codegen) | Generates server and client code from [OpenAPI](https://swagger.io/specification/) specifications | +| [github.com/swaggo/echo-swagger](https://github.com/swaggo/echo-swagger) | Serves [Swagger](https://swagger.io/) 2.0 API documentation | +| [github.com/ziflex/lecho](https://github.com/ziflex/lecho) | [Zerolog](https://github.com/rs/zerolog) adapter for the Echo logger interface | +| [github.com/brpaz/echozap](https://github.com/brpaz/echozap) | Uber's [Zap](https://github.com/uber-go/zap) adapter for the Echo logger interface | +| [github.com/samber/slog-echo](https://github.com/samber/slog-echo) | [slog](https://pkg.go.dev/log/slog) request logging middleware | +| [github.com/darkweak/souin/plugins/echo](https://github.com/darkweak/souin/tree/master/plugins/echo) | HTTP cache based on [Souin](https://github.com/darkweak/souin), with distributed and local storage backends | +| [github.com/mikestefanello/pagoda](https://github.com/mikestefanello/pagoda) | Full-stack web starter kit built with Echo | +| [github.com/go-woo/protoc-gen-echo](https://github.com/go-woo/protoc-gen-echo) | Generates Echo server code from Protocol Buffers | -Please send a PR to add your own library here. +To add your library, send a pull request. ## Contribute -**Use issues for everything** +v4 takes bug and security fixes only (see [Support](#support)). Send new features to v5 on the [master branch](https://github.com/labstack/echo). + +- Open an issue before a large change. Send small fixes directly as a pull request. +- Include a test, documentation and, where it helps, an example. -- For a small change, just send a PR. -- For bigger changes open an issue for discussion before sending a PR. -- PR should have: - - Test case - - Documentation - - Example (If it makes sense) -- You can also contribute by: - - Reporting issues - - Suggesting new features or enhancements - - Improve/fix documentation +Report security issues privately as [SECURITY.md](https://github.com/labstack/echo/blob/master/SECURITY.md) describes, not in public issues. ## Credits -- [Vishal Rana](https://github.com/vishr) (Author) +- [Vishal Rana](https://github.com/vishr) (Author and Maintainer) - [Nitin Rana](https://github.com/nr17) (Consultant) -- [Roland Lammel](https://github.com/lammel) (Maintainer) -- [Martti T.](https://github.com/aldas) (Maintainer) -- [Pablo Andres Fuente](https://github.com/pafuent) (Maintainer) +- [Martti T.](https://github.com/aldas) (Maintainer Emeritus) +- [Roland Lammel](https://github.com/lammel) (Maintainer Emeritus) +- [Pablo Andres Fuente](https://github.com/pafuent) (Maintainer Emeritus) - [Contributors](https://github.com/labstack/echo/graphs/contributors) ## License -[MIT](https://github.com/labstack/echo/blob/master/LICENSE) +[MIT](https://github.com/labstack/echo/blob/v4/LICENSE)