Ticket #2407: CGI.py

File CGI.py, 8.0 KB (added by Martin, 9 years ago)

The CGI Handler classes

Line 
1#-*- coding: iso-8859-1 -*-
2# Copyright (C) 2006 Martin Glueck. All rights reserved
3# 351 Bienterra Trail, #2, Rockford, IL, 61107, martin.glueck@insightbb.com
4# ****************************************************************************
5#
6# This library is free software; you can redistribute it and/or
7# modify it under the terms of the GNU Library General Public
8# License as published by the Free Software Foundation; either
9# version 2 of the License, or (at your option) any later version.
10#
11# This library is distributed in the hope that it will be useful,
12# but WITHOUT ANY WARRANTY; without even the implied warranty of
13# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14# Library General Public License for more details.
15#
16# You should have received a copy of the GNU Library General Public
17# License along with this library; if not, write to the Free
18# Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
19# ****************************************************************************
20#
21#++
22# Name
23#    django.core.handlers.CGI
24#
25# Purpose
26#    A CGI Handler for Django
27#
28# Revision Dates
29#    14-Jul-2006 (MG) Creation
30#    ««revision-date»»···
31#--
32
33import django
34import sys
35from   django                       import http
36from   django.core.handlers.base    import BaseHandler
37from   django.core                  import signals
38from   django.dispatch              import dispatcher
39from   django.utils                 import datastructures
40
41__all__          = ["CGI_Handler"]
42
43# See http://www.w3.org/Protocols/rfc2616/rfc2616-sec10.html
44STATUS_CODE_TEXT = \
45    { 100 : "CONTINUE"
46    , 101 : "SWITCHING PROTOCOLS"
47    , 200 : "OK"
48    , 201 : "CREATED"
49    , 202 : "ACCEPTED"
50    , 203 : "NON-AUTHORITATIVE INFORMATION"
51    , 204 : "NO CONTENT"
52    , 205 : "RESET CONTENT"
53    , 206 : "PARTIAL CONTENT"
54    , 300 : "MULTIPLE CHOICES"
55    , 301 : "MOVED PERMANENTLY"
56    , 302 : "FOUND"
57    , 303 : "SEE OTHER"
58    , 304 : "NOT MODIFIED"
59    , 305 : "USE PROXY"
60    , 306 : "RESERVED"
61    , 307 : "TEMPORARY REDIRECT"
62    , 400 : "BAD REQUEST"
63    , 401 : "UNAUTHORIZED"
64    , 402 : "PAYMENT REQUIRED"
65    , 403 : "FORBIDDEN"
66    , 404 : "NOT FOUND"
67    , 405 : "METHOD NOT ALLOWED"
68    , 406 : "NOT ACCEPTABLE"
69    , 407 : "PROXY AUTHENTICATION REQUIRED"
70    , 408 : "REQUEST TIMEOUT"
71    , 409 : "CONFLICT"
72    , 410 : "GONE"
73    , 411 : "LENGTH REQUIRED"
74    , 412 : "PRECONDITION FAILED"
75    , 413 : "REQUEST ENTITY TOO LARGE"
76    , 414 : "REQUEST-URI TOO LONG"
77    , 415 : "UNSUPPORTED MEDIA TYPE"
78    , 416 : "REQUESTED RANGE NOT SATISFIABLE"
79    , 417 : "EXPECTATION FAILED"
80    , 500 : "INTERNAL SERVER ERROR"
81    , 501 : "NOT IMPLEMENTED"
82    , 502 : "BAD GATEWAY"
83    , 503 : "SERVICE UNAVAILABLE"
84    , 504 : "GATEWAY TIMEOUT"
85    , 505 : "HTTP VERSION NOT SUPPORTED"
86    }
87
88class CGI_Request (http.HttpRequest) :
89    """A Request from a normal CGI interface."""
90
91    _request                = None
92    _get                    = None
93    _post                   = None
94    _cookies                = None
95    _files                  = None
96
97    def __init__ (self, environ) :
98        ### don't chain up, we set the dict's here as properties
99        ### super (CGI_Request, self).__init__ (self, environ)
100        self.environ   = environ
101        self.path      = environ.get ("REDIRECT_URL", "/")
102        self.META      = environ
103        self.method    = environ.get ("REQUEST_METHOD", "GET").upper()
104    # end def __init__
105
106    def __repr__(self):
107        return "\n".join \
108            ( ( "<%s" % (self.__class__.__name__)
109              , "  GET:  %r"    % (self.GET)
110              , "  POST: %r"    % (self.POST)
111              , "  COOKIES: %r" % (self.COOKIES)
112              , "  META: %r"    % (self.META)
113              , ">"
114              )
115            )
116    # end def __repr__
117
118    def get_full_path(self):
119        return '%s%s' % \
120            ( self.path
121            ,            self.environ.get ("QUERY_STRING", "")
122              and ("?" + self.environ     ["QUERY_STRING"])
123              or ''
124            )
125    # end def get_full_path
126
127    def _load_post_and_files(self):
128        # Populates self._post and self._files
129        if self.method == "POST" :
130            if self.environ.get ("CONTENT_TYPE", "").startswith ("multipart") :
131                header_dict = dict\
132                    ( [ (k, v) for k, v in self.environ.iteritems ()
133                                 if k.startswith('HTTP_')
134                      ]
135                    )
136                header_dict ["Content-Type"] = self.environ.get \
137                    ("CONTENT_TYPE", "")
138                (self._post, self._files
139                ) = http.parse_file_upload (header_dict, self.raw_post_data)
140            else :
141                self._post  = http.QueryDict (self.raw_post_data)
142                self._files = datastructures.MultiValueDict ()
143        else:
144            self._post  = http.QueryDict                ("")
145            self._files = datastructures.MultiValueDict ()
146    # end def _load_post_and_files
147
148    def _get_request(self):
149        if self._request is None :
150            self._request = datastructures.MergeDict (self.POST, self.GET)
151        return self._request
152    # end def _get_request
153
154    def _get_get(self):
155        if self._get is None :
156            self._get = http.QueryDict (self.environ.get ("QUERY_STRING", ""))
157        return self._get
158    # end def _get_get
159
160    def _set_get(self, get) :
161        self._get = get
162    # end def _set_get
163
164    def _get_post(self):
165        if self._post is None:
166            self._load_post_and_files ()
167        return self._post
168    # end def _get_post
169
170    def _set_post(self, post):
171        self._post = post
172    # end def _set_post
173
174    def _get_cookies(self):
175        if self._cookies is None :
176            self._cookies = http.parse_cookie \
177                (self.environ.get ("HTTP_COOKIE", ""))
178        return self._cookies
179    # end def _get_cookies
180
181    def _set_cookies(self, cookies):
182        self._cookies = cookies
183    # end def _set_cookies
184
185    def _get_files(self):
186        if self._files is None :
187            self._load_post_and_files ()
188        return self._files
189    # end def _get_files
190
191    def _get_raw_post_data(self):
192        try:
193            return self._raw_post_data
194        except AttributeError:
195            self._raw_post_data = sys.stdin.read \
196                (int (self.environ ["CONTENT_LENGTH"]))
197            return self._raw_post_data
198    # end def _get_raw_post_data
199
200    GET           = property (_get_get,     _set_get)
201    POST          = property (_get_post,    _set_post)
202    COOKIES       = property (_get_cookies, _set_cookies)
203    FILES         = property (_get_files)
204    REQUEST       = property (_get_request)
205    raw_post_data = property (_get_raw_post_data)
206
207# end class CGI_Request
208
209class CGI_Handler (BaseHandler) :
210    """The handler for a CGI request."""
211
212    def __call__ (self, environ, start_response) :
213        from django.conf import settings
214
215        # Set up middleware if needed. We couldn't do this earlier, because
216        # settings weren't available.
217        if self._request_middleware is None:
218            self.load_middleware ()
219
220        dispatcher.send (signal = signals.request_started)
221        try:
222            request  = CGI_Request       (environ)
223            response = self.get_response (request.path, request)
224            # Apply response middleware
225            for middleware_method in self._response_middleware:
226                response = middleware_method (request, response)
227        finally:
228            dispatcher.send (signal = signals.request_finished)
229
230        status_text = STATUS_CODE_TEXT.get \
231            (response.status_code, "UNKNOWN STATUS CODE")
232        status           = '%s %s' % (response.status_code, status_text)
233        response_headers = response.headers.items ()
234        for c in response.cookies.values ():
235            response_headers.append (('Set-Cookie', c.output(header='')))
236        start_response (status, response_headers)
237        return response.iterator
238    # end def __call__
239
240# end class CGI_Handler
241
242
243### __END__ django.core.handerls.CGI
Back to Top