Django

Code

Ticket #2407: CGI.py

File CGI.py, 8.0 kB (added by Martin, 2 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
33 import django
34 import sys
35 from   django                       import http
36 from   django.core.handlers.base    import BaseHandler
37 from   django.core                  import signals
38 from   django.dispatch              import dispatcher
39 from   django.utils                 import datastructures
40
41 __all__          = ["CGI_Handler"]
42
43 # See http://www.w3.org/Protocols/rfc2616/rfc2616-sec10.html
44 STATUS_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
88 class 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
209 class 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