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

Bottle app does not work after mount #520

Closed
vermoudakias opened this issue Jul 1, 2013 · 3 comments
Closed

Bottle app does not work after mount #520

vermoudakias opened this issue Jul 1, 2013 · 3 comments

Comments

@vermoudakias
Copy link

Consider the following code:

from bottle import Bottle, request, response, HTTPError

root_app = Bottle()
home_app = Bottle()
param_app = Bottle()

PREFIX_PARAM   = 'params'

HOME_OBJ = {
    PREFIX_PARAM: 'Service parameters',
}

PARAM_OBJ = {
    'p1': 'Testing param',
}


@home_app.get('/')
def home_list():
    return HOME_OBJ

@param_app.get('/')
@param_app.get('/<oid>')
def param_list(oid=None):
    print '*** param list (%s)' % oid
    if oid is not None and oid not in PARAM_OBJ:
        raise HTTPError(status=404)
    return PARAM_OBJ



path_prefix = '/app'
#path_prefix = '/'
if path_prefix and len(path_prefix) > 0:
    p = path_prefix.strip(' /')
    if len(p) > 0:
        p = '/%s' % p
    else:
        p = ''
else:
    p = ''
print 'Path prefix is [%s]' % p
if len(p) == 0 or p == '/':
    root_app.merge(home_app)
else:
    root_app.mount(p, home_app)
root_app.mount('%s/%s' % (p, PREFIX_PARAM), param_app)
root_app.run(host='localhost', port=8080)

I perform the following requests (using httpie https://github.com/jkbr/httpie):

host~ # http GET localhost:8080/app
HTTP/1.0 200 OK
Content-Length: 32
Content-Type: application/json
Date: Mon, 01 Jul 2013 15:12:46 GMT
Server: WSGIServer/0.1 Python/2.7.3

{
    "params": "Service parameters"
}
host~ # http GET localhost:8080/app/params
HTTP/1.0 200 OK
Content-Length: 23
Content-Type: application/json
Date: Mon, 01 Jul 2013 15:14:08 GMT
Server: WSGIServer/0.1 Python/2.7.3

{
    "p1": "Testing param"
}
host~ # http GET localhost:8080/app/params/p1
HTTP/1.0 404 Not Found
Content-Length: 742
Content-Type: text/html; charset=UTF-8
Date: Mon, 01 Jul 2013 15:14:42 GMT
Server: WSGIServer/0.1 Python/2.7.3

<!DOCTYPE HTML PUBLIC "-//IETF//DTD HTML 2.0//EN">
    <html>
        <head>
            <title>Error: 404 Not Found</title>
            <style type="text/css">
              html {background-color: #eee; font-family: sans;}
              body {background-color: #fff; border: 1px solid #ddd;
                    padding: 15px; margin: 15px;}
              pre {background-color: #eee; border: 1px solid #ddd; padding: 5px;}
            </style>
        </head>
        <body>
            <h1>Error: 404 Not Found</h1>
            <p>Sorry, the requested URL <tt>&#039;http://localhost:8080/app/params/p1&#039;</tt>
               caused an error:</p>
            <pre>Not found: &#039;/params/p1&#039;</pre>
        </body>
    </html>

The last request fails to match the rule @param_app.get('/<oid>').
Any clue why this is happening? Is this a mount(...) bug?

Also, if I use path_prefix = '/' (in this case, root_app.merge() is used), and perform the same requests (with the correct URLs) the last call succeeds.

@defnull
Copy link
Member

defnull commented Jul 1, 2013

Mounting an application to a prefix path says that everything under that path should be redirected to the mounted app. The URL /app/parm/p1 is handled by the home_app, because that was mounted to /app. Thats documented and intended behavior.

@vermoudakias
Copy link
Author

Thanks for looking at it.
If this is the case, then why the second URL hit /app/params matches the rule @param_app.get('/')?

@vermoudakias
Copy link
Author

I did some testing and here what I found.
First, I mount the param_app on home_app instead of root_app.
Second, I moved the mount/merge block of root_app after the setup of everything else (see the IMPORTANT line below).

from bottle import Bottle, request, response, HTTPError

root_app = Bottle()
home_app = Bottle()
param_app = Bottle()

PREFIX_PARAM   = 'params'

HOME_OBJ = {
    PREFIX_PARAM: 'Service parameters',
}

PARAM_OBJ = {
    'p1': 'Testing param',
}

@home_app.get('/')
def home_list(oid=None):
    print '*** home list (%s)' % oid
    return HOME_OBJ

@param_app.get('/')
@param_app.get('/<oid>')
def param_list(oid=None):
    print '*** param list (%s)' % oid
    if oid is not None and oid not in PARAM_OBJ:
        raise HTTPError(status=404)
    return PARAM_OBJ


# IMPORTANT: Setup home_app mount before root_app
home_app.mount('/%s' % PREFIX_PARAM, param_app)

# http GET localhost:8080/app
# http GET localhost:8080/app/params
# http GET localhost:8080/app/params/p1
path_prefix = '/app'

# http GET localhost:8080
# http GET localhost:8080/params
# http GET localhost:8080/params/p1
#path_prefix = '/'

if path_prefix and len(path_prefix) > 0:
    p = path_prefix.strip(' /')
    if len(p) > 0:
        p = '/%s' % p
    else:
        p = '/'
else:
    p = '/'
print 'Path prefix is [%s]' % p
if len(p) == 0 or p == '/':
    root_app.merge(home_app)
else:
    root_app.mount(p, home_app)

# XXX Does not work
#home_app.mount('/%s' % PREFIX_PARAM, param_app)

root_app.run(host='localhost', port=8080)

Now everything works as intended.
Isn't this home_app.mount(...) line order a bit weird?

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

2 participants