Giter VIP home page Giter VIP logo

flamego's Introduction

Flamego Flamego

GitHub Workflow Status Codecov GoDoc Sourcegraph

Flamego is a fantastic modular Go web framework with a slim core but limitless extensibility.

It is the successor of the Macaron, and equips the most powerful routing syntax among all web frameworks within the Go ecosystem.

Installation

The minimum requirement of Go is 1.19.

go get github.com/flamego/flamego

Getting started

package main

import "github.com/flamego/flamego"

func main() {
	f := flamego.Classic()
	f.Get("/", func() string {
		return "Hello, Flamego!"
	})
	f.Run()
}

Features

Middleware

  • Logger - Log requests and response status code
  • Recovery - Automatic recovery from panics
  • Static - Serve static files
  • Renderer - Render content
  • template - Go template rendering
  • session - User session management
  • recaptcha - Google reCAPTCHA verification
  • csrf - Generate and validate CSRF tokens
  • cors - Cross-Origin Resource Sharing
  • binding - Request data binding and validation
  • gzip - Gzip compression to responses
  • cache - Cache management
  • brotli - Brotli compression to responses
  • auth - Basic and bearer authentication
  • i18n - Internationalization and localization
  • captcha - Captcha service
  • hcaptcha - hCaptcha verification

Getting help

Users and projects

  • Cardinal: Attack-defence CTF platform.
  • mebeats: Realtime heartbeat monitor service based on Mi band.
  • ASoulDocs: Ellien's documentation server.
  • NekoBox: Anonymous question box.
  • Codenotify.run: Codenotify as a Service.
  • Relay: A web server for forwarding events from service A to service B.
  • bilibili-lottery: 一款支持对哔哩哔哩视频或动态评论进行抽奖的小程序
  • pgrok: Poor man's ngrok.
  • Caramelverse: A fashion brand.
  • Sourcegraph Accounts: Centralized accounts system for all of the Sourcegraph-operated services
  • Just send a PR to add yours!

Development

Install "go-mockgen" and "goimports" to re-generate mocks:

go install github.com/derision-test/go-mockgen/cmd/go-mockgen@latest
go install golang.org/x/tools/cmd/goimports@latest

go generate ./...

License

This project is under the MIT License. See the LICENSE file for the full license text.

flamego's People

Contributors

altonhe avatar asjdf avatar deepsource-autofix[bot] avatar dependabot[bot] avatar dsh0416 avatar l2nce avatar moesang avatar pharrisee avatar unknwon avatar wuhan005 avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

flamego's Issues

Returning a byte slice with an error outputs an empty HTTP body

Component

Core framework

Middleware

n/a

Version

v1.1.0

Describe the bug

I'm not sure if this is supported but when I'm using a handler that returns ([]byte, error), the response is empty.
It works when I only return []byte though.

To reproduce

package main

import (
	"github.com/flamego/flamego"
)

func main() {
	f := flamego.Classic()

	f.Get("/", func() ([]byte, error) {
		return []byte(`{"hello": "world"}`), nil
	})

	f.Run()
}

Expected behavior

See the output in the browser

Additional context

Here are the relevant logs, we can see that the handler actually returns 0 bytes.

[Flamego] 2022-04-08 15:23:03: Started GET / for 100.100.100.100
[Flamego] 2022-04-08 15:23:03: Completed GET / 0  in 100.3µs

Code of Conduct

  • I agree to follow this project's Code of Conduct

router: support using `http.MethodGet`, `http.MethodPost` to replace "GET,POST" in `f.Routes`

Component

Core framework

Middleware

n/a

Is your feature request related to a problem? Please describe

To register a route for multiple HTTP methods, one would use follows:

f.Routes("/", "GET,POST", ...)

However, the use of "GET,POST" looks very non-elegant, and one always needs to type in full characters without editor's auto-completion (because this is literal string).

Describe the solution you'd like

The net/http package provides constants for each HTTP method, e.g. http.MethodGet, we should be able to do things more elegant like:

f.Routes("/", http.MethodGet, http.MethodPost, <my handlers>)

Because these constants are strings after all, the router should be able to distinguished them from handlers, and magically do the trick for users.

Describe alternatives you've considered

n/a

Additional context

No response

Code of Conduct

  • I agree to follow this project's Code of Conduct

middleware: add support for request rate limiting

Component

Middleware

Middleware

https://github.com/zhqqqy/flamego-limit

Is your feature request related to a problem? Please describe

