~ubuntu-branches/ubuntu/natty/moin/natty-updates

« back to all changes in this revision

Viewing changes to MoinMoin/request/request_modpython.py

  • Committer: Bazaar Package Importer
  • Author(s): Jonas Smedegaard
  • Date: 2008-06-22 21:17:13 UTC
  • mto: This revision was merged to the branch mainline in revision 18.
  • Revision ID: james.westby@ubuntu.com-20080622211713-inlv5k4eifxckelr
ImportĀ upstreamĀ versionĀ 1.7.0

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
# -*- coding: iso-8859-1 -*-
 
2
"""
 
3
    MoinMoin - mod_python Request Implementation for Apache and mod_python.
 
4
 
 
5
    @copyright: 2001-2003 Juergen Hermann <jh@web.de>,
 
6
                2003-2006 MoinMoin:ThomasWaldmann
 
7
    @license: GNU GPL, see COPYING for details.
 
8
"""
 
9
from MoinMoin import log
 
10
logging = log.getLogger(__name__)
 
11
 
 
12
from MoinMoin import wikiutil
 
13
from MoinMoin.request import RequestBase, RemoteClosedConnection
 
14
 
 
15
class Request(RequestBase):
 
16
    """ specialized on mod_python requests """
 
17
 
 
18
    def __init__(self, req, properties={}):
 
19
        """ Saves mod_pythons request and sets basic variables using
 
20
            the req.subprocess_env, cause this provides a standard
 
21
            way to access the values we need here.
 
22
 
 
23
            @param req: the mod_python request instance
 
24
        """
 
25
        try:
 
26
            # flags if headers sent out contained content-type or status
 
27
            self._have_ct = 0
 
28
            self._have_status = 0
 
29
 
 
30
            req.add_common_vars()
 
31
            self.mpyreq = req
 
32
            # some mod_python 2.7.X has no get method for table objects,
 
33
            # so we make a real dict out of it first.
 
34
            if not hasattr(req.subprocess_env, 'get'):
 
35
                env = dict(req.subprocess_env)
 
36
            else:
 
37
                env = req.subprocess_env
 
38
            self._setup_vars_from_std_env(env)
 
39
            RequestBase.__init__(self, properties)
 
40
 
 
41
        except Exception, err:
 
42
            self.fail(err)
 
43
 
 
44
    def fixURI(self, env):
 
45
        """ Fix problems with script_name and path_info using
 
46
        PythonOption directive to rewrite URI.
 
47
 
 
48
        This is needed when using Apache 1 or other server which does
 
49
        not support adding custom headers per request. With mod_python we
 
50
        can use the PythonOption directive:
 
51
 
 
52
            <Location /url/to/mywiki/>
 
53
                PythonOption X-Moin-Location /url/to/mywiki/
 
54
            </location>
 
55
 
 
56
        Note that *neither* script_name *nor* path_info can be trusted
 
57
        when Moin is invoked as a mod_python handler with apache1, so we
 
58
        must build both using request_uri and the provided PythonOption.
 
59
        """
 
60
        # Be compatible with release 1.3.5 "Location" option
 
61
        # TODO: Remove in later release, we should have one option only.
 
62
        old_location = 'Location'
 
63
        options_table = self.mpyreq.get_options()
 
64
        if not hasattr(options_table, 'get'):
 
65
            options = dict(options_table)
 
66
        else:
 
67
            options = options_table
 
68
        location = options.get(self.moin_location) or options.get(old_location)
 
69
        if location:
 
70
            env[self.moin_location] = location
 
71
            # Try to recreate script_name and path_info from request_uri.
 
72
            import urlparse
 
73
            scriptAndPath = urlparse.urlparse(self.request_uri)[2]
 
74
            self.script_name = location.rstrip('/')
 
75
            path = scriptAndPath.replace(self.script_name, '', 1)
 
76
            self.path_info = wikiutil.url_unquote(path, want_unicode=False)
 
77
 
 
78
        RequestBase.fixURI(self, env)
 
79
 
 
80
    def _setup_args_from_cgi_form(self):
 
81
        """ Override to use mod_python.util.FieldStorage
 
82
 
 
83
        It's little different from cgi.FieldStorage, so we need to
 
84
        duplicate the conversion code.
 
85
        """
 
86
        from mod_python import util
 
87
        form = util.FieldStorage(self.mpyreq, keep_blank_values=1) # by default this evaluates query string AND body POST data!
 
88
 
 
89
        args = {}
 
90
 
 
91
        # You cannot get rid of .keys() here
 
92
        for key in form.keys():
 
93
            if key is None:
 
94
                continue
 
95
            values = form[key]
 
96
            if not isinstance(values, list):
 
97
                values = [values]
 
98
            fixedResult = []
 
99
            for item in values:
 
100
                if isinstance(item, util.StringField):
 
101
                    fixedResult.append(item.value)
 
102
                elif isinstance(item, util.Field) and item.filename:
 
103
                    fixedResult.append(item.file)
 
104
                    # Remember filenames with a name hack
 
105
                    args[key + '__filename__'] = item.filename
 
106
                elif isinstance(item, str):
 
107
                    # mod_python 2.7 might return strings instead of Field objects.
 
108
                    fixedResult.append(item)
 
109
            args[key] = fixedResult
 
110
 
 
111
        return self.decodeArgs(args)
 
112
 
 
113
    def run(self, req):
 
114
        """ mod_python calls this with its request object. We don't
 
115
            need it cause its already passed to __init__. So ignore
 
116
            it and just return RequestBase.run.
 
117
 
 
118
            @param req: the mod_python request instance
 
119
        """
 
120
        return RequestBase.run(self)
 
121
 
 
122
    def read(self, n):
 
123
        """ Read from input stream. """
 
124
        if n is None:
 
125
            logging.warning("calling request.read(None) might block")
 
126
            return self.mpyreq.read()
 
127
        else:
 
128
            return self.mpyreq.read(n)
 
129
 
 
130
    def write(self, *data):
 
131
        """ Write to output stream. """
 
132
        data = self.encode(data)
 
133
        try:
 
134
            self.mpyreq.write(data)
 
135
        except Exception:
 
136
            raise RemoteClosedConnection()
 
137
 
 
138
    def flush(self):
 
139
        """ We can't flush it, so do nothing. """
 
140
        pass
 
141
 
 
142
    def finish(self):
 
143
        """ Just return apache.OK. Status is set in req.status. """
 
144
        RequestBase.finish(self)
 
145
        # is it possible that we need to return something else here?
 
146
        from mod_python import apache
 
147
        return apache.OK
 
148
 
 
149
    def _emit_http_headers(self, headers):
 
150
        """ private method to send out preprocessed list of HTTP headers """
 
151
        st_header, ct_header, other_headers = headers[0], headers[1], headers[2:]
 
152
        status = st_header.split(':', 1)[1].lstrip()
 
153
        self.mpyreq.status = int(status.split(' ', 1)[0])
 
154
        self.mpyreq.content_type = ct_header.split(':', 1)[1].lstrip()
 
155
        for header in other_headers:
 
156
            key, value = header.split(':', 1)
 
157
            value = value.lstrip()
 
158
            self.mpyreq.headers_out[key] = value
 
159
        # this is for mod_python 2.7.X, for 3.X it's a NOP
 
160
        self.mpyreq.send_http_header()
 
161