librelist archives

« back to archive

More-than-1-level /static URL

More-than-1-level /static URL

From:
Tim Golden
Date:
2011-11-04 @ 16:57
Before I start logging an issue, can I just check whether this:

   /static/css/test.css

is expected to work with the latest Flask/Werkzeug?

In short, I have an app which uses this setup (not uncommon, surely)
and has worked fine with Flask==0.6.1/Werkzeug==0.6.2. With the
latest versions of each, those paths now give a 404. A simpler
path, eg:

   /static/test.css

appears to work.

git bisect pointed to commit 415d1e0cff681f84e90a1af00f96b42aa04e4c89 of 
Werkzeug, which is now quite a while ago. Before I start either
raising an issue or diving in to understand the Werkzeug router, can
I ask if I'm missing something?

FWIW, this is only an issue in development; my live server does
the obvious thing and serves static media via an Apache Alias
directive.

TJG

Re: [flask] More-than-1-level /static URL

From:
Armin Ronacher
Date:
2011-11-04 @ 19:09
Hi,

On 11/4/11 5:57 PM, Tim Golden wrote:
> Before I start logging an issue, can I just check whether this:
> 
>    /static/css/test.css
> 
> is expected to work with the latest Flask/Werkzeug?
Yes.

> git bisect pointed to commit 415d1e0cff681f84e90a1af00f96b42aa04e4c89 of 
> Werkzeug, which is now quite a while ago. Before I start either
> raising an issue or diving in to understand the Werkzeug router, can
> I ask if I'm missing something?
This commit and the ones afterwards added the new routing ordering
system which is more predictable and should be more reliable.  The rule
by itself cannot cause this problem but you might have a other rule with
similar complexity overlapping it.

Eg: /static/<path:foo> versus /<path:foo>/<path:bar>.  Could you paste
the rules on your url map so I can debug this?

