diff --git a/django/core/handlers/base.py b/django/core/handlers/base.py
index 3606e18..ce51d8a 100644
--- a/django/core/handlers/base.py
+++ b/django/core/handlers/base.py
@@ -97,28 +97,39 @@ class BaseHandler(object):
                         urlresolvers.set_urlconf(urlconf)
                         resolver = urlresolvers.RegexURLResolver(r'^/', urlconf)
 
-                    callback, callback_args, callback_kwargs = resolver.resolve(
-                            request.path_info)
+                    for candidate in resolver.backtracking_resolve(request.path_info):
+                        callback, callback_args, callback_kwargs = candidate.func, candidate.args, candidate.kwargs
 
-                    # Apply view middleware
-                    for middleware_method in self._view_middleware:
-                        response = middleware_method(request, callback, callback_args, callback_kwargs)
-                        if response:
-                            break
-
-                if response is None:
-                    try:
-                        response = callback(request, *callback_args, **callback_kwargs)
-                    except Exception, e:
-                        # If the view raised an exception, run it through exception
-                        # middleware, and if the exception middleware returns a
-                        # response, use that. Otherwise, reraise the exception.
-                        for middleware_method in self._exception_middleware:
-                            response = middleware_method(request, e)
+                        # Apply view middleware
+                        for middleware_method in self._view_middleware:
+                            response = middleware_method(request, callback, callback_args, callback_kwargs)
                             if response:
                                 break
+
                         if response is None:
-                            raise
+                            try:
+                                response = callback(request, *callback_args, **callback_kwargs)
+                                break
+                            except urlresolvers.ContinueResolving:
+                                # If the URL resolver candidate raised a ContinueResolving,
+                                # allow the URL resolver to pick up where it left off
+                                continue
+                            except Exception, e:
+                                # If the view raised an exception, run it through exception
+                                # middleware, and if the exception middleware returns a
+                                # response, use that. Otherwise, reraise the exception.
+                                for middleware_method in self._exception_middleware:
+                                    response = middleware_method(request, e)
+                                    if response:
+                                        break
+                                if response is None:
+                                    raise
+
+                        # We need to ensure that we break out of the URL resolver
+                        # search loop, since we found a URL resolver match
+                        # but the matched view did not raise a ContinueResolving exception
+                        # so we want to terminate this search now
+                        break
 
                 # Complain if the view returned None (a common error).
                 if response is None:
diff --git a/django/core/urlresolvers.py b/django/core/urlresolvers.py
index a253319..d2fd50d 100644
--- a/django/core/urlresolvers.py
+++ b/django/core/urlresolvers.py
@@ -68,9 +68,50 @@ class ResolverMatch(object):
         return "ResolverMatch(func=%s, args=%s, kwargs=%s, url_name='%s', app_name='%s', namespace='%s')" % (
             self.func, self.args, self.kwargs, self.url_name, self.app_name, self.namespace)
 
+class ResolverMatches(object):
+    def __init__(self, resolver):
+        self.resolver = resolver
+        self.__in_iteration = False
+
+    def __iter__(self):
+        return self
+
+    def __repr__(self):
+        return self.candidate.__repr__()
+
+    def next(self, peek=False):
+        # If this is the first time accessing our iterator, or we have
+        # already started iteration, fetch and store the next candidate,
+        # or we want to keep in on the current candidate
+        if not hasattr(self, '_candidate') or (self.__in_iteration and not peek):
+            self._candidate = self.resolver.next()
+
+        # Functions like __nonzero__ should not trigger the start of
+        # iteration over the resolver generator. They need to know
+        # if the generator is empty or not, but their peeking should not
+        # remove an item from the generator for those that attempt to
+        # iterate over the generator at a later point.
+        if not peek:
+            self.__in_iteration = True
+        return self._candidate
+
+    def candidate(self):
+        return self.next(peek=True)
+    candidate = property(candidate)
+
+    def __nonzero__(self):
+        try:
+            self.next(peek=True)
+        except Resolver404:
+            return False
+        return True
+
 class Resolver404(Http404):
     pass
 
+class ContinueResolving(Resolver404):
+    pass
+
 class NoReverseMatch(Exception):
     # Don't make this raise an error when used in a template.
     silent_variable_failure = True
@@ -291,13 +332,28 @@ class RegexURLResolver(LocaleRegexProvider):
         return self._app_dict[language_code]
 
     def resolve(self, path):
