Commits

Donald Stufft committed cd0c21d

Handle the secondary disaptch of /pypi/*

Comments (0)

Files changed (1)

 defusedxml.xmlrpc.monkey_patch()
 
 # system imports
+import inspect
 import sys, os, urllib, cStringIO, traceback, cgi, binascii, gzip
 import time, random, smtplib, base64, email, types, urlparse
 import re, zipfile, logging, shutil, Cookie, subprocess, hashlib
             routing.Rule("/mirrors/", endpoint="mirrors", methods=["GET"]),
             routing.Rule("/security/", endpoint="security", methods=["GET"]),
 
+            # PyPI
+            #   These routes are different then the rest because there's a
+            #   secondary level of dispatching that needs to be done based
+            #   on the :action query string. The Werkzeug URL routing does not
+            #   support dispatching based on a query string.
+            routing.Submount("/pypi", [
+                routing.Rule("/",
+                    defaults={
+                        "package": None,
+                        "version": None,
+                        "action": None,
+                    },
+                    endpoint="dispatch_pypi",
+                ),
+                routing.Rule("/<package>/",
+                    defaults={"version": None, "action": None},
+                    endpoint="dispatch_pypi",
+                ),
+                routing.Rule("/<package>/<version>/",
+                    defaults={"action": None},
+                    endpoint="dispatch_pypi",
+                ),
+                routing.Rule("/<package>/<version>/<action>/",
+                    endpoint="dispatch_pypi",
+                ),
+            ]),
+
             # OpenID
             routing.Rule("/id/", endpoint="openid_discovery"),
             routing.Rule("/id/<username>/", endpoint="openid_user"),
             # Dispatch to the endpoint
             return getattr(self, "do_%s" % endpoint)(request, database, **args)
 
-            # Secondary dispatch based on :action and request.path
-            action, name, version = None, None, None
-            if ":action" in request.form:
-                action = request.form[":action"]
-                if isinstance(action, list):
-                    raise RuntimeError("Multiple actions: %r" % action)
-            elif request.path:
-                # Split into path items, drop leading slash
-                items = request.path.decode('utf-8').split('/')[1:]
-
-                if request.path == "/":
-                    action = "index"
-                elif len(items) >= 1:
-                    name = items[0]
-                    action = "display"
-
-                if len(items) >= 2 and items[1]:
-                    version = items[1]
-                    action = "display"
-
-                # TODO: Url based instead of ?:action based???
-                if len(items) == 3 and items[2]:
-                    action = items[2]
-
-                if not action:
-                    raise NotFound
-            else:
+    def do_dispatch_pypi(self, request, database, package, version, action):
+        """
+        A Secondary dispatch method based on the action query string
+        """
+        action = request.form.get(":action", action)
+        if isinstance(action, list):
+            raise RuntimeError("Multiple actions: %r" % action)
+
+        if not action:
+            # If we have no action, package, or version we are at the home page
+            if not package and not version:
                 action = "home"
-
-            if version in {"doap", "json"}:
-                action, version = version, None
-
-            # make sure the user has permission
-            if action in {"submit"}:
-                if not request.user.authenticated:
-                    raise Unauthorised
-                if request.database.get_otk(request.user.username):
-                    raise Unauthorised("Incomplete registration; check your "
-                                       "email")
-                if not request.database.user_active(request.user.username):
-                    raise Unauthorised("Inactive User")
-
-            # handle the action
-            if action in '''home browse rss index search submit doap
-            display_pkginfo submit_pkg_info remove_pkg pkg_edit verify
-            submit_form display register_form user user_form
-            forgotten_password_form forgotten_password
-            password_reset pw_reset pw_reset_change
-            role role_form list_classifiers login logout files urls
-            file_upload show_md5 doc_upload claim openid openid_return dropid
-            clear_auth addkey delkey lasthour json gae_file about delete_user
-            rss_regen openid_endpoint openid_decide_post packages_rss
-            exception'''.split():
-                return getattr(self, action)(request, database)
+            elif package and not version:
+                action = "display"
+            elif package and version:
+                action = "display"
+
+        if version in {"doap", "json"}:
+            action, version = version, None
+
+        if not action:
+            raise NotFound
+
+        # Make sure the user has permission
+        if action in {"submit"}:
+            if not request.user.authenticated:
+                raise Unauthorised
+            if database.get_otk(request.user.username):
+                raise Unauthorised("Incomplete registration; check your "
+                                   "email")
+            if not database.user_active(request.user.username):
+                raise Unauthorised("Inactive User")
+
+        try:
+            if action in {
+                    "home", "browse", "rss", "index", "search", "submit",
+                    "doap", "display_pkginfo", "submit_pkg_info", "remove_pkg",
+                    "pkg_edit", "verify", "submit_form", "display",
+                    "register_form", "user", "user_form",
+                    "forgotten_password_form", "forgotten_password",
+                    "password_reset", "pw_reset", "pw_reset_change", "role",
+                    "role_form", "list_classifiers", "login", "logout",
+                    "files", "urls", "file_upload", "show_md5", "doc_upload",
+                    "claim", "openid", "openid_return", "dropid", "clear_auth",
+                    "addkey", "delkey", "lasthour", "json", "gae_file",
+                    "about", "delete_user", "rss_regen", "openid_endpoint",
+                    "openid_decide_post", "packages_rss", "exception"}:
+                func = getattr(self, "do_%s" % action)
+
+                # Determine which kwargs to pass into the function
+                kwargs = {"package": package, "version": version}
+                argspec = inspect.getargspec(func)
+                kwargs = {k: v for k, v in kwargs.items() if k in argspec.args}
+
+                return func(request, database, **kwargs)
             else:
                 raise NotFound
-
+        finally:
             # TODO(Werkzeug): Determine if this needs to return a response
-            if action in '''file_upload submit submit_pkg_info pkg_edit
-            remove_pkg'''.split():
+            if action in {
+                    "file_upload", "submit", "submit_pkg_info", "pkg_edit",
+                    "remove_pkg"}:
                 self.rss_regen()
 
     def authenticate(self, request, database):