bottlepy / bottle

bottle.py is a fast and simple micro-framework for python web-applications.
http://bottlepy.org/
MIT License
8.37k stars 1.46k forks source link

Cookie doesn't set in dynamic route. #1238

Closed macwilam closed 3 years ago

macwilam commented 4 years ago

I think I found a bug. When I am trying to set a cookie in a dynamic route it is not being set. This simplest code to reproduce for me is:

from bottle import Bottle, route, run, request, redirect, response

app = Bottle()

secretKey = "123456"

@app.route('/test')
@app.route('/test/<uid>')
def anonymous(uid = 'none2'):
    print(uid)
    response.set_cookie("user", uid, secret=secretKey)
    redirect('/') 

@app.route('/')
def index():
    print(request.get_cookie("user", secret=secretKey))
    return "result" + str(request.get_cookie("user", secret=secretKey))
app.run(host='localhost', port=8981, reloader=True, debug=True)

When I start the server and visit: http://localhost:8981/test/anything "antyhing" is printed in the console but the result is "resultNone" if we visit http://localhost:8981/test the result is "resultsetOK"

Environment:

botle 2.18
Python 3.6.9

The cookie is not being set if we just return template or something and than visit index manually. I added redirect as it is easiest to check if it is working.

If I am doing something stupid and it is supposed to work this way I apologize.

macwilam commented 4 years ago

After more testing it is not a problem with the cookie not being set but it dissapears. So if instead of redirect in /test/ I use template i can see the cookie being set properly in the browser. however if i move to different site on the server cookies are not visible. As if they are set for a different domain.

So I finally managed to get to the root of it. It is all about "path" in the cookie. If the route is "'/test'" the path is "/" and when we use a dynamic route the path in the cookie is "/test/". So yes it is kind of a feature as it is according to documentation in a way but I think more info about it could be provided in docs.

PyB1l commented 3 years ago

Hi @macwilam, I find that path strip functionality is useful more cases, including cookie settings. I am using a small hook in bottle.Bottle instances:

def strip_path_hook():
    """Ignore trailing slashes.
    """
    bottle.request.environ['PATH_INFO'] = \
        bottle.request.environ['PATH_INFO'].rstrip('/')

app.hook('before_request')(strip_path)

And I do not have issues with cookies.

defnull commented 3 years ago

That's how cookies work. By default cookies are limited to the "parent" path of the current request. A cookie defined by /test/whatever will be limited to the /test/* path. You need to set path='/' if you want the cookie to be sent to other paths too.

Removing the tailing slash as suggested by @PyB1l has a lot of problems. The paths /foo and /foo/ are not the same. Relative URLs and links resolve differently for example. If you really want to do that, actually redirecting the client to the correct path would be better.