-        tried = []
+        return self.backtracking_resolve(path).next()
+
+    def backtracking_resolve(self, path, tried=None):
+        return ResolverMatches(self.__backtracking_resolve(path, tried))
+
+    def __backtracking_resolve(self, path, tried=None):
+        if tried is None:
+            tried = []
+
         match = self.regex.search(path)
         if match:
             new_path = path[match.end():]
             for pattern in self.url_patterns:
+                sub_tried = []
+                sub_matches = []
                 try:
-                    sub_match = pattern.resolve(new_path)
+                    if isinstance(pattern, RegexURLResolver):
+                        sub_matches = pattern.backtracking_resolve(new_path, sub_tried)
+                    else:
+                        sub_match = pattern.resolve(new_path)
+                        if sub_match:
+                            sub_matches = [sub_match]
                 except Resolver404, e:
                     sub_tried = e.args[0].get('tried')
                     if sub_tried is not None:
@@ -305,13 +361,24 @@ class RegexURLResolver(LocaleRegexProvider):
                     else:
                         tried.append([pattern])
                 else:
-                    if sub_match:
-                        sub_match_dict = dict([(smart_str(k), v) for k, v in match.groupdict().items()])
-                        sub_match_dict.update(self.default_kwargs)
-                        for k, v in sub_match.kwargs.iteritems():
-                            sub_match_dict[smart_str(k)] = v
-                        return ResolverMatch(sub_match.func, sub_match.args, sub_match_dict, sub_match.url_name, self.app_name or sub_match.app_name, [self.namespace] + sub_match.namespaces)
-                    tried.append([pattern])
+                    if sub_matches:
+                        for sub_match in sub_matches:
+                            sub_match_dict = dict([(smart_str(k), v) for k, v in match.groupdict().items()])
+                            sub_match_dict.update(self.default_kwargs)
+                            for k, v in sub_match.kwargs.iteritems():
+                                sub_match_dict[smart_str(k)] = v
+                            yield ResolverMatch(
+                                    sub_match.func,
+                                    sub_match.args,
+                                    sub_match_dict,
+                                    sub_match.url_name,
+                                    self.app_name or sub_match.app_name,
+                                    [self.namespace] + sub_match.namespaces,
+                                    )
+                    if sub_tried:
+                        tried.extend([[pattern] + t for t in sub_tried])
+                    else:
+                        tried.append([pattern])
             raise Resolver404({'tried': tried, 'path': new_path})
         raise Resolver404({'path' : path})
 
@@ -415,6 +482,11 @@ def resolve(path, urlconf=None):
         urlconf = get_urlconf()
     return get_resolver(urlconf).resolve(path)
 
+def backtracking_resolve(path, urlconf=None):
+    if urlconf is None:
+        urlconf = get_urlconf()
+    return get_resolver(urlconf).backtracking_resolve(path)
+
 def reverse(viewname, urlconf=None, args=None, kwargs=None, prefix=None, current_app=None):
     if urlconf is None:
         urlconf = get_urlconf()
diff --git a/docs/topics/http/urls.txt b/docs/topics/http/urls.txt
index 5c9711c..7a4ad98 100644
--- a/docs/topics/http/urls.txt
+++ b/docs/topics/http/urls.txt
@@ -51,13 +51,19 @@ algorithm the system follows to determine which Python code to execute:
    ``urlpatterns``. This should be a Python list, in the format returned by
    the function :func:`django.conf.urls.patterns`.
 
-3. Django runs through each URL pattern, in order, and stops at the first
-   one that matches the requested URL.
-
-4. Once one of the regexes matches, Django imports and calls the given
-   view, which is a simple Python function. The view gets passed an
-   :class:`~django.http.HttpRequest` as its first argument and any values
-   captured in the regex as remaining arguments.
+3. Django runs through each URL pattern, in order, and for each matched pattern
+   calls the corresponding view. If a view raises a
+   :class:`~django.core.urlresolvers.ContinueResolving` exception it will
+   continue calling the next matched pattern until it runs out of matches or a
+   view does not raise an :class:`~django.core.urlresolvers.ContinueResolving`
+   exception, in which case it will return the matched views response.
+
+4. The view called by a matched pattern of the URL resolver is a simple Python
+   function that gets passed an :class:`~django.http.HttpRequest` as its first
+   argument and any values captured in the regex as remaining arguments. As
+   mentioned above, a view can raise a
+   :class:`~django.core.urlresolvers.ContinueResolving` exception to allow the
+   URL resolver to continue searching for potential URL pattern matches.
 
 5. If no regex matches, or if an exception is raised during any
    point in this process, Django invokes an appropriate
