1. David Chambers
  2. Mango

Commits

David Chambers  committed cfc213a

Fixed bug (caused by inappropriate use of `os.walk`) which allowed /bar/ to match /path/to/posts/foo/bar/.

  • Participants
  • Parent commits 4fd9215
  • Branches default

Comments (0)

Files changed (1)

File views.py

View file
             }, **context_defaults(request)))
 
 def post(request, path, view_source=False):
-    filepath = UNIX_PATH_TO_POSTS
+    fragments = path.split('/')
+    fragments.reverse()
+
+    files = []
+    directories = []
+    for dirpath, dirnames, filenames in os.walk(UNIX_PATH_TO_POSTS):
+        for filename in filenames:
+            head, tail = os.path.split(os.path.join(dirpath, filename))
+            unix_path = u'/'.join(head.split(os.sep)).replace(UNIX_PATH_TO_POSTS, '')
+            files.append((os.path.join(*unix_path.split('/')), tail))
+        for dirname in dirnames:
+            unix_path = u'/'.join(os.path.join(dirpath, dirname).split(os.sep)).replace(
+                    UNIX_PATH_TO_POSTS, '')
+            directories.append(os.path.join(*unix_path.split('/')))
+
+    filepath = None
     is_short = False
-    fragments = path.split('/')
-    last_index = len(fragments) - 1
+    for head, tail in files:
+        match = re.match(RE['alias=>canon'], os.path.splitext(tail)[0])
+        if not filepath and fragments[0] in match.groupdict().values():
+            filepath = tail
+            if fragments[0] == match.group('alias'):
+                is_short = True
+            for fragment in fragments[1:]:
+                head, tail = os.path.split(head)
+                match = re.match(RE['alias=>canon'], tail.lower())
+                if fragment in match.groupdict().values():
+                    filepath = os.path.join(tail, filepath)
+                    if not is_short and fragment == match.group('alias'):
+                        is_short = True
+                else:
+                    filepath = None
+                    is_short = False
+                    break
 
-    def match_fragment(dirnames=[], filenames=[]):
-        for name in dirnames or filenames:
-            match = re.match(RE['alias=>canon'],
-                    name.lower() if dirnames else os.path.splitext(name)[0])
-            if fragment in match.groupdict().values():
-                return (True, os.path.join(filepath, name), is_short or fragment == match.group('alias'))
-        return (False, filepath, is_short)
+    if not filepath:
+        for directory in directories:
+            head = directory
+            if not filepath:
+                for fragment in fragments:
+                    head, tail = os.path.split(head)
+                    match = re.match(RE['alias=>canon'], tail.lower())
+                    if fragment in match.groupdict().values():
+                        filepath = os.path.join(tail, filepath) if filepath else tail
+                        if fragment == match.group('alias'):
+                            is_short = True
+                    else:
+                        filepath = None
+                        is_short = False
+                        break
 
-    for index, fragment in enumerate(fragments):
-        found = False
-        for dirpath, dirnames, filenames in os.walk(filepath):
-            if index == last_index:
-                found, filepath, is_short = match_fragment(filenames=filenames) # files take precedence
-                if found:
-                    break
-            found, filepath, is_short = match_fragment(dirnames=dirnames)
-            if found:
-                break
+    if filepath:
+        filepath = os.path.join(PATH_TO_POSTS, filepath)
 
-    if not found:
+    if not filepath or not os.path.exists(filepath):
         raise Http404
 
     if os.path.isdir(filepath):
         if view_source:
             return HttpResponsePermanentRedirect('../')
 
+        fragments = [u'']
+        head, tail = os.path.split(filepath)
+        while tail:
+            match = re.match(RE['alias=>canon'], tail)
+            fragments.insert(1, os.path.join(tail, filepath) if filepath else tail)
+            head, tail = os.path.split(head)
+        filepath = os.path.join(*fragments)
+
+        if is_short:
+            fragments = [u'']
+            for fragment in filepath.split(os.sep):
+                if fragment:
+                    match = re.match(RE['alias=>canon'], fragment)
+                    fragments.append(match.group('canon'))
+            return HttpResponseRedirect(u'/'.join(fragments).replace(
+                    UNIX_PATH_TO_POSTS, ''))
+
         match = re.match(RE['alias=>canon'], os.path.split(filepath)[1])
         category_posts, category_pages = utils.get_documents(filepath)
         return render_to_response('category.dhtml', dict({