Web frameworks generally need the function of current limiting.

Describe the solution you'd like

I implemented a simple current limiting middleware based on the sliding window algorithm, which can be enabled in the specified router, and the current limiting key can be customized.

Describe alternatives you've considered

It may also be possible to implement current limiting algorithms such as token buckets based on this

Additional context

No response

Code of Conduct

  • I agree to follow this project's Code of Conduct

binding: Improve validation rule error message

Component

Middleware

Middleware

https://github.com/flamego/binding

Is your feature request related to a problem? Please describe

When using validation with the binding package, only the failed rule is returned to the client, e.g.

{"error":"Key: \"Lottery.WinnerCount\" Error: Field validation for \"WinnerCount\" failed on the \"gt\" tag"}

However, the one important element is missing, which is the expected range of values.

Describe the solution you'd like

The error message should contain the range of expected values.

Describe alternatives you've considered

n/a

Additional context

No response

Code of Conduct

  • I agree to follow this project's Code of Conduct

router: support `{**}` as the shorthand for `{**: **}`

Component

Core framework

Middleware

n/a

Is your feature request related to a problem? Please describe

In Flamego, the ** isn't a unique way nor special indicator of globs when it is used as the name of a bind parameter, for example:

Meanwhile, arbitrary name may be used to capture globs, e.g. {repo: **} captures globs in the bind parameter named repo.

However, it seems common use ** to represent globs like {**: **}, but looks redundant.

Describe the solution you'd like

It makes sense to have {**} as the shorthand for {**: **} to be ergonomic.

Describe alternatives you've considered

Live with it.

Additional context

Feel free to ask more details or clarifying questions!

If you would like to contribute on the implementation, please:

  1. Comment on the issue for taking the responsibility so everyone knows.
  2. Acknowledge that the expected timeline is one week.

Code of Conduct

  • I agree to follow this project's Code of Conduct

Incorrect handling of non-CORS requests

Component

Middleware

Middleware

https://github.com/flamego/cors

Version

1.0.1

Describe the bug

CORS middleware will still intercept and require origin fields in the request header when encountering non-cross-domain requests.

To reproduce

use the middleware and then direct access to the service

Expected behavior

When a non-cross-domain request is received, the request is not intercepted

Additional context

No response

Code of Conduct

  • I agree to follow this project's Code of Conduct

binding: support YAML format

Component

Middleware

Middleware

https://github.com/flamego/binding

Is your feature request related to a problem? Please describe

YAML is a popular data exchange format besides JSON and XML.

Describe the solution you'd like

Building on top of gopkg.in/yaml.v2 similar to what have been implemented in go-macaron/binding#40.

Describe alternatives you've considered

Live with it.

Additional context

Feel free to ask more details or clarifying questions!

If you would like to contribute on the implementation, please:

  1. Comment on the issue for taking the responsibility so everyone knows.
  2. Acknowledge that the expected timeline is one week.

Code of Conduct

  • I agree to follow this project's Code of Conduct

Binding nested structs

What needs to be improved? Please describe

Documentation about Binding middleware could include an example for binding nested structs.
In the documentation you have an example for JSON (type User and type Address). But it would be nice to have an example of an HTML form for saving a user with multiple address.
https://flamego.dev/middleware/binding.html#json

Why do you think it is important?

It is not clear how to write the HTML form so the binding occurs.

Code of Conduct

  • I agree to follow this project's Code of Conduct

Encountered a GOB error when using Session and CSRF at the same time

Component

Middleware

Middleware

https://github.com/flamego/session

Version

1.2.1

Describe the bug

在使用redis存储session时遇到问题 gob: type not registered for interface: time.Time

To reproduce

配置 session 使用 Redis 作为存储。
然后后部加上csrf。
可在flamego/session/redis/redis.go:68 下断点复现。
image

Expected behavior

正常应该无报错

Additional context

No response

Code of Conduct

  • I agree to follow this project's Code of Conduct

template: mysterious error "failed to write out rendered HTML: short write"

Component

Middleware

Middleware

https://github.com/flamego/template

Version

1.0.0

Describe the bug

Occasionally seeing logs of "failed to write out rendered HTML: short write" printed to console.

To reproduce

Running https://github.com/asoul-sig/asouldocs for https://asouldocs.dev

Expected behavior

Not sure, is this a real error or should just be ignored? Maybe something wrong with the response body content length?

Additional context

Related: denoland/deno#3478 (comment)

Code of Conduct

  • I agree to follow this project's Code of Conduct

