Skip to content
This repository has been archived by the owner on Jan 8, 2020. It is now read-only.

Commit

Permalink
Merge branch 'redirects' into develop
Browse files Browse the repository at this point in the history
  • Loading branch information
waxlamp committed Jan 21, 2016
2 parents 4cf099a + 4a77f68 commit a008a81
Show file tree
Hide file tree
Showing 8 changed files with 108 additions and 4 deletions.
2 changes: 2 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,8 @@ versioning](http://semver.org).
- "Watch" plugin controls whether services and dependent modules are
automatically reloaded when they change
- ``tangelo.ensurePlugin()`` function that avoids JavaScript parsing problems
- Service functions ``tangelo.redirect()`` and ``tangelo.internal_redirect()``
to allow services to redirect to other resources

### Changed
- Documentation introduction is more focused; tutorials are more
Expand Down
38 changes: 38 additions & 0 deletions docs/tangelo-py.rst
Original file line number Diff line number Diff line change
Expand Up @@ -116,6 +116,44 @@ HTTP Interaction
if there is no such key. If `value` is given, it will become newly associated
to `key`.

.. py:function:: tangelo.redirect(path[, status_code])
Used to signal the browser that a web service wants to perform an HTTP
redirect to a different `path`. The optional `status_code` should be a value
in the ``3xx`` range indicating the type of redirect desired; it defaults to
``303``.

In the following example service,

.. code:: python
import tangelo
def run():
return tangelo.redirect("other/path/content.html")
Tangelo will direct the client to the URL shown, resulting in that file
being served instead of the service itself.

.. py:function:: tangelo.internal_redirect(path)
Used to signal the server to serve content from a different path in place of
the current service; similar to :py:func:`tangelo.redirect()` but without
informing the client of the redirection.

The example above will look very similar using this function instead:

.. code:: python
import tangelo
def run():
return tangelo.internal_redirect("other/path/content.html")
When this internal redirection occurs, the browser's displayed URL, for
example, will not change to reflect the requested path.


Web Services Utilities
======================

Expand Down
19 changes: 19 additions & 0 deletions tangelo/tangelo/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,25 @@ def http_status(code, message=None):
cherrypy.response.status = "%s%s" % (code, " %s" % (message) if message is not None else "")


class _Redirect(object):
def __init__(self, path, status):
self.path = path
self.status = status


def redirect(path, status=303):
return _Redirect(path, status)


class _InternalRedirect(object):
def __init__(self, path):
self.path = path


def internal_redirect(path):
return _InternalRedirect(path)


def log(section, message=None, color=None, lvl=logging.INFO):
if message is None:
message = section
Expand Down
15 changes: 11 additions & 4 deletions tangelo/tangelo/server.py
Original file line number Diff line number Diff line change
Expand Up @@ -472,10 +472,17 @@ def invoke_service(self, module, *pargs, **kwargs):
# Restore the CWD to what it was before the service invocation.
os.chdir(save_cwd)

# If the result is not a string, attempt to convert it to one via JSON
# serialization. This allows services to return a Python object if they
# wish, or to perform custom serialization (such as for MongoDB results,
# etc.).
# If the result is a redirect request, then convert it to the
# appropriate CherryPy logic and continue.
#
# Otherwise, if the result is not a string, attempt to convert it to one
# via JSON serialization. This allows services to return a Python
# object if they wish, or to perform custom serialization (such as for
# MongoDB results, etc.).
if isinstance(result, tangelo._Redirect):
raise cherrypy.HTTPRedirect(result.path, result.status)
elif isinstance(result, tangelo._InternalRedirect):
raise cherrypy.InternalRedirect(result.path)
if not isinstance(result, types.StringTypes):
try:
result = json.dumps(result)
Expand Down
27 changes: 27 additions & 0 deletions tests/redirection.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
import nose
import requests

import fixture


@nose.with_setup(fixture.start_tangelo, fixture.stop_tangelo)
def test_redirect():
r = requests.get(fixture.url("redirect/redirect"), allow_redirects=False)
assert r.ok
assert r.status_code == 303
assert r.text.startswith("This resource can be found at")

r = requests.get(fixture.url("redirect/redirect"))
assert r.ok
assert r.status_code == 200
assert r.text == "hello, world\n"

r = requests.get(fixture.url("redirect/internal_redirect"), allow_redirects=False)
assert r.ok
assert r.status_code == 200
assert r.text == "hello, world\n"

r = requests.get(fixture.url("redirect/internal_redirect"))
assert r.ok
assert r.status_code == 200
assert r.text == "hello, world\n"
1 change: 1 addition & 0 deletions tests/web/redirect/content.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
hello, world
5 changes: 5 additions & 0 deletions tests/web/redirect/internal_redirect.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
import tangelo


def run():
return tangelo.internal_redirect("content.txt")
5 changes: 5 additions & 0 deletions tests/web/redirect/redirect.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
import tangelo


def run():
return tangelo.redirect("content.txt")

0 comments on commit a008a81

Please sign in to comment.