diff --git a/tests/regressiontests/test_client_regress/models.py b/tests/regressiontests/test_client_regress/models.py
index b1e5bc4..d369a21 100644
--- a/tests/regressiontests/test_client_regress/models.py
+++ b/tests/regressiontests/test_client_regress/models.py
@@ -899,6 +899,22 @@ class UnicodePayloadTests(TestCase):
                                     content_type="application/json; charset=koi8-r")
         self.assertEqual(response.content, json.encode('koi8-r'))
 
+class BacktrackingResolveTests(TestCase):
+    def test_capture(self):
+        response = self.client.get("/test_client_regress/capture-foo")
+        self.assertEqual(response.content, "Success for backtracking_resolve_dynamic_capture: capture-foo")
+
+        response = self.client.get("/test_client_regress/bar-capture")
+        self.assertEqual(response.content, "Success for backtracking_resolve_dynamic_capture: bar-capture")
+
+    def test_redirect(self):
+        response = self.client.get("/test_client_regress/redirect-bar")
+        self.assertRedirects(response, "/test_client_regress/arg_view/test/", status_code=302, target_status_code=200)
+
+    def test_failed_capture(self):
+        response = self.client.get("/test_client_regress/redirect-foo")
+        self.assertEqual(response.status_code, 404)
+
 class DummyFile(object):
     def __init__(self, filename):
         self.name = filename
diff --git a/tests/regressiontests/test_client_regress/urls.py b/tests/regressiontests/test_client_regress/urls.py
index 5590c23..996fe76 100644
--- a/tests/regressiontests/test_client_regress/urls.py
+++ b/tests/regressiontests/test_client_regress/urls.py
@@ -7,6 +7,7 @@ from . import views
 
 
 urlpatterns = patterns('',
+    (r'^(?P<data>.*)$', views.backtracking_resolve_dynamic_capture),
     (r'^no_template_view/$', views.no_template_view),
     (r'^staff_only/$', views.staff_only_view),
     (r'^get_view/$', views.get_view),
@@ -20,6 +21,7 @@ urlpatterns = patterns('',
     (r'^redirect_to_non_existent_view/$', RedirectView.as_view(url='/test_client_regress/non_existent_view/')),
     (r'^redirect_to_non_existent_view2/$', RedirectView.as_view(url='/test_client_regress/redirect_to_non_existent_view/')),
     (r'^redirect_to_self/$', RedirectView.as_view(url='/test_client_regress/redirect_to_self/')),
+    (r'^(?P<data>.*)$', views.backtracking_resolve_dynamic_redirect),
     (r'^circular_redirect_1/$', RedirectView.as_view(url='/test_client_regress/circular_redirect_2/')),
     (r'^circular_redirect_2/$', RedirectView.as_view(url='/test_client_regress/circular_redirect_3/')),
     (r'^circular_redirect_3/$', RedirectView.as_view(url='/test_client_regress/circular_redirect_1/')),
diff --git a/tests/regressiontests/test_client_regress/views.py b/tests/regressiontests/test_client_regress/views.py
index b398293..6260305 100644
--- a/tests/regressiontests/test_client_regress/views.py
+++ b/tests/regressiontests/test_client_regress/views.py
@@ -1,5 +1,6 @@
 from django.conf import settings
 from django.contrib.auth.decorators import login_required
+from django.core.urlresolvers import ContinueResolving, reverse
 from django.http import HttpResponse, HttpResponseRedirect
 from django.core.exceptions import SuspiciousOperation
 from django.shortcuts import render_to_response
@@ -9,6 +10,17 @@ from django.core.serializers.json import DjangoJSONEncoder
 from django.test.client import CONTENT_TYPE_RE
 from django.template import RequestContext
 
+
+def backtracking_resolve_dynamic_capture(request, data):
+    if data in ('capture-foo', 'bar-capture',):
+        return HttpResponse("Success for backtracking_resolve_dynamic_capture: %s" % data)
+    raise ContinueResolving
+
+def backtracking_resolve_dynamic_redirect(request, data):
+    if data in ('redirect-bar', 'baz-redirect',):
+        return HttpResponseRedirect(reverse('arg_view', kwargs={'name': 'test'}))
+    raise ContinueResolving
+
 def no_template_view(request):
     "A simple view that expects a GET request, and returns a rendered template"
     return HttpResponse("No template used. Sample content: twice once twice. Content ends.")
diff --git a/tests/regressiontests/urlpatterns_reverse/backtracking_urls.py b/tests/regressiontests/urlpatterns_reverse/backtracking_urls.py
new file mode 100644
index 0000000..9dc468c
--- /dev/null
+++ b/tests/regressiontests/urlpatterns_reverse/backtracking_urls.py
@@ -0,0 +1,7 @@
+from django.conf.urls.defaults import *
+from views import continue_resolving_view, backtracking_view
+
+urlpatterns = patterns('',
+    url(r'', continue_resolving_view, name='continue_resolving_view'),
+    url(r'^backtrack/$', backtracking_view, name='backtracking_view'),
+)
\ No newline at end of file
diff --git a/tests/regressiontests/urlpatterns_reverse/tests.py b/tests/regressiontests/urlpatterns_reverse/tests.py
index 307d8da..bbb1cf4 100644
--- a/tests/regressiontests/urlpatterns_reverse/tests.py
+++ b/tests/regressiontests/urlpatterns_reverse/tests.py
@@ -5,15 +5,16 @@ from __future__ import absolute_import
 
 from django.conf import settings
 from django.core.exceptions import ImproperlyConfigured, ViewDoesNotExist
-from django.core.urlresolvers import (reverse, resolve, NoReverseMatch,
-    Resolver404, ResolverMatch, RegexURLResolver, RegexURLPattern)
+from django.core.urlresolvers import (backtracking_resolve, reverse, resolve,
+    NoReverseMatch, Resolver404, ResolverMatch, RegexURLResolver,
+    RegexURLPattern)
 from django.http import HttpResponseRedirect, HttpResponsePermanentRedirect
 from django.shortcuts import redirect
 from django.test import TestCase
 from django.utils import unittest
 from django.contrib.auth.models import User
 
-from . import urlconf_outer, urlconf_inner, middleware, views
+from . import urlconf_outer, middleware, views
 
 
 resolve_test_data = (
@@ -164,6 +165,24 @@ class URLPatternReverse(TestCase):
         # Reversing None should raise an error, not return the last un-named view.
         self.assertRaises(NoReverseMatch, reverse, None)
 
+class BacktrackingUrlTests(TestCase):
+    urls = 'regressiontests.urlpatterns_reverse.backtracking_urls'
+
+    def test_backtracking_normal_reverse(self):
+        self.assertEqual(reverse('backtracking_view'), '/backtrack/')
+
+    def test_backtracking_normal_resolve(self):
+        r = backtracking_resolve('/backtrack/')
+        first = r.next()
+        self.assertEqual(first.func.__name__, 'continue_resolving_view')
+        second = r.next()
+        self.assertEqual(second.func.__name__, 'backtracking_view')
+        self.assertRaises(Resolver404, r.next)
+
+        response = self.client.get('/backtrack/')
+        self.assertEqual(response.status_code, 200)
+        self.assertEqual(response.content, 'backtracked ok')
+
 class ResolverTests(unittest.TestCase):
     def test_non_regex(self):
         """
diff --git a/tests/regressiontests/urlpatterns_reverse/views.py b/tests/regressiontests/urlpatterns_reverse/views.py
index f631acf..2bb4c45 100644
--- a/tests/regressiontests/urlpatterns_reverse/views.py
+++ b/tests/regressiontests/urlpatterns_reverse/views.py
@@ -1,3 +1,4 @@
+from django.core.urlresolvers import ContinueResolving
 from django.http import HttpResponse
 from django.views.generic import RedirectView
 from django.core.urlresolvers import reverse_lazy
@@ -13,6 +14,12 @@ def kwargs_view(request, arg1=1, arg2=2):
 def absolute_kwargs_view(request, arg1=1, arg2=2):
     return HttpResponse('')
 
+def continue_resolving_view(request, *args, **kwargs):
+    raise ContinueResolving
+
+def backtracking_view(request, *args, **kwargs):
+    return HttpResponse('backtracked ok')
+
 def defaults_view(request, arg1, arg2):
     pass
 