(print sorted(app.url_map.iter_rules())


Regards,
Armin

Re: [flask] More-than-1-level /static URL

From:
Armin Ronacher
Date:
2011-11-04 @ 23:31
Hi,

On 11/4/11 8:09 PM, Armin Ronacher wrote:
> Eg: /static/<path:foo> versus /<path:foo>/<path:bar>.  Could you paste
> the rules on your url map so I can debug this?
> 
> (print sorted(app.url_map.iter_rules())
Please do "list" instead of sorted.  sorted messes with what I was
trying to debug in the first place :D


Regards,
Armin

Re: [flask] More-than-1-level /static URL

From:
Tim Golden
Date:
2011-11-05 @ 07:04
On 04/11/2011 23:31, Armin Ronacher wrote:
> Hi,
>
> On 11/4/11 8:09 PM, Armin Ronacher wrote:
>> Eg: /static/<path:foo>  versus /<path:foo>/<path:bar>.  Could you paste
>> the rules on your url map so I can debug this?
>>
>> (print sorted(app.url_map.iter_rules())
> Please do "list" instead of sorted.  sorted messes with what I was
> trying to debug in the first place :D

See below. And, indeed, the 3-part category-item-book
precedes the /static rule:

/title/edit/
/title/edit/
/data/author/
/favicon.ico/
/robots.txt/
/whatsnew/
/choices/
/contact/
/article/
/initial/
/genres/
/logout/
/search/
/choice/
/about/
/login/
/
/initial/<initial>/<book_code>/
/swatch/<type>/<range>
/title/<code>/edit/
/title/<code>/edit/
/<category_code>/<item_code>/<book_code>/
/thumbnail/<code>
/books.cgi/<path:rest>
/whatsnew/<content_code>/
/thumblet/<code>
/article/<code>/
/initial/<initial>/
/choices/<path:rest>
/search/<book_code>/
/choice/<book_code>/
/static/<path:filename>
/genres/<path:rest>
/title/<code>/
/cover/<code>
/<category_code>/<item_code>/
/<category_code>/


TJG

Re: [flask] More-than-1-level /static URL

From:
Tim Golden
Date:
2011-11-04 @ 20:36
On 04/11/2011 19:09, Armin Ronacher wrote:
>Could you paste
> the rules on your url map so I can debug this?

Thanks for taking the time. Rules below:

/static/<path:filename>
/robots.txt/
/favicon.ico/
/books.cgi/<path:rest>
/genres/
/genres/<path:rest>
/choices/
/choices/<path:rest>
/
/about/
/login/
/logout/
/contact/
/search/
/search/<book_code>/
/title/edit/
/title/<code>/edit/
/title/edit/
/title/<code>/edit/
/title/<code>/
/article/
/article/<code>/
/whatsnew/
/whatsnew/<content_code>/
/swatch/<type>/<range>
/cover/<code>
/thumbnail/<code>
/thumblet/<code>
/initial/
/initial/<initial>/
/initial/<initial>/<book_code>/
/choice/
/choice/<book_code>/
/<category_code>/
/<category_code>/<item_code>/
/<category_code>/<item_code>/<book_code>/
/data/author/


I notice that the (automatic) rule for static files has no trailing
slash while the normal Flask behaviour is to redirect to a final
slash. I'll try to see if that's significant once I've sent
this email:

c:\temp>curl --head http://localhost:5000/static/css/goodtoread.css
HTTP/1.0 301 MOVED PERMANENTLY
Content-Type: text/html; charset=utf-8
Content-Length: 303
Location: http://localhost:5000/static/css/goodtoread.css/
Server: Werkzeug/0.9-dev Python/2.7.1
Date: Fri, 04 Nov 2011 20:32:28 GMT

c:\temp>curl --head http://localhost:5000/static/css/goodtoread.css/
HTTP/1.0 404 NOT FOUND
Content-Type: text/html; charset=utf-8
Content-Length: 6463
Server: Werkzeug/0.9-dev Python/2.7.1
Date: Fri, 04 Nov 2011 20:32:07 GMT


TJG

Re: [flask] More-than-1-level /static URL

From:
Armin Ronacher
Date:
2011-11-04 @ 23:21
Hi,

On 11/4/11 9:36 PM, Tim Golden wrote:
> Thanks for taking the time. Rules below:
I will check that ASAP.

> I notice that the (automatic) rule for static files has no trailing
> slash while the normal Flask behaviour is to redirect to a final
> slash. I'll try to see if that's significant once I've sent
> this email:
If the rule is defined with a trailing slash we will redirect the user
if it's missing.  Our design principles say: trailing slash indicates
more content below this resource.  This is compatible with the relative
URL rule.  If you link to "foo" from "/bar/" it will link to "/bar/foo".

In this case "/static/" is a folder but "/static/css/foo.css" is a file.
 No content below foo.css, as such no trailing slash.


Regards,
Armin

Re: [flask] More-than-1-level /static URL

From:
Andy Wilson
Date:
2011-11-04 @ 20:42
Is it being caught by the /<category_code>/ endpoint?


On Fri, Nov 4, 2011 at 3:36 PM, Tim Golden <mail@timgolden.me.uk> wrote:
> On 04/11/2011 19:09, Armin Ronacher wrote:
>>Could you paste
>> the rules on your url map so I can debug this?
>
> Thanks for taking the time. Rules below:
>
> /static/<path:filename>
> /robots.txt/
> /favicon.ico/
> /books.cgi/<path:rest>
> /genres/
> /genres/<path:rest>
> /choices/
> /choices/<path:rest>
> /
> /about/
> /login/
> /logout/
> /contact/
> /search/
> /search/<book_code>/
> /title/edit/
> /title/<code>/edit/
> /title/edit/
> /title/<code>/edit/
> /title/<code>/
> /article/
> /article/<code>/
> /whatsnew/
> /whatsnew/<content_code>/
> /swatch/<type>/<range>
> /cover/<code>
> /thumbnail/<code>
> /thumblet/<code>
> /initial/
> /initial/<initial>/
> /initial/<initial>/<book_code>/
> /choice/
> /choice/<book_code>/
> /<category_code>/
> /<category_code>/<item_code>/
> /<category_code>/<item_code>/<book_code>/
> /data/author/
>
>
> I notice that the (automatic) rule for static files has no trailing
> slash while the normal Flask behaviour is to redirect to a final
> slash. I'll try to see if that's significant once I've sent
> this email:
>
> c:\temp>curl --head http://localhost:5000/static/css/goodtoread.css
> HTTP/1.0 301 MOVED PERMANENTLY
> Content-Type: text/html; charset=utf-8
> Content-Length: 303
> Location: http://localhost:5000/static/css/goodtoread.css/
> Server: Werkzeug/0.9-dev Python/2.7.1
> Date: Fri, 04 Nov 2011 20:32:28 GMT
>
> c:\temp>curl --head http://localhost:5000/static/css/goodtoread.css/
> HTTP/1.0 404 NOT FOUND
> Content-Type: text/html; charset=utf-8
> Content-Length: 6463
> Server: Werkzeug/0.9-dev Python/2.7.1
> Date: Fri, 04 Nov 2011 20:32:07 GMT
>
>
> TJG
>

Re: [flask] More-than-1-level /static URL

From:
Armin Ronacher
Date:
2011-11-04 @ 23:24
Hi,

On 11/4/11 9:42 PM, Andy Wilson wrote:
> Is it being caught by the /<category_code>/ endpoint?
It should not:

from flask import Flask

app = Flask(__name__)
app.add_url_rule('/<category>/', endpoint='category')
app.add_url_rule('/<category>/<item>', endpoint='category_item')

with app.test_request_context('/static/css/foo.css') as ctx:
    assert ctx.request.endpoint == 'static'
    assert ctx.request.view_args == {'filename': 'css/foo.css'}

with app.test_request_context('/foo/') as ctx:
    assert ctx.request.endpoint == 'category'
    assert ctx.request.view_args == {'category': 'foo'}

with app.test_request_context('/foo/bar') as ctx:
    assert ctx.request.endpoint == 'category_item'
    assert ctx.request.view_args == {'category': 'foo', 'item': 'bar'}


That passes for me.


Regards,
Armin

Re: [flask] More-than-1-level /static URL

From:
Andy Wilson
Date:
2011-11-04 @ 23:53
On Fri, Nov 4, 2011 at 6:24 PM, Armin Ronacher
<armin.ronacher@active-4.com> wrote:
> Hi,
>
> On 11/4/11 9:42 PM, Andy Wilson wrote:
>> Is it being caught by the /<category_code>/ endpoint?
> It should not:
>
> ...
>
> That passes for me.
>
>
> Regards,
> Armin
>


Failing for me if you add the rule for /<category>/<item>/<book_code>/


from flask import Flask

app = Flask(__name__)
app.add_url_rule('/<category>/', endpoint='category')
app.add_url_rule('/<category>/<item>/', endpoint='category_item')
app.add_url_rule('/<category>/<item>/<book_code>/',
endpoint='category_item_bookcode')

with app.test_request_context('/static/css/foo.css') as ctx:
   assert ctx.request.endpoint == 'static'
   assert ctx.request.view_args == {'filename': 'css/foo.css'}

with app.test_request_context('/foo/') as ctx:
   assert ctx.request.endpoint == 'category'
   assert ctx.request.view_args == {'category': 'foo'}

with app.test_request_context('/foo/bar') as ctx:
   assert ctx.request.endpoint == 'category_item'
   assert ctx.request.view_args == {'category': 'foo', 'item': 'bar'}




Maybe this is useful: with a url rule for
'/<category>/<item>/<book_code>/', ctx.request.endpoint is None but
with '/<category>/<item>/<book_code>', ctx.request.endpoint is
'category_item_bookcode'

Re: [flask] More-than-1-level /static URL

From:
Tim Golden
Date:
2011-11-04 @ 21:00
 >> /static/<path:filename>
...
 >> /<category_code>/
 >> /<category_code>/<item_code>/
 >> /<category_code>/<item_code>/<book_code>/

On 04/11/2011 20:42, Andy Wilson wrote:
> Is it being caught by the /<category_code>/ endpoint?

Well I didn't think it would be (on account of /static being
first in the list) but it appears that you're right: if I
munge those /<category_code>/.../ URLs, the stylesheets
show up.

So my question now is... is there an issue with the routing
order? Or do I -- somehow -- have to rework my URL map to
allow for this.

This is not in any way a critical situation for me: my live
site is running Flask 0.6 and doesn't need to upgrade. And
in any case, the live site serves /static files via Apache.
But if I did want to upgrade, say to start using Blueprints,
I'd need to know what approach I should be using.

TJG

Re: [flask] More-than-1-level /static URL

From:
Juancarlo Añez
Date:
2011-11-04 @ 22:41
On Fri, Nov 4, 2011 at 16:30, Tim Golden <mail@timgolden.me.uk> wrote:

> Well I didn't think it would be (on account of /static being
> first in the list) but it appears that you're right: if I
> munge those /<category_code>/.../ URLs, the stylesheets
> show up.
>

That rule doesn't seem RESTful or fair enough for Flask or anything else.
It's a kind of "catch-all".

Am I mistaken?

-- 
JA

Re: [flask] More-than-1-level /static URL

From:
Tim Golden
Date:
2011-11-05 @ 09:44
On 04/11/2011 22:41, Juancarlo Añez wrote:
>
>
> On Fri, Nov 4, 2011 at 16:30, Tim Golden <mail@timgolden.me.uk
> <mailto:mail@timgolden.me.uk>> wrote:
>
>     Well I didn't think it would be (on account of /static being
>     first in the list) but it appears that you're right: if I
>     munge those /<category_code>/.../ URLs, the stylesheets
>     show up.
>
>
> That rule doesn't seem RESTful or fair enough for Flask or anything
> else. It's a kind of "catch-all".