validator: make examples to work with i18n

Component

Middleware

Middleware

https://github.com/flamego/validator

Is your feature request related to a problem? Please describe

The validator module should be able to work with github.com/go-i18n/i18n and github.com/flamego/i18n, we need to make some example or make code changes to make that happen.

Describe the solution you'd like

n/a

Describe alternatives you've considered

n/a

Additional context

No response

Code of Conduct

  • I agree to follow this project's Code of Conduct

router: type-safe helpers for multiplex routes

Component

Core framework

Middleware

n/a

Is your feature request related to a problem? Please describe

Currently multiplex routes are supported via:

f.Routes("/", http.MethodGet, http.MethodPost, <my handlers>)

// or

f.Routes("/", "GET,POST", ...)

But neither of are both elegant and type-safe.

Describe the solution you'd like

Something like

f.RoutePath("/").Methods(http.MethodGet, http.MethodPost).Handlers(...)

Describe alternatives you've considered

Live with it

Additional context

Derived from #113 (comment)

Code of Conduct

  • I agree to follow this project's Code of Conduct

cache: support MongoDB as the backend

Component

Middleware

Middleware

https://github.com/flamego/cache

Is your feature request related to a problem? Please describe

MongoDB is a popular NoSQL database, and it very suitable as the cache backend.

Describe the solution you'd like

Add support of MongoDB similar to flamego/session#15.

Describe alternatives you've considered

N/A

Additional context

No response

Code of Conduct

  • I agree to follow this project's Code of Conduct

does flamego need to limit of uniqueness of injector.Map and injector.MapTo ?

Component

Core framework

Middleware

https://github.com/flamego/

Is your feature request related to a problem? Please describe

type User struct {
    Name string
}
Flame.Map(User{Name: "A"})
Flame.Map(User{Name: "B"})

user don't know which is used

Describe the solution you'd like

func (inj *injector) Map(values ...interface{}) TypeMapper {
	for _, val := range values {
		if _, ok := inj.values[reflect.TypeOf(val)]; ok {
			panic(fmt.Sprintf("unable to map duplicate value: %v", reflect.TypeOf(val)))
		}
		inj.values[reflect.TypeOf(val)] = reflect.ValueOf(val)
	}
	return inj
}

same as MapTo

Describe alternatives you've considered

support multiple instances in long term?

Additional context

No response

Code of Conduct

  • I agree to follow this project's Code of Conduct

session: support auto-create table for PostgreSQL and MySQL

Component

Middleware

Middleware

https://github.com/flamego/session

Is your feature request related to a problem? Please describe

The session middleware require manual creation of the table for PostgreSQL and MySQL backend.

Describe the solution you'd like

Add an option to the postgres.Config and mysql.Config like the following (field name need to be discussed):

type Config struct{
	// ...
	InitTable bool
}

Which automatically creates the table when not exists.

The SQL to create the table can be derived from the tests.

Describe alternatives you've considered

Live with it.

Additional context

Feel free to ask more details or clarifying questions!

If you would like to contribute on the implementation, please:

  1. Comment on the issue for taking the responsibility so everyone knows.
  2. Acknowledge that the expected timeline is one week.

Code of Conduct

  • I agree to follow this project's Code of Conduct

router: add support for `HeadersRegexp`

Component

Core framework

Middleware

n/a

Is your feature request related to a problem? Please describe

hi,
it that any plan to support router with HeadersRegexp?
i want to write S3 web service (looks like minio) with flamego ,but it miss HeadersRegexp func to filter request with header.

https://github.com/minio/minio/blob/master/cmd/api-router.go#L242

// HeadersRegexp accepts a sequence of key/value pairs, where the value has regex
// support. For example:
//
//     r := mux.NewRouter()
//     r.HeadersRegexp("Content-Type", "application/(text|json)",
//               "X-Requested-With", "XMLHttpRequest")
//
// The above route will only match if both the request header matches both regular expressions.
// If the value is an empty string, it will match any value if the key is set.
// Use the start and end of string anchors (^ and $) to match an exact value.

Describe the solution you'd like

https://github.com/gorilla/mux/blob/d07530f46e1eec4e40346e24af34dcc6750ad39f/route.go#L255

Describe alternatives you've considered

https://github.com/minio/minio/blob/master/cmd/api-router.go#L242

Additional context

No response

Code of Conduct

  • I agree to follow this project's Code of Conduct

middleware: add support for Server-Sent Events

Component

Middleware

Middleware

https://github.com/flamego/sse

Is your feature request related to a problem? Please describe

The issue go-macaron/macaron#53 of Macaron submitted by the community asks for supporting SSE (Server-Sents Events), which can help developers build a stable streaming service.

I think it's time for us to support this feature in Flamego, as the Macaron is in maintenance mode.

Describe the solution you'd like

Implement a new middleware sse to support this feature.

Describe alternatives you've considered

n/a

Additional context

I've made an SSE middleware for Macaron, we can easily modify it to support Flamego.
https://github.com/EggMD/sse

Code of Conduct

  • I agree to follow this project's Code of Conduct

middleware: add support for hCaptcha

Component

Middleware

Middleware

https://github.com/flamego/hcaptcha

Is your feature request related to a problem? Please describe

hCaptcha is yet another popular captcha service which claims to focus on user privacy, security and UX.

Describe the solution you'd like

Create a middleware similar to what have been implemented for recaptcha for the Google reCAPTCHA.

Describe alternatives you've considered

n/a

Additional context

Feel free to ask more details or clarifying questions!

If you would like to contribute on the implementation, please:

  1. Comment on the issue for taking the responsibility so everyone knows.
  2. Ask @flamego/core to create the repository so you can start sending pull requests to.
  3. Acknowledge that the expected timeline is one week.

Code of Conduct

  • I agree to follow this project's Code of Conduct

core: testing `go.mod` tidiness in CI

We want to make sure go.mod is up-to-date for every pull request to the core framework.

The actual implementation can be seen in this blog post but we should avoid using bash script and see if it's possible to use the exit code to control the GitHub Action's behavior (i.e. fail on exit 1).

router: type-safe helpers for multiplex routes

Component

Core framework

Middleware

n/a

Is your feature request related to a problem? Please describe

Currently multiplex routes are supported via:

f.Routes("/", http.MethodGet, http.MethodPost, <my handlers>)

// or

f.Routes("/", "GET,POST", ...)

But neither of are both elegant and type-safe.

Describe the solution you'd like

Derived from #113 (comment)

Describe alternatives you've considered

Live with it

Additional context

No response

Code of Conduct

  • I agree to follow this project's Code of Conduct

static: `Index` option does not take effect when using go embed file system.

Component

Core framework

Middleware

n/a

Version

1.20.4

Describe the bug

Flamego provides flamego.Static middleware to serve static files, it has an option Index to specify which file to attempt to serve as the directory index.

However, when using the go embed as the file system, the Index field doesn't work. This is because the go embed file system can not accept the file path that starts with or ends with a slash, e.g. /a/b/c/.

package main

import (
	"embed"
	"fmt"
)

//	dist
//	└── frontend
//	    └── index.html
//
//	2 directories, 1 file

//go:embed dist
var embedFS embed.FS

func main() {
	fmt.Println(embedFS.Open("dist/frontend/index.html")) // ok
	fmt.Println(embedFS.Open("dist/frontend"))            // ok
	fmt.Println(embedFS.Open("dist/frontend/"))           // file does not exist
	fmt.Println(embedFS.Open("/dist/frontend"))           // file does not exist
}

The Open() https://github.com/flamego/flamego/blob/main/static.go#L100 here will get a file path ends with a slash, then it returns a file does not exist error as I mentioned above.

To reproduce

# Create the embed directory
mkdir -p dist/frontend
# Create the index.html
echo "<html>Hello Flamego!</html>" > dist/frontend/index.html
package main

import (
	"embed"
	"fmt"
	"net/http"
	"net/http/httptest"

	"github.com/flamego/flamego"
)

//	dist
//	└── frontend
//	    └── index.html
//
//	2 directories, 1 file

// $ cat dist/frontend/index.html
// <html>Hello Flamego!</html>

//go:embed dist
var embedFS embed.FS

func main() {
	f := flamego.Classic()
	f.Use(flamego.Static(flamego.StaticOptions{
		FileSystem: http.FS(embedFS),
	}))

	reqNormal := httptest.NewRequest(http.MethodGet, "/dist/frontend/index.html", nil)
	reqIndex := httptest.NewRequest(http.MethodGet, "/dist/frontend/", nil)

	recorder := httptest.NewRecorder()
	f.ServeHTTP(recorder, reqNormal)
	fmt.Println(recorder.Result().StatusCode, recorder.Body.String())

	recorder = httptest.NewRecorder()
	f.ServeHTTP(recorder, reqIndex)
	fmt.Println(recorder.Result().StatusCode, recorder.Body.String())
}

