tornadoweb / tornadoweb/tornado

Template loader problems with absolute paths

Open
#731 9 comments 0 reactions 0 assignees View on GitHub

Nobody has claimed this yet.

template windows
Dominant language
Python
Stars
22.2k
Forks
5.6k
Avg merge
3h 42m
Merged PRs (30d)
16

Description

Several problems in Loader.resolve_path:

  • If RequestHandler.render() is passed an absolute path, relative paths in {%extends%} and friends don't work.
  • It uses startswith('/') instead of isabs()
  • Strange things happen if you use .. in an extends directive to break out of the template loader's root.

From the mailing list:
In my project, template folder is not include the template root path, such as Template Load: self.root is "D:\website\app_1\template"
but some common template file is not include in this path. so When I use the {% extends%} like follow:
{% extends "../../template/common/layout.html" %}
I found if the "../../template/common/layout.html" has "{% include logo.html%}", the logo.html cannot be found in the current folder.

Website tree like that:
|- template
| - common | |- layout.html #{%include logo.html%} |- logo.html #ERROR, cannot found this path
- app - template
`- main.html -- #{%extend ../../template/common/layout.html%}

I found there is a bug in class Loader(BaseLoader) resolve_path method:

def resolve_path(self, name, parent_path=None):
    if parent_path and not parent_path.startswith("<") and \
       not parent_path.startswith("/") and \
       not name.startswith("/"):
        current_path = os.path.join(self.root, parent_path)
        file_dir = os.path.dirname(os.path.abspath(current_path))
        relative_path = os.path.abspath(os.path.join(file_dir, name))
        if relative_path.startswith(self.root):
            name = relative_path[len(self.root) + 1:]
        #BUG: should add else here
        else:
            name = relative_path
    return name

bdarnell:
Hmm, this code is strange - it doesn't really make sense to call abspath and put the result in a variable called "relative_path", but it's been there since the beginning. It looks like there are other issues too - the startswith("/") calls should probably be os.path.isabs() to work on windows. If we make that change, your proposed fix no longer works, since layout.html's "name" will be absolute and it will no longer try to load logo.html as a relative path.

It doesn't feel right to use a template loader to access files outside of its root in the first place. I think it would be better if your loader's root was the common ancestor of all the templates you need. Or maybe we need a way to chain multiple loaders together. I'll have to think more about this code and what it's trying to do.

Contributor guide

Open the contributing guide

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

Research direction

Start at Loader.resolve_path and its use from RequestHandler.render, then reproduce the absolute-path, Windows-path, and parent-directory cases described in the issue. Before changing code, clarify the intended behavior for templates outside the loader root; done requires an agreed resolution for relative includes, absolute paths, and root escapes.

Written by the indexing model from the issue text.

Assessment

Tech stack
python
Domain
backend, web-dev
Issue type
Bug
Difficulty
5/5
Estimated time
Over a week
Activity status
Stale
Clarity
Needs clarification
Newbie friendliness
35/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.