It's not a catch-all;
it's a kind of generic route as I have a number of categories, all
of which use the same display view and differ only in the model
they're presenting (/author/tim-golden, /genre/historical, 
/age-range/teens etc.). I don't pretend that this is the only or the 
best way
to do this, but it does work.

It can, by accident, operate as a catch-all, which is what's
happening here: it's matching any three-part path which isn't
caught higher up. In this case, however, it 404-s out as early
as it can when it detects that what you're requesting doesn't
match a known category. (Which is what's happening with the
/static paths).

As to whether it's RESTful or not, I don't see why it shouldn't be,
although I don't pretend to be an authority on RESTfulness. Frankly,
though, if someone came back and said: it's not RESTful, I wouldn't
be losing too much sleep as a result. :)

TJG

Re: [flask] More-than-1-level /static URL

From:
Tim Golden
Date:
2011-11-04 @ 18:44
On 04/11/2011 16:57, Tim Golden wrote:
> Before I start logging an issue, can I just check whether this:
>
>     /static/css/test.css
>
> is expected to work with the latest Flask/Werkzeug?

Just to be clear: I'm saying that this has worked fine for months
on a production website running 0.6 but no longer does in a dev
setup with newer versions of Flask/Werkzeug

TJG

Re: [flask] More-than-1-level /static URL

