News

[17/Sep/2009:19:20] Release 0.5 includes Open Flash Chart support.

[01/Jul/2009:10:50] Repoze.who authentication tutorial added

[22/Jun/2009:11:36] AJAX calculator tutorial added.

[01/May/2009:14:15] MVC/SQL based wiki tutorial added.



Contact Email:



view source
W1200_1300.
applicationAPI.
whiff



Download instructions
at whiff.sourceforge.net
project page
.
WHIFF DOCUMENTION

Application/Middleware API

Whiff provides a application programmers interface (API) for building applications using Python modules.

Contents:
Application/Middleware boilerplates
CGI parameter parsing and retrieval
Getting environment parameters by relativized names
Locating and calling a template/application by URL
Parse and format JSON data
Evaluate a parameter
Delegate to a parameter
Delegate to a URL
Getting and Putting WHIFF registered resources

Application/Middleware boilerplates

The WHIFF infrastructure provides application programming support for building WSGI applications and middlewares.

When WHIFF selects a module to respond to a request WHIFF looks for a function in the module named __wsgi__ or a class (constructor callable) in the module named __middleware__. WHIFF will not automatically directly use other entries in the module as a security precaution.

For the purposes of this discussion we will distinguish two two main categories of applications: generators create response to a web request themself, and delegators which delegate the generation of the web response to another application, usually after modifying the execution environment or configuring the other application. A couple examples taken from the standard middleware directory will illustrate the difference between generators and delegators, as well as provide example of most of the API functionality offered by WHIFF to Python based WSGI applications.

The standard middleware DebugDump is a generator which dumps the application environment dictionary as the response to the web request.

# content of whiff/middleware/debugDump.py

from whiff.middleware import misc
from whiff import resolver
from whiff.rdjson import jsonParse
from whiff.middleware import quoteHtml

class dump(misc.utility):
    "dump out the environment as text/plain with html special characters quoted"
    def __init__(self,
                 parse_cgi = True,
                 content_type='text/plain'):
        self.content_type = content_type
        self.parse_cgi = parse_cgi
    def __call__(self, env, start_response):
	# determine the content type desired for the reply
        content_type = self.param_value(self.content_type, env)
	# determine whether to parse the CGI parameters
        parse_cgi = self.param_json(self.parse_cgi, env)
        if parse_cgi:
	    # parse CGI parameters, as requested
            env = resolver.process_cgi(env, parse_cgi=True)
	# format the env dictionary as a JSON string representation
        json_env = jsonParse.format(env)
	# "quote" HTML special characters
        quoted_json = resolver.quote(json_env)
	# start the response
        start_response("200 OK", [('Content-Type', content_type)])
	# deliver the response
        return [quoted_json]

__middleware__ = dump
debugDump is built to a code pattern common to many generator implementations, which looks something like this
from whiff.middleware import misc
... MORE IMPORTS ...

class APPLICATION(misc.utility):

    def __init__(self,
		...APPLICATION PARAMETERS...
		):
	...RECORD THE PARAMETERS FOR FUTURE USE..

    def __call__(self, env, start_response):
	...COMPUTE THE RESPONSE TO THE REQUEST...
        start_response("200 OK", [('Content-Type', CONTENT_TYPE FOR REQUEST)])
        return RESPONSE ITERABLE

__middleware__ = APPLICATION
Above APPLICATION inherits from the whiff.middleware.misc.utility abstract superclass because the superclass provides valuable conveniences. For example the debugDump application uses the param_value, param_json and deliver_page methods inherited from the whiff.middleware.misc.utility superclass.

Note also that the assignment

__middleware__ = APPLICATION
is required to identify the application intended to respond to HTTP requests on behalf of this module.

The main difference between a generator like DebugDump and a delegator like ifVisible, shown below, is that a generator starts the response, decides the content type of the response and explicitly returns the response iterable (which should be a sequence of string values).

IfVisible does not start the response, nor decide the content type, nor explicitly create the response, but delegates all of those responsibilities to one of its parameters, either page or elsePage depending on whether testPage evaluates to whitespace or not.

# content of whiff/middleware/ifVisible.py

"""
Simple conditional based on page value: test if all white or not
"""

from whiff.middleware import misc

class ifVisible(misc.utility):
    def __init__(self,
                 testPage,
                 page,
                 elsePage="", # page to deliver if testpage is all white
                 ):
        self.testPage = testPage
        self.page = page
        self.elsePage = elsePage

    def __call__(self, env, start_response):
        test = self.param_value(self.testPage, env).strip() 
        if test:
            return self.deliver_page(self.page, env, start_response)
        else:
            return self.deliver_page(self.elsePage, env, start_response)

__middleware__ = ifVisible
The above follows the outline common to many delegator applications:
from whiff.middleware import misc

class APPLICATION(misc.utility):

    def __init__(self,
		OTHER PARAMETERS...
                 ):
	...STORE OTHER PARAMETERS FOR FUTURE USE...

    def __call__(self, env, start_response):
	...DECIDE HOW TO DELEGATE THE RESPONSE...
	...AND POSSIBLY CHANGE THE ENVIRONMENT...
        return self.deliver_page(OTHER APPLICATION, env, start_response)

__middleware__ = APPLICATION
If you feel the need to implement a middleware or application, it will most likely fit into either the generator or delegator category and one of the above boilerplates will get you started.

The following sections describe the WHIFF services which may help you fill in the boilerplate.

CGI parameter parsing and retrieval

CGI parameters are values usually sent from a form submitted by a web page. These values are encoded in strings either in the HTTP header or the body of the HTTP request.

