Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Echo compatibility #57

Closed
jpfluger opened this issue Apr 30, 2019 · 9 comments
Closed

Echo compatibility #57

jpfluger opened this issue Apr 30, 2019 · 9 comments

Comments

@jpfluger
Copy link

jpfluger commented Apr 30, 2019

Well done @alexedwards on re-imagining scs. 🥇 This was a comprehensive rewrite. A number of items I appreciate:

  • Status
  • Efficient load/save with help from Status
  • Session and SessionCookie are global in scope
  • I also like that IdleTimeout and Lifetime were split from the old options.
  • go.mod added for go modules support

For me, v2 solves a number of issues for which I had kept a permanent local fork of scs on my machine. (My fork was getting a bit dated too!)

I've done some testing and so far so good. I had one issue with a private token but this example provides a powerful solution to my issue.

@alexedwards
Copy link
Owner

Thanks Jaret!

My main objectives for this were decoupling the modification and saving of session data, and making it easier for developers to communicate the session token to clients not using a cookie if they want to.

There's still a bit of work to do, I still need to port some of the stores (boltstore, dynamostore etc) from the old version and improve the documentation, but I'm happy with the new API : )

@jpfluger
Copy link
Author

jpfluger commented May 2, 2019

I have my code all tested. Unfortunately I could not interface the new (or old) scs with Echo cleanly. I really like the clear design of the new scs and really like echo (much of my code-base uses echo already). The gorilla/sessions version of middleware doesn't meet my needs either.

I have a working version of an echo-enabled scs repository as a fork.

I don't mind keeping the fork current with scs changes but there isn't a way to post echo-related issues there. The way echo handles redirects/header writing and context saving were the "difficult" (impossible?) points of integration. I tried with an interface but... it just diverges too much.

Thoughts? I don't want to create confusion with the fork but I also think it would be helpful to echo-users. I could write a GIST... or could rename the repo to (scs-echo) and have echo-users post issues there.

@alexedwards alexedwards changed the title Congratulations on v2 Echo compatibility Aug 21, 2019
@alexedwards
Copy link
Owner

Sorry for the delay on this.

It's not obvious what to do about Echo. I'm pretty certain that the 'fault' (if there's such a thing) for the incompatibility issues lies with the design of Echo, not the design of SCS. SCS doesn't do anything unconventional, it works with the standard library, and I don't know of any other Go routers or frameworks where there is a compatibility problem.

A couple of years ago I spent some time trying to figure out exactly what was causing the problems with Echo. IIRC, I filed an issue for one bug I found, but even when that was fixed the problems continued. I think it has all got something to do with the way that Echo manipulates the request Context field. But I was never able to get to the bottom of it.

If it is possible to create a fork of SCS which works with Echo, called scs-echo then that would be great and I'm all for you (or anyone else) to do it 👍

@alexedwards
Copy link
Owner

Thanks for the discussion about this. I don't think there is currently any specific action that needs to be taken on the main SCS respository, so I'm going to close it for now. Feel free to reopen if necessary.

@razorness
Copy link

razorness commented Jan 27, 2021

Hi,

just tested this package with echo v4.1.17: it looks like it works.

Accessing session data works, writing session data works, renew token works and the cookie expiration gets updated.

Here is a code example with redis:

var SessionManager *scs.SessionManager

func Session() echo.MiddlewareFunc {
	pool := &redis.Pool{
		Dial: func() (redis.Conn, error) {
			return redis.Dial("tcp", viper.GetString(config.RedisHost))
		},
		MaxIdle: viper.GetInt(config.RedisMaxIdleConnections),
	}

	SessionManager = scs.New()
	SessionManager.Store = redisstore.New(pool)

	return echo.WrapMiddleware(SessionManager.LoadAndSave)
}

Accessing and writing session data works like this (another middleware):

func AuthMiddleware() echo.MiddlewareFunc {
	return func(h echo.HandlerFunc) echo.HandlerFunc {
		return func(c echo.Context) error {

			userId := SessionManager.GetString(c.Request().Context(), "userId")
			// do some stuff 

		}
	}
}

To be honest, I didn't test it very well yet.

@alexedwards
Copy link
Owner

alexedwards commented Jan 28, 2021

@razorness Thanks, that's interesting. I've updated the note on Echo compatibility in the README to be less strongly-worded for now:

You may have some problems using this package with the Echo framework. If you do, then please consider using the Echo session manager instead.

@razorness
Copy link

I also tried to get scs working with gin-gonic. Because of the implementation of ResponseWriter and instantly sending of the headers in gin, scs is not working properly with gin-gonic.
However, echo and scs seems to be a great combination. 😎

@szqmtl
Copy link

szqmtl commented May 3, 2021

I tried echo 4.2 with scs 2.4, error hander didn't work. Both default error handler and custom error handler returned 200 although http.StatusBadRequest was specified in ctx.JSON. When I commented out the middle ware usage with scs, it worked again.

@szqmtl
Copy link

szqmtl commented May 4, 2021

I am kind of locate the problem which'd be in the function func (bw *bufferedResponseWriter) WriteHeader(code int).

The following snippet is the test function:

type bufferedResponseWriter struct {
	http.ResponseWriter
	buf         bytes.Buffer
	code        int
	wroteHeader bool
}

func (bw *bufferedResponseWriter) Write(b []byte) (int, error) {
	return bw.buf.Write(b)
}

func (bw *bufferedResponseWriter) WriteHeader(code int) {
	if !bw.wroteHeader {
		bw.code = code
		bw.wroteHeader = true
	}
}

func testLoadAndSave(next http.Handler) http.Handler {
	return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
		fmt.Println("in test load")

		bw := &bufferedResponseWriter{ResponseWriter: w}
		next.ServeHTTP(bw, r)
		fmt.Println("out test load")
	})
}

When I added the function to e.Use(echo.WrapMiddleware(testLoadAndSave)), the problem was reproduced. If I changed the code to

type bufferedResponseWriter struct {
	http.ResponseWriter
	buf         bytes.Buffer
	code        int
	wroteHeader bool
	W           http.ResponseWriter  // Keeping the original writer
}

func (bw *bufferedResponseWriter) Write(b []byte) (int, error) {
	return bw.buf.Write(b)
}

func (bw *bufferedResponseWriter) WriteHeader(code int) {
        bw.W.WriteHeader(code)        // execute the original writer
	if !bw.wroteHeader {
		bw.code = code
		bw.wroteHeader = true
	}
	
}

func testLoadAndSave(next http.Handler) http.Handler {
	return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
		fmt.Println("in test load")

		bw := &bufferedResponseWriter{ResponseWriter: w, W: w}.    // make a copy of original writer
		next.ServeHTTP(bw, r)
		fmt.Println("out test load")
	})
}

The problem was gone. Therefore, if someone could investigate further, the reason might be found and got it solved.

Thank you

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

4 participants