From:
Simon Sapin
Date:
2011-11-04 @ 17:50
Le 04/11/2011 17:57, Tim Golden a écrit :
> Before I start logging an issue, can I just check whether this:
>
>     /static/css/test.css
>
> is expected to work with the latest Flask/Werkzeug?

Hi,

I assume that you let Flask handle static files? Then it’s supposed to 
work since it uses <path:filename> instead of just <filename> in the URL 
rule. (The later does not allow slashes.) Do you have another view 
function named "static"? Flask uses this name internally for static files.

https://github.com/mitsuhiko/flask/blob/master/flask/app.py#L449

Regards,
-- 
Simon Sapin

Re: [flask] More-than-1-level /static URL

From:
Tim Golden
Date:
2011-11-04 @ 18:42
On 04/11/2011 17:50, Simon Sapin wrote:
> Le 04/11/2011 17:57, Tim Golden a écrit :
>> Before I start logging an issue, can I just check whether this:
>>
>>      /static/css/test.css
>>
>> is expected to work with the latest Flask/Werkzeug?
>
> Hi,
>
> I assume that you let Flask handle static files?

In dev: yes; in production, they're intercepted by an Apache Alias.

> Then it’s supposed to
> work since it uses<path:filename>  instead of just<filename>  in the URL
> rule. (The later does not allow slashes.)

That's what I'd understood. And this works fine for Flask 0.6, just
not for later versions. (See my earlier post for a git bisect guess).

> Do you have another view
> function named "static"? Flask uses this name internally for static files.

Didn't think of that, but no I don't

TJG