The WHIFF utility function

new_env = whiff.resolver.process_cgi(env, parse_cgi=True)
parses CGI parameters from either the header or the body and puts the name/value pairs found into a dictionary in the returned environment (the input environment is not changed to avoid unwanted side effects).

Once CGI parameters have been parsed and stored as a dictionary in the environment the utility function

value = whiff.whiffenv.cgiGet(env, variable_name)
extracts the value associated with the CGI parameter associated with the variable_name.

If you want to use CGI parameters that may have multiple values you will need to directly use the argument dictionary stored in the environment new_env[whiffenv.CGI_DICTIONARY] which stores a mapping of variable names to lists of values.

Both the above methods will automatically reflect any CGI prefix in effect in order to allow relative naming for page fragments. For example if the CGI prefix in the environment is "myPrefix" then whiff.whiffenv.cgiGet(env, "MyVariable") will get the value associated with the globally submitted CGI parameter named myPrefixMyVariable.

To access the dictionary of all CGI parameters and values, ignoring any CGI prefix which may be in effect, use the dictionary new_env[whiffenv.TOP_CGI_DICTIONARY] (in most cases this is not needed and not a good idea).

In order to make it easy for WHIFF applications to avoid "javascript injection attacks" and other security problems WHIFF delivers the CGI parameters in HTML-quoted form. So if the user typed the value

<script> alert("Purple dinosour"); </script>
the CGI value delivered by WHIFF replaces the angle brackets with HTML entities
&lt;script&gt; alert(&quot;Purple dinosour&quot;); &lt;/script&gt;
To unquote the quoted cgi value in Python code use the whiff.resolver.unquote function
>>> resolver.unquote('&lt;script&gt; alert(&quot;Purple dinosour&quot;); &lt;/script&gt;')
'<script> alert("Purple dinosour"); </script>'

Getting environment parameters by relativized names

Your WSGI application has direct access to its environment dictionary env and can directly access any information in the dictionary. If a CGI prefix is in effect it may be useful for the application to see only the parameters matching the CGI prefix.

To find the absolute name associated with a relative Name use the utility function

absolute_Name = whiff.whiffenv.getName(env, Name)
(This is the Python analogue of the {{id Name/}} configuration directive).

To find the value associated with a relative Name use the utility function

Value = whiff.whiffenv.getId(env, Name)
(This is the Python analogue of the {{get-id Name/}} configuration directive.)

To add a value to the environment by relative Name use

whiff.whiffenv.setId(env, Name, Value)

Locating and calling a template/application by URL

Sometimes it is useful to locate an application managed by WHIFF using its relative URL. The standard middleware callTemplate is designed to provide this functionality
application = whiff.middleware.callTemplate.callTemplate("url/to/application")
The application returned by callTemplate must be called as a WSGI application to get the response from the application, for example as in
return application(env, start_response)
This functionality is somewhat analogous to the {{include ...}} configuration directive.

Parse and format JSON data

When a parameter to an application is expected to produce JSON data, the parameter may be evaluated and converted into the analogous Python data structure using the inherited method:
data = self.param_json(parameter, env)
This method is useful both for sending simple values such as true or 100 to an application and for sending complex values such as sequences of mappings.

To convert a Python data structure which is compatible with JSON data restrictions to a JSON representation use the utility function

stringRepresentation = whiff.rdjson.jsonParse.format(dataStructure)

Evaluate a parameter

To load a unicode compatible text response from a WSGI application parameter use the inherited method
unicodeStringResponse = self.param_value(parameter, env)
This method is used, for example, by the quoteHTML middleware to obtain the value of its parameter before transforming the value by quoting HTML special characters. In the event that the parameter is expected to be a binary value such as a PNG image use the param_binary method
binary8bitString = self.param_binary(parameter, env)

Delegate to a parameter

To return the response of another application as the response to the request use the inherited method deliver_page like this:
return self.deliver_page(other_application, env, start_response)
The deliver_page method collaborates with the other misc.utility methods to make sure that all headers produced by components are included in the response. In addition, deliver_page permits the other_application to be a simple string. For example one way to implement the "hello world" WSGI application in WHIFF is:
from whiff.middleware import misc

class hello(misc.utility):
    def __call__(self, env, start_response):
        return self.deliver_page("hello_world", env, start_response)

__middleware__ = hello
The deliver_page method takes care of the rest of the WSGI protocol automatically.

Delegate to a URL

Use the whiff.resolver.callUrl(url, env, start_response) function to delegate the response to an application located by an URL. For example the following application essentially performs an "internal redirect" to a authenticate/login page after modifying the environment.
from whiff import resolver

def __wsgi__(env, start_response):
    env = env.copy()
    env["greeting"] = "GREETINGS EARTHLING!"
    return resolver.callUrl("authenticate/login", env, start_response)
Please see the URL rewriting tutorial for a more advanced example usage of resolver.callUrl.

Getting and Putting WHIFF registered resources

The whiff.gateway module provides standard interfaces for WHIFF registered resources.
# get a resource (raise whiff.gateway.NoSuchResource if missing)
value = whiff.gateway.getResource(env, resourcePath)

# get a resource (use the defaultValue if missing)
value = whiff.gateway.getResource(env, resourcePath, defaultValue)

# put a resource
whiff.gateway.putResource(env, resourcePath, value)
Please see the Directory Configuration API guide and the Resource Concept document for further discussion of usage, configuration and deployment of WHIFF resources.
0 comments.
Care to comment?
name: (required)
- email (not published):
comment: (required)

<< security number? >>