Output:

GOROOT=/Users/johnwu/go/go1.20.4 #gosetup
GOPATH=/Users/johnwu/go #gosetup
/Users/johnwu/go/go1.20.4/bin/go build -o /private/var/folders/3s/l9q20bds7t77n64fh52dpyyh0000gn/T/GoLand/___go_build_ GoPlayground #gosetup
/private/var/folders/3s/l9q20bds7t77n64fh52dpyyh0000gn/T/GoLand/___go_build_
2023-08-08 00:51:44 Logger: Started method=GET path=/dist/frontend/index.html remote=192.0.2.1
2023-08-08 00:51:44 Logger: Completed method=GET path=/dist/frontend/index.html status=200 duration=4.389128ms
200 <html>Hello Flamego!</html>

2023-08-08 00:51:44 Logger: Started method=GET path=/dist/frontend/ remote=192.0.2.1
2023-08-08 00:51:44 Logger: Completed method=GET path=/dist/frontend/ status=404 duration="175.247µs"
404 404 page not found

Expected behavior

The index.html should be rendered normally when visiting /dist/frontend/.

Additional context

To fix this issue, we can just only trim the slash at the end of the file path, for the http.FS has already helped us trim the slash prefix. (FYI: https://github.com/golang/go/blob/master/src/net/http/fs.go#L774)

Code of Conduct

  • I agree to follow this project's Code of Conduct

Bump go version to 1.19

Component

Core framework

Middleware

https://github.com/flamego/

Is your feature request related to a problem? Please describe

Current implementation of flamego doesn't support go 1.19

vendor/github.com/flamego/flamego/internal/route/parser.go:15:10: cannot use generic type participle.Parser[G any] without instantiation
vendor/github.com/flamego/flamego/internal/route/parser.go:65:33: implicit function instantiation requires go1.18 or later (-lang was set to go1.16; check go.mod)
vendor/github.com/flamego/flamego/internal/route/parser.go:65:33: cannot infer G (/Users/pbeza/Documents/go-nerve/vendor/github.com/alecthomas/participle/v2/parser.go:65:12)

Describe the solution you'd like

bump go version to 1.19 or/and resolve issues above

Describe alternatives you've considered

Additional context

No response

Code of Conduct

  • I agree to follow this project's Code of Conduct

Support integration with New Relic middlewares

Component

Core framework

Middleware

https://github.com/flamego/

Is your feature request related to a problem? Please describe

I've been using flamego in my company and we need to have a service that uses it integrated with New Relic.

I was able to make it work, with the normal/expected type of code of a middleware using New Relic as follows:

type NewRelicHandler struct {
	Flame       *flamego.Flame
	NewRelicApp *newrelic.Application
}

func (nrw NewRelicHandler) ServeHTTP(rw http.ResponseWriter, req *http.Request) {
	if nrw.NewRelicApp == nil || shouldIgnorePath(req.URL.Path) {
		nrw.Flame.ServeHTTP(rw, req)
		return
	}

	path := sanitizePath(req.URL.Path)

	tx := nrw.NewRelicApp.StartTransaction(req.Method + " " + path)
	defer tx.End()

	tx.SetWebRequestHTTP(req)
	r := newrelic.RequestWithTransactionContext(req, tx)
	w := tx.SetWebResponse(rw)

	nrw.Flame.ServeHTTP(w, r)
}

and then returning a handler like so:

http.Handler {
	return mypackage.NewRelicHandler{
		Flame:       Flame(),
		NewRelicApp: NewRelicApp,
	}
}

However, this has some issues in terms of path sanitising to turn urls in the form /data/123 into the form /data/{id} to avoid too many entry points into New Relic.

Taking into account that it's not easy to "override" and reuse the request and response writer in the downstream handlers, and context is not accessible in this handler, I've been struggling with the implementation.

Describe the solution you'd like

I'd like to have some way to ensure the request and response writer used by the flamego context and underlying dependent types, including template, renderer, etc. would be updated as well so that, in the end, the response will be the one initialised in New Relic.

Describe alternatives you've considered

I've tried using a simple flamego handler but I failed to do so because I could not find a way to ensure the response writer would be updated in all dependent/injected services.

Additional context

No response

Code of Conduct

  • I agree to follow this project's Code of Conduct

binding: support binding query

Component

Middleware

Middleware

https://github.com/flamego/binding/

Is your feature request related to a problem? Please describe

Support binding query parameters into struct.

Describe the solution you'd like

type query struct {
	Username string `query:"username" validate:"required"`
	Password string `query:"password" validate:"required"`
}
f.Get("/", Query(query{}, opts), func(c flamego.Context) {
	_, _ = c.ResponseWriter().Write([]byte("Hello world"))
})

Describe alternatives you've considered

nil

Additional context

No response

Code of Conduct

  • I agree to follow this project's Code of Conduct

context: `RemoteAddr` is unsafe

Component

Core framework

Middleware

n/a

Version

1.1.0

Describe the bug

As the document mentioned, the RemoteAddr() method looks at the following things in the order to determine which one is more likely to contain the real client address.

The X-Real-IP request header
The X-Forwarded-For request header
The http.Request.RemoteAddr field

So the client's IP can be spoofed by setting the X-Real-IP or X-Forwarded-For header when the Flamego server is exposed directly to the internet.

The Gin web framework has the same vulnerability before, check CVE-2020-28483 for details.

I think we should create a new function called ClientIP() to get the client IP address from these headers. The RemoteAddr() can only get it from http.Request.RemoteAddr.

Moreover, the Flame instance should allow the developers to set the trusted remote IP headers and the trusted proxies if they want to get the client IP from user-provided headers.

To reproduce

n/a

Expected behavior

n/a

Additional context

https://nvd.nist.gov/vuln/detail/CVE-2020-28483
gin-gonic/gin#2473

Code of Conduct

  • I agree to follow this project's Code of Conduct

session: panic when context is cancelled

Component

Middleware

Middleware

https://github.com/flamego/session

Version

1.1.0

Describe the bug

When use Postgres, Redis or MongoDB as the session storage backend, it will call Save(ctx context.Context, session Session) error function to save the session data.

The context will be cancelled if users close the connection, which leads the Save(ctx context.Context, session Session) error here https://github.com/flamego/session/blob/main/session.go#L187-L190 returns a context cancelled error. The handler will then panic in L189.
It is very common for users to close the connection. Although it can be recovered by the flamego.Recovery() middleware every times, I don't think it is a good behavior here to panic directly.

To reproduce

  1. Run the following code:
package main

import (
	"time"

	"github.com/flamego/flamego"
	"github.com/flamego/session"
	"github.com/flamego/session/postgres"
)

func main() {
	f := flamego.Classic()

	f.Use(session.Sessioner(session.Options{
		Initer: postgres.Initer(),
		Config: postgres.Config{
			DSN: "postgres://<user>:<password>@127.0.0.1:5432/<dbname>?sslmode=disable",
		},
	}))

	f.Get("/", func(ctx flamego.Context, sess session.Session) {
		time.Sleep(10 * time.Second)
		sess.Set("foo", "bar")
	})

	f.Run()
}
  1. Run the following command. It closes the connection after 3 seconds.
timeout 3s curl http://localhost:2830/ 
  1. Wait about 10 seconds, the panic log appears.
[Flamego] Listening on 0.0.0.0:2830 (development)
[Flamego] 2022-10-05 01:29:45: Started GET / for [::1]
[Flamego] PANIC: session: save: upsert: context canceled
/Users/johnwu/go/pkg/mod/github.com/flamego/[email protected]/session.go:189 (0x12cb4ea)
        Sessioner.func2: panic("session: save: " + err.Error())
/Users/johnwu/go/pkg/mod/github.com/flamego/[email protected]/handler.go:26 (0x12a26ac)
        ContextInvoker.Invoke: invoke(args[0].(Context))
/Users/johnwu/go/pkg/mod/github.com/flamego/[email protected]/inject/inject.go:134 (0x1234614)
        (*injector).fastInvoke: return f.Invoke(in)
/Users/johnwu/go/pkg/mod/github.com/flamego/[email protected]/inject/inject.go:112 (0x123453c)
        (*injector).Invoke: return inj.fastInvoke(v, t, t.NumIn())
/Users/johnwu/go/pkg/mod/github.com/flamego/[email protected]/context.go:210 (0x12a11f3)
        (*context).run: vals, err := c.Invoke(h)
/Users/johnwu/go/pkg/mod/github.com/flamego/[email protected]/context.go:160 (0x12a0ebc)
        (*context).Next: c.run()
/Users/johnwu/go/pkg/mod/github.com/flamego/[email protected]/recovery.go:149 (0x12a3c21)
        Recovery.func4: c.Next()
/Users/johnwu/go/pkg/mod/github.com/flamego/[email protected]/logger.go:26 (0x12a2cc5)
        LoggerInvoker.Invoke: invoke(params[0].(Context), params[1].(*log.Logger))
/Users/johnwu/go/pkg/mod/github.com/flamego/[email protected]/inject/inject.go:134 (0x1234614)
        (*injector).fastInvoke: return f.Invoke(in)
/Users/johnwu/go/pkg/mod/github.com/flamego/[email protected]/inject/inject.go:112 (0x123453c)
        (*injector).Invoke: return inj.fastInvoke(v, t, t.NumIn())
/Users/johnwu/go/pkg/mod/github.com/flamego/[email protected]/context.go:210 (0x12a11f3)
        (*context).run: vals, err := c.Invoke(h)
/Users/johnwu/go/pkg/mod/github.com/flamego/[email protected]/context.go:160 (0x12a0ebc)
        (*context).Next: c.run()
/Users/johnwu/go/pkg/mod/github.com/flamego/[email protected]/logger.go:74 (0x12a3329)
        Logger.func2: ctx.Next()
/Users/johnwu/go/pkg/mod/github.com/flamego/[email protected]/logger.go:26 (0x12a2cc5)
        LoggerInvoker.Invoke: invoke(params[0].(Context), params[1].(*log.Logger))
/Users/johnwu/go/pkg/mod/github.com/flamego/[email protected]/inject/inject.go:134 (0x1234614)
        (*injector).fastInvoke: return f.Invoke(in)
/Users/johnwu/go/pkg/mod/github.com/flamego/[email protected]/inject/inject.go:112 (0x123453c)
        (*injector).Invoke: return inj.fastInvoke(v, t, t.NumIn())
/Users/johnwu/go/pkg/mod/github.com/flamego/[email protected]/context.go:210 (0x12a11f3)
        (*context).run: vals, err := c.Invoke(h)
/Users/johnwu/go/pkg/mod/github.com/flamego/[email protected]/router.go:252 (0x12a5fb6)
        (*router).Route.func1: r.contextCreator(w, req, params, handlers, r.URLPath).run()
/Users/johnwu/go/pkg/mod/github.com/flamego/[email protected]/router.go:349 (0x12a64af)
        (*router).ServeHTTP: leaf.Handler()(w, req, route.Params{
/Users/johnwu/go/pkg/mod/github.com/flamego/[email protected]/flame.go:135 (0x12a1f27)
        (*Flame).ServeHTTP: f.Router.ServeHTTP(w, r)
/Users/johnwu/go/go1.18/src/net/http/server.go:2916 (0x122745a)
        serverHandler.ServeHTTP: handler.ServeHTTP(rw, req)
/Users/johnwu/go/go1.18/src/net/http/server.go:1966 (0x1223356)
        (*conn).serve: serverHandler{c.server}.ServeHTTP(w, w.req)
/Users/johnwu/go/go1.18/src/runtime/asm_amd64.s:1571 (0x1063660)
        goexit: BYTE    $0x90   // NOP
[Flamego] 2022-10-05 01:29:55: Completed GET / 500 Internal Server Error in 10.021810497s

Expected behavior

No panic here.

Additional context

No response

Code of Conduct

  • I agree to follow this project's Code of Conduct

cache: support auto-create table for PostgreSQL and MySQL

Component

Middleware

Middleware

https://github.com/flamego/cache

Is your feature request related to a problem? Please describe

The cache middleware require manual creation of the table for PostgreSQL and MySQL backend.

Describe the solution you'd like

Add an option to the postgres.Config and mysql.Config like the following (field name need to be discussed):

type Config struct{
	// ...
	InitTable bool
}

Which automatically creates the table when not exists.

Notes:

Describe alternatives you've considered

Live with it.

Additional context

Feel free to ask more details or clarifying questions!

If you would like to contribute on the implementation, please:

  1. Comment on the issue for taking the responsibility so everyone knows.
  2. Acknowledge that the expected timeline is one week.

Code of Conduct

  • I agree to follow this project's Code of Conduct

router: `{**: **}` does not capture the trailing slash

Component

Core framework

Middleware

n/a

Version

1.0.0

Describe the bug

When using **: ** to capture globs, the last slash character is missing.

Define a route with parameter ** like f.Get("/{**: **}").
When making a request to /a/b/, the bind parameter value is a/b, but a/b/ is expected.

To reproduce

https://go.dev/play/p/RX4ErxvYVoy

package main

import (
	"fmt"
	"net/http"
	"net/http/httptest"

	"github.com/flamego/flamego"
)

func main() {
	f := flamego.New()

	f.Get("/{**: **}", func(c flamego.Context) {
		_, _ = c.ResponseWriter().Write([]byte(c.Param("**")))
	})

	w := httptest.NewRecorder()
	req := httptest.NewRequest(http.MethodGet, "/a/b/", nil)
	f.ServeHTTP(w, req)

	fmt.Println(w.Body.String())
}

Expected behavior

c.Param("**") should return a/b/.

Additional context

No response

Code of Conduct

  • I agree to follow this project's Code of Conduct

cors: doesn't check the port of URL while parsing `Access-Control-Allow-Origin`

Component

Middleware

Middleware

https://github.com/flamego/cors

Version

1.0.0

Describe the bug

The cors middleware use URL.Hostname() to get hostname and then compare it with configured value of AllowDomain

However, the result of URL.Hostname() doesn't contain the port information.

According to MDN Same OriginPolicy, port(if specified) is also a part of SOP.

URL.Parse("http://example.com:8080").Hostname() // example.com, not example.com:8080

When AllowDomain is configured with a port(such as example.com:8080) and Access-Control-Allow-Orogin keeps the same as AllowDomain. The CORS check will always fail.

image

To reproduce

First I create a simple flamego server and it runs at http://0.0.0.0:2830

f := flamego.Classic()
	CORS := cors.CORS(cors.Options{
		Scheme:      "http",
		Methods:     []string{"GET", "POST", "OPTIONS"},
		AllowDomain: []string{"127.0.0.1:60012"},
	})
	f.Get("/", CORS, func(c flamego.Context) string {
		return "ok"
	})
	f.Run()

then I create a webpage and serve it at http://127.0.0.1:60012/index.html

<body>
    <script>
        fetch("http://127.0.0.1:2830/")
    </script>
</body>

This is the request header copied from devtools:

GET / HTTP/1.1
Host: 127.0.0.1:2830
User-Agent: Mozilla/5.0 (X11; Linux x86_64; rv:99.0) Gecko/20100101 Firefox/99.0
Accept: */*
Accept-Language: en-US,en;q=0.5
Accept-Encoding: gzip, deflate, br
Referer: http://127.0.0.1:60012/
Origin: http://127.0.0.1:60012
DNT: 1
Connection: keep-alive
Sec-Fetch-Dest: empty
Sec-Fetch-Mode: cors
Sec-Fetch-Site: same-site
Pragma: no-cache
Cache-Control: no-cache

The response from flamego is:

HTTP/1.1 400 Bad Request
Content-Type: text/plain; charset=utf-8
X-Content-Type-Options: nosniff
Date: Wed, 06 Apr 2022 07:23:36 GMT
Content-Length: 59

CORS request from prohibited domain http://127.0.0.1:60012

Expected behavior

The backend should return ok with response code 200

Additional context

source code: cors middleware#line 99

Suggestion: use URL.Hostname()+":"+URL.Port() to get host while checking Access-Control-Allow-Orogin

Code of Conduct

  • I agree to follow this project's Code of Conduct

context: support setting default value for `Query` methods

Component

Core framework

Middleware

n/a

Is your feature request related to a problem? Please describe

When getting values of query parameters, it is common and reasonable to have a fallback (default) value when the parameter is absent.

Describe the solution you'd like

Change the method signature of Context.Query to accept an optional second argument as the default value, e.g.

type Context interface {
-	Query(name string) string
+	Query(name string, default ...string) string
-	QueryInt(name string) int
+	QueryInt(name string, default ...int) int
}
func myHandler(c flamego.Context) {
	c.Query("name", "default")
	c.QueryInt("name2", 10)
}

Describe alternatives you've considered

Live with it

Additional context

Originally proposed in #87 (comment)

Code of Conduct

  • I agree to follow this project's Code of Conduct

docs: add documentation for SSE middleware

What needs to be improved? Please describe

  • Add both English and Chinese versions of SSE middleware.

Update links to the docs on:

  • The "Middleware" section on the main repository's README
  • The "Getting help" section on each middleware repository's README
  • flamego.dev/middleware

Why do you think it is important?

This is a new middleware for Flamego.

It was implemented in "dependency injection style" which is much different from the other Go web frameworks.

So it's necessary for us to provide documentation for developers.

Code of Conduct

  • I agree to follow this project's Code of Conduct

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.