Merge lp:~ubuntu-branches/ubuntu/natty/mod-wsgi/natty-201104071155 into lp:ubuntu/natty/mod-wsgi
- Natty (11.04)
- natty-201104071155
- Merge into natty
Proposed by
James Westby
Status: | Rejected |
---|---|
Rejected by: | Colin Watson |
Proposed branch: | lp:~ubuntu-branches/ubuntu/natty/mod-wsgi/natty-201104071155 |
Merge into: | lp:ubuntu/natty/mod-wsgi |
Diff against target: |
15059 lines (+15019/-0) (has conflicts) 7 files modified
.pc/.quilt_patches (+1/-0) .pc/.quilt_series (+1/-0) .pc/.version (+1/-0) .pc/applied-patches (+1/-0) .pc/fix-python-3.2-lp-749720.patch/mod_wsgi.c (+14969/-0) debian/patches/fix-python-3.2-lp-749720.patch (+45/-0) debian/patches/series (+1/-0) Conflict adding file .pc. Moved existing file to .pc.moved. Conflict adding file debian/patches. Moved existing file to debian/patches.moved. |
To merge this branch: | bzr merge lp:~ubuntu-branches/ubuntu/natty/mod-wsgi/natty-201104071155 |
Related bugs: |
Reviewer | Review Type | Date Requested | Status |
---|---|---|---|
Dave Walker (community) | Disapprove | ||
Daniel Holbach (community) | Needs Fixing | ||
Ubuntu branches | Pending | ||
Review via email: mp+56743@code.launchpad.net |
Commit message
Description of the change
The package history in the archive and the history in the bzr branch differ. As the archive is authoritative the history of lp:ubuntu/natty/mod-wsgi now reflects that and the old bzr branch has been pushed to lp:~ubuntu-branches/ubuntu/natty/mod-wsgi/natty-201104071155. A merge should be performed if necessary.
To post a comment you must log in.
Revision history for this message
Daniel Holbach (dholbach) wrote : | # |
Revision history for this message
Daniel Holbach (dholbach) : | # |
review:
Needs Fixing
Revision history for this message
Dave Walker (davewalker) wrote : | # |
This is fallout from UDD vs Developer push to lp:ubuntu/* branch. Merge proposal contains same delta.
review:
Disapprove
Unmerged revisions
- 16. By James Page
-
* Updates to support python >= 3.2 (LP: #749720):
- Picked patch to support python >= 3.2 from upstream trunk.
- Fixed libapache2-mod-wsgi- py3.postinst to correctly detect
default python 3 version.
* Converted to source/format "3.0 (quilt)" and updated debhelper
version (>= 7.0.15).
Preview Diff
[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1 | === added directory '.pc' |
2 | === renamed directory '.pc' => '.pc.moved' |
3 | === added file '.pc/.quilt_patches' |
4 | --- .pc/.quilt_patches 1970-01-01 00:00:00 +0000 |
5 | +++ .pc/.quilt_patches 2011-04-07 12:02:22 +0000 |
6 | @@ -0,0 +1,1 @@ |
7 | +debian/patches |
8 | |
9 | === added file '.pc/.quilt_series' |
10 | --- .pc/.quilt_series 1970-01-01 00:00:00 +0000 |
11 | +++ .pc/.quilt_series 2011-04-07 12:02:22 +0000 |
12 | @@ -0,0 +1,1 @@ |
13 | +series |
14 | |
15 | === added file '.pc/.version' |
16 | --- .pc/.version 1970-01-01 00:00:00 +0000 |
17 | +++ .pc/.version 2011-04-07 12:02:22 +0000 |
18 | @@ -0,0 +1,1 @@ |
19 | +2 |
20 | |
21 | === added file '.pc/applied-patches' |
22 | --- .pc/applied-patches 1970-01-01 00:00:00 +0000 |
23 | +++ .pc/applied-patches 2011-04-07 12:02:22 +0000 |
24 | @@ -0,0 +1,1 @@ |
25 | +fix-python-3.2-lp-749720.patch |
26 | |
27 | === added directory '.pc/fix-python-3.2-lp-749720.patch' |
28 | === added file '.pc/fix-python-3.2-lp-749720.patch/.timestamp' |
29 | === added file '.pc/fix-python-3.2-lp-749720.patch/mod_wsgi.c' |
30 | --- .pc/fix-python-3.2-lp-749720.patch/mod_wsgi.c 1970-01-01 00:00:00 +0000 |
31 | +++ .pc/fix-python-3.2-lp-749720.patch/mod_wsgi.c 2011-04-07 12:02:22 +0000 |
32 | @@ -0,0 +1,14969 @@ |
33 | +/* vim: set sw=4 expandtab : */ |
34 | + |
35 | +/* |
36 | + * Copyright 2007-2010 GRAHAM DUMPLETON |
37 | + * |
38 | + * Licensed under the Apache License, Version 2.0 (the "License"); |
39 | + * you may not use this file except in compliance with the License. |
40 | + * You may obtain a copy of the License at |
41 | + * |
42 | + * http://www.apache.org/licenses/LICENSE-2.0 |
43 | + * |
44 | + * Unless required by applicable law or agreed to in writing, software |
45 | + * distributed under the License is distributed on an "AS IS" BASIS, |
46 | + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
47 | + * See the License for the specific language governing permissions and |
48 | + * limitations under the License. |
49 | + */ |
50 | + |
51 | +/* |
52 | + * Enabled access to Apache private API and data structures. Need to do |
53 | + * this to access the following: |
54 | + * |
55 | + * In Apache 1.3 it is not possible to access ap_check_cmd_context() |
56 | + * where as this was made public in Apache 2.0. |
57 | + * |
58 | + * In Apache 2.X need access to ap_create_request_config(). |
59 | + * |
60 | + * In Apache 2.X need access to core_module and core_request_config. |
61 | + * |
62 | + */ |
63 | + |
64 | +#define CORE_PRIVATE 1 |
65 | + |
66 | +#include "httpd.h" |
67 | + |
68 | +#if !defined(HTTPD_ROOT) |
69 | +#error Sorry, Apache developer package does not appear to be installed. |
70 | +#endif |
71 | + |
72 | +#if !defined(AP_SERVER_MAJORVERSION_NUMBER) |
73 | +#if AP_MODULE_MAGIC_AT_LEAST(20010224,0) |
74 | +#define AP_SERVER_MAJORVERSION_NUMBER 2 |
75 | +#define AP_SERVER_MINORVERSION_NUMBER 0 |
76 | +#define AP_SERVER_PATCHLEVEL_NUMBER 0 |
77 | +#else |
78 | +#define AP_SERVER_MAJORVERSION_NUMBER 1 |
79 | +#define AP_SERVER_MINORVERSION_NUMBER 3 |
80 | +#define AP_SERVER_PATCHLEVEL_NUMBER 0 |
81 | +#endif |
82 | +#endif |
83 | + |
84 | +#if !defined(AP_SERVER_BASEVERSION) |
85 | +#define AP_SERVER_BASEVERSION SERVER_BASEVERSION |
86 | +#endif |
87 | + |
88 | +#if AP_SERVER_MAJORVERSION_NUMBER < 2 |
89 | +typedef int apr_status_t; |
90 | +#define APR_SUCCESS 0 |
91 | +typedef pool apr_pool_t; |
92 | +typedef unsigned int apr_port_t; |
93 | +#include "ap_ctype.h" |
94 | +#include "ap_alloc.h" |
95 | +#define apr_isspace ap_isspace |
96 | +#define apr_table_make ap_make_table |
97 | +#define apr_table_get ap_table_get |
98 | +#define apr_table_set ap_table_set |
99 | +#define apr_table_setn ap_table_setn |
100 | +#define apr_table_add ap_table_add |
101 | +#define apr_table_elts ap_table_elts |
102 | +#define apr_array_make ap_make_array |
103 | +#define apr_array_push ap_push_array |
104 | +#define apr_array_cat ap_array_cat |
105 | +#define apr_array_append ap_append_arrays |
106 | +typedef array_header apr_array_header_t; |
107 | +typedef table apr_table_t; |
108 | +typedef table_entry apr_table_entry_t; |
109 | +typedef int apr_size_t; |
110 | +typedef unsigned long apr_off_t; |
111 | +#define apr_psprintf ap_psprintf |
112 | +#define apr_pstrndup ap_pstrndup |
113 | +#define apr_pstrdup ap_pstrdup |
114 | +#define apr_pstrcat ap_pstrcat |
115 | +#define apr_pcalloc ap_pcalloc |
116 | +#define apr_palloc ap_palloc |
117 | +#define apr_isalnum isalnum |
118 | +#define apr_toupper toupper |
119 | +typedef time_t apr_time_t; |
120 | +#include "http_config.h" |
121 | +typedef int apr_lockmech_e; |
122 | +#else |
123 | +#include "apr_lib.h" |
124 | +#include "ap_mpm.h" |
125 | +#include "ap_compat.h" |
126 | +#include "apr_tables.h" |
127 | +#include "apr_strings.h" |
128 | +#include "http_config.h" |
129 | +#include "ap_listen.h" |
130 | +#include "apr_version.h" |
131 | +#endif |
132 | + |
133 | +#include "ap_config.h" |
134 | +#include "http_core.h" |
135 | +#include "http_log.h" |
136 | +#include "http_main.h" |
137 | +#include "http_protocol.h" |
138 | +#include "http_request.h" |
139 | +#include "util_script.h" |
140 | +#include "util_md5.h" |
141 | + |
142 | +#ifndef APR_FPROT_GWRITE |
143 | +#define APR_FPROT_GWRITE APR_GWRITE |
144 | +#endif |
145 | +#ifndef APR_FPROT_WWRITE |
146 | +#define APR_FPROT_WWRITE APR_WWRITE |
147 | +#endif |
148 | + |
149 | +#if !AP_MODULE_MAGIC_AT_LEAST(20050127,0) |
150 | +/* Debian backported ap_regex_t to Apache 2.0 and |
151 | + * thus made official version checking break. */ |
152 | +#ifndef AP_REG_EXTENDED |
153 | +typedef regex_t ap_regex_t; |
154 | +typedef regmatch_t ap_regmatch_t; |
155 | +#define AP_REG_EXTENDED REG_EXTENDED |
156 | +#endif |
157 | +#endif |
158 | + |
159 | +#if !AP_MODULE_MAGIC_AT_LEAST(20081201,0) |
160 | +#define ap_unixd_config unixd_config |
161 | +#endif |
162 | + |
163 | +#ifndef WIN32 |
164 | +#include <pwd.h> |
165 | +#endif |
166 | + |
167 | +#include "Python.h" |
168 | + |
169 | +#if !defined(PY_VERSION_HEX) |
170 | +#error Sorry, Python developer package does not appear to be installed. |
171 | +#endif |
172 | + |
173 | +#if PY_VERSION_HEX <= 0x02030000 |
174 | +#error Sorry, mod_wsgi requires at least Python 2.3.0 for Python 2.X. |
175 | +#endif |
176 | + |
177 | +#if PY_VERSION_HEX >= 0x03000000 && PY_VERSION_HEX < 0x03010000 |
178 | +#error Sorry, mod_wsgi requires at least Python 3.1.0 for Python 3.X. |
179 | +#endif |
180 | + |
181 | +#if !defined(WITH_THREAD) |
182 | +#error Sorry, mod_wsgi requires that Python supporting thread. |
183 | +#endif |
184 | + |
185 | +#include "compile.h" |
186 | +#include "node.h" |
187 | +#include "osdefs.h" |
188 | + |
189 | +#ifndef PyVarObject_HEAD_INIT |
190 | +#define PyVarObject_HEAD_INIT(type, size) \ |
191 | + PyObject_HEAD_INIT(type) size, |
192 | +#endif |
193 | + |
194 | +#if PY_MAJOR_VERSION >= 3 |
195 | +#define PyStringObject PyBytesObject |
196 | +#define PyString_Check PyBytes_Check |
197 | +#define PyString_Size PyBytes_Size |
198 | +#define PyString_AsString PyBytes_AsString |
199 | +#define PyString_FromString PyBytes_FromString |
200 | +#define PyString_FromStringAndSize PyBytes_FromStringAndSize |
201 | +#define PyString_AS_STRING PyBytes_AS_STRING |
202 | +#define PyString_GET_SIZE PyBytes_GET_SIZE |
203 | +#define _PyString_Resize _PyBytes_Resize |
204 | +#endif |
205 | + |
206 | +#ifndef WIN32 |
207 | +#if AP_SERVER_MAJORVERSION_NUMBER >= 2 |
208 | +#if APR_HAS_OTHER_CHILD && APR_HAS_THREADS && APR_HAS_FORK |
209 | +#define MOD_WSGI_WITH_DAEMONS 1 |
210 | +#endif |
211 | +#endif |
212 | +#endif |
213 | + |
214 | +#if AP_SERVER_MAJORVERSION_NUMBER >= 2 |
215 | +#define MOD_WSGI_WITH_BUCKETS 1 |
216 | +#define MOD_WSGI_WITH_AAA_HANDLERS 1 |
217 | +#endif |
218 | + |
219 | +#if defined(MOD_WSGI_WITH_AAA_HANDLERS) |
220 | +static PyTypeObject Auth_Type; |
221 | +#if AP_SERVER_MAJORVERSION_NUMBER >= 2 |
222 | +#if AP_SERVER_MINORVERSION_NUMBER >= 2 |
223 | +#define MOD_WSGI_WITH_AUTHN_PROVIDER 1 |
224 | +#endif |
225 | +#endif |
226 | +#if AP_MODULE_MAGIC_AT_LEAST(20060110,0) |
227 | +#define MOD_WSGI_WITH_AUTHZ_PROVIDER 1 |
228 | +#endif |
229 | +#endif |
230 | + |
231 | +#if defined(MOD_WSGI_WITH_AUTHN_PROVIDER) |
232 | +#include "mod_auth.h" |
233 | +#include "ap_provider.h" |
234 | +#ifndef AUTHN_PROVIDER_VERSION |
235 | +#define AUTHN_PROVIDER_VERSION "0" |
236 | +#endif |
237 | +#endif |
238 | + |
239 | +#if defined(MOD_WSGI_WITH_DAEMONS) |
240 | + |
241 | +#if !AP_MODULE_MAGIC_AT_LEAST(20051115,0) |
242 | +static void ap_close_listeners(void) |
243 | +{ |
244 | + ap_listen_rec *lr; |
245 | + |
246 | + for (lr = ap_listeners; lr; lr = lr->next) { |
247 | + apr_socket_close(lr->sd); |
248 | + lr->active = 0; |
249 | + } |
250 | +} |
251 | +#endif |
252 | + |
253 | +#if (APR_MAJOR_VERSION == 0) && \ |
254 | + (APR_MINOR_VERSION == 9) && \ |
255 | + (APR_PATCH_VERSION < 5) |
256 | +static apr_status_t apr_unix_file_cleanup(void *thefile) |
257 | +{ |
258 | + apr_file_t *file = thefile; |
259 | + |
260 | + return apr_file_close(file); |
261 | +} |
262 | + |
263 | +static apr_status_t apr_os_pipe_put_ex(apr_file_t **file, |
264 | + apr_os_file_t *thefile, |
265 | + int register_cleanup, |
266 | + apr_pool_t *pool) |
267 | +{ |
268 | + apr_status_t rv; |
269 | + |
270 | + rv = apr_os_pipe_put(file, thefile, pool); |
271 | + |
272 | + if (register_cleanup) { |
273 | + apr_pool_cleanup_register(pool, (void *)(*file), |
274 | + apr_unix_file_cleanup, |
275 | + apr_pool_cleanup_null); |
276 | + } |
277 | + |
278 | + return rv; |
279 | +} |
280 | +#endif |
281 | + |
282 | +#endif |
283 | + |
284 | +#if AP_SERVER_MAJORVERSION_NUMBER < 2 |
285 | + |
286 | +static char *apr_off_t_toa(apr_pool_t *p, apr_off_t n) |
287 | +{ |
288 | + const int BUFFER_SIZE = sizeof(apr_off_t) * 3 + 2; |
289 | + char *buf = apr_palloc(p, BUFFER_SIZE); |
290 | + char *start = buf + BUFFER_SIZE - 1; |
291 | + int negative; |
292 | + if (n < 0) { |
293 | + negative = 1; |
294 | + n = -n; |
295 | + } |
296 | + else { |
297 | + negative = 0; |
298 | + } |
299 | + *start = 0; |
300 | + do { |
301 | + *--start = '0' + (char)(n % 10); |
302 | + n /= 10; |
303 | + } while (n); |
304 | + if (negative) { |
305 | + *--start = '-'; |
306 | + } |
307 | + return start; |
308 | +} |
309 | + |
310 | +#endif |
311 | + |
312 | +#if defined(WIN32) && defined(APR_HAS_UNICODE_FS) |
313 | +typedef apr_uint16_t apr_wchar_t; |
314 | + |
315 | +APR_DECLARE(apr_status_t) apr_conv_utf8_to_ucs2(const char *in, |
316 | + apr_size_t *inbytes, |
317 | + apr_wchar_t *out, |
318 | + apr_size_t *outwords); |
319 | + |
320 | +static apr_status_t wsgi_utf8_to_unicode_path(apr_wchar_t* retstr, |
321 | + apr_size_t retlen, |
322 | + const char* srcstr) |
323 | +{ |
324 | + /* TODO: The computations could preconvert the string to determine |
325 | + * the true size of the retstr, but that's a memory over speed |
326 | + * tradeoff that isn't appropriate this early in development. |
327 | + * |
328 | + * Allocate the maximum string length based on leading 4 |
329 | + * characters of \\?\ (allowing nearly unlimited path lengths) |
330 | + * plus the trailing null, then transform /'s into \\'s since |
331 | + * the \\?\ form doesn't allow '/' path seperators. |
332 | + * |
333 | + * Note that the \\?\ form only works for local drive paths, and |
334 | + * \\?\UNC\ is needed UNC paths. |
335 | + */ |
336 | + apr_size_t srcremains = strlen(srcstr) + 1; |
337 | + apr_wchar_t *t = retstr; |
338 | + apr_status_t rv; |
339 | + |
340 | + /* This is correct, we don't twist the filename if it is will |
341 | + * definately be shorter than 248 characters. It merits some |
342 | + * performance testing to see if this has any effect, but there |
343 | + * seem to be applications that get confused by the resulting |
344 | + * Unicode \\?\ style file names, especially if they use argv[0] |
345 | + * or call the Win32 API functions such as GetModuleName, etc. |
346 | + * Not every application is prepared to handle such names. |
347 | + * |
348 | + * Note also this is shorter than MAX_PATH, as directory paths |
349 | + * are actually limited to 248 characters. |
350 | + * |
351 | + * Note that a utf-8 name can never result in more wide chars |
352 | + * than the original number of utf-8 narrow chars. |
353 | + */ |
354 | + if (srcremains > 248) { |
355 | + if (srcstr[1] == ':' && (srcstr[2] == '/' || srcstr[2] == '\\')) { |
356 | + wcscpy (retstr, L"\\\\?\\"); |
357 | + retlen -= 4; |
358 | + t += 4; |
359 | + } |
360 | + else if ((srcstr[0] == '/' || srcstr[0] == '\\') |
361 | + && (srcstr[1] == '/' || srcstr[1] == '\\') |
362 | + && (srcstr[2] != '?')) { |
363 | + /* Skip the slashes */ |
364 | + srcstr += 2; |
365 | + srcremains -= 2; |
366 | + wcscpy (retstr, L"\\\\?\\UNC\\"); |
367 | + retlen -= 8; |
368 | + t += 8; |
369 | + } |
370 | + } |
371 | + |
372 | + if (rv = apr_conv_utf8_to_ucs2(srcstr, &srcremains, t, &retlen)) { |
373 | + return (rv == APR_INCOMPLETE) ? APR_EINVAL : rv; |
374 | + } |
375 | + if (srcremains) { |
376 | + return APR_ENAMETOOLONG; |
377 | + } |
378 | + for (; *t; ++t) |
379 | + if (*t == L'/') |
380 | + *t = L'\\'; |
381 | + return APR_SUCCESS; |
382 | +} |
383 | +#endif |
384 | + |
385 | +/* Compatibility macros for log level and status. */ |
386 | + |
387 | +#if AP_SERVER_MAJORVERSION_NUMBER < 2 |
388 | +#define WSGI_LOG_LEVEL(l) l |
389 | +#define WSGI_LOG_LEVEL_AND_STATUS(l, e) l | (!e ? APLOG_NOERRNO : 0) |
390 | +#else |
391 | +#define WSGI_LOG_LEVEL(l) l, 0 |
392 | +#define WSGI_LOG_LEVEL_AND_STATUS(l, e) l, e |
393 | +#endif |
394 | + |
395 | +#define WSGI_LOG_EMERG(e) WSGI_LOG_LEVEL_AND_STATUS(APLOG_EMERG, e) |
396 | +#define WSGI_LOG_ALERT(e) WSGI_LOG_LEVEL_AND_STATUS(APLOG_ALERT, e) |
397 | +#define WSGI_LOG_CRIT(e) WSGI_LOG_LEVEL_AND_STATUS(APLOG_CRIT, e) |
398 | +#define WSGI_LOG_ERR(e) WSGI_LOG_LEVEL_AND_STATUS(APLOG_ERR, e) |
399 | +#define WSGI_LOG_WARNING(e) WSGI_LOG_LEVEL_AND_STATUS(APLOG_WARNING, e) |
400 | +#define WSGI_LOG_NOTICE(e) WSGI_LOG_LEVEL_AND_STATUS(APLOG_NOTICE, e) |
401 | +#define WSGI_LOG_INFO(e) WSGI_LOG_LEVEL_AND_STATUS(APLOG_INFO, e) |
402 | +#define WSGI_LOG_DEBUG(e) WSGI_LOG_LEVEL_AND_STATUS(APLOG_DEBUG, e) |
403 | + |
404 | +/* Version and module information. */ |
405 | + |
406 | +#define MOD_WSGI_MAJORVERSION_NUMBER 3 |
407 | +#define MOD_WSGI_MINORVERSION_NUMBER 3 |
408 | +#define MOD_WSGI_VERSION_STRING "3.3" |
409 | + |
410 | +#if AP_SERVER_MAJORVERSION_NUMBER < 2 |
411 | +module MODULE_VAR_EXPORT wsgi_module; |
412 | +#else |
413 | +module AP_MODULE_DECLARE_DATA wsgi_module; |
414 | +#endif |
415 | + |
416 | +/* Constants. */ |
417 | + |
418 | +#define WSGI_RELOAD_MODULE 0 |
419 | +#define WSGI_RELOAD_PROCESS 1 |
420 | + |
421 | +/* Base server object. */ |
422 | + |
423 | +static server_rec *wsgi_server = NULL; |
424 | + |
425 | +/* Process information. */ |
426 | + |
427 | +static pid_t wsgi_parent_pid = 0; |
428 | +static int wsgi_multiprocess = 1; |
429 | +static int wsgi_multithread = 1; |
430 | + |
431 | +/* Daemon information. */ |
432 | + |
433 | +static const char *wsgi_daemon_group = ""; |
434 | + |
435 | +static apr_array_header_t *wsgi_daemon_list = NULL; |
436 | + |
437 | +static apr_pool_t *wsgi_parent_pool = NULL; |
438 | +static apr_pool_t *wsgi_daemon_pool = NULL; |
439 | + |
440 | +static int volatile wsgi_daemon_shutdown = 0; |
441 | + |
442 | +#if defined(MOD_WSGI_WITH_DAEMONS) |
443 | +static apr_interval_time_t wsgi_deadlock_timeout = 0; |
444 | +static apr_interval_time_t wsgi_inactivity_timeout = 0; |
445 | +static apr_time_t volatile wsgi_deadlock_shutdown_time = 0; |
446 | +static apr_time_t volatile wsgi_inactivity_shutdown_time = 0; |
447 | +static apr_thread_mutex_t* wsgi_shutdown_lock = NULL; |
448 | +#endif |
449 | + |
450 | +/* Script information. */ |
451 | + |
452 | +static apr_array_header_t *wsgi_import_list = NULL; |
453 | + |
454 | +/* Configuration objects. */ |
455 | + |
456 | +typedef struct { |
457 | + const char *location; |
458 | + const char *application; |
459 | + ap_regex_t *regexp; |
460 | + const char *process_group; |
461 | + const char *application_group; |
462 | + const char *callable_object; |
463 | + int pass_authorization; |
464 | +} WSGIAliasEntry; |
465 | + |
466 | +typedef struct { |
467 | + const char *handler_script; |
468 | + const char *process_group; |
469 | + const char *application_group; |
470 | + const char *callable_object; |
471 | + const char *pass_authorization; |
472 | +} WSGIScriptFile; |
473 | + |
474 | +typedef struct { |
475 | + apr_pool_t *pool; |
476 | + |
477 | + apr_array_header_t *alias_list; |
478 | + |
479 | + const char *socket_prefix; |
480 | + apr_lockmech_e lock_mechanism; |
481 | + |
482 | + int verbose_debugging; |
483 | + |
484 | + apr_array_header_t *python_warnings; |
485 | + |
486 | + int python_optimize; |
487 | + int py3k_warning_flag; |
488 | + |
489 | + const char *python_home; |
490 | + const char *python_path; |
491 | + const char *python_eggs; |
492 | + |
493 | + int restrict_embedded; |
494 | + int restrict_stdin; |
495 | + int restrict_stdout; |
496 | + int restrict_signal; |
497 | + |
498 | + int case_sensitivity; |
499 | + |
500 | + apr_table_t *restrict_process; |
501 | + |
502 | + const char *process_group; |
503 | + const char *application_group; |
504 | + const char *callable_object; |
505 | + |
506 | + WSGIScriptFile *dispatch_script; |
507 | + |
508 | + int pass_apache_request; |
509 | + int pass_authorization; |
510 | + int script_reloading; |
511 | + int error_override; |
512 | + int chunked_request; |
513 | + |
514 | +#if AP_SERVER_MAJORVERSION_NUMBER >= 2 |
515 | + apr_hash_t *handler_scripts; |
516 | +#endif |
517 | +} WSGIServerConfig; |
518 | + |
519 | +static WSGIServerConfig *wsgi_server_config = NULL; |
520 | + |
521 | +static WSGIScriptFile *newWSGIScriptFile(apr_pool_t *p) |
522 | +{ |
523 | + WSGIScriptFile *object = NULL; |
524 | + |
525 | + object = (WSGIScriptFile *)apr_pcalloc(p, sizeof(WSGIScriptFile)); |
526 | + |
527 | + object->handler_script = NULL; |
528 | + object->application_group = NULL; |
529 | + object->process_group = NULL; |
530 | + |
531 | + return object; |
532 | +} |
533 | + |
534 | +static WSGIServerConfig *newWSGIServerConfig(apr_pool_t *p) |
535 | +{ |
536 | + WSGIServerConfig *object = NULL; |
537 | + |
538 | + object = (WSGIServerConfig *)apr_pcalloc(p, sizeof(WSGIServerConfig)); |
539 | + |
540 | + object->pool = p; |
541 | + |
542 | + object->alias_list = NULL; |
543 | + |
544 | + object->socket_prefix = NULL; |
545 | + |
546 | +#if defined(MOD_WSGI_WITH_DAEMONS) |
547 | + object->socket_prefix = DEFAULT_REL_RUNTIMEDIR "/wsgi"; |
548 | + object->socket_prefix = ap_server_root_relative(p, object->socket_prefix); |
549 | +#endif |
550 | + |
551 | + object->verbose_debugging = 0; |
552 | + |
553 | + object->python_warnings = NULL; |
554 | + |
555 | + object->py3k_warning_flag = -1; |
556 | + object->python_optimize = -1; |
557 | + |
558 | + object->python_home = NULL; |
559 | + object->python_path = NULL; |
560 | + object->python_eggs = NULL; |
561 | + |
562 | + object->restrict_embedded = -1; |
563 | + object->restrict_stdin = -1; |
564 | + object->restrict_stdout = -1; |
565 | + object->restrict_signal = -1; |
566 | + |
567 | +#if defined(WIN32) || defined(DARWIN) |
568 | + object->case_sensitivity = 0; |
569 | +#else |
570 | + object->case_sensitivity = 1; |
571 | +#endif |
572 | + |
573 | + object->restrict_process = NULL; |
574 | + |
575 | + object->process_group = NULL; |
576 | + object->application_group = NULL; |
577 | + object->callable_object = NULL; |
578 | + |
579 | + object->dispatch_script = NULL; |
580 | + |
581 | + object->pass_apache_request = -1; |
582 | + object->pass_authorization = -1; |
583 | + object->script_reloading = -1; |
584 | + object->error_override = -1; |
585 | + object->chunked_request = -1; |
586 | + |
587 | + return object; |
588 | +} |
589 | + |
590 | +static void *wsgi_create_server_config(apr_pool_t *p, server_rec *s) |
591 | +{ |
592 | + WSGIServerConfig *config = NULL; |
593 | + |
594 | + config = newWSGIServerConfig(p); |
595 | + |
596 | + return config; |
597 | +} |
598 | + |
599 | +static void *wsgi_merge_server_config(apr_pool_t *p, void *base_conf, |
600 | + void *new_conf) |
601 | +{ |
602 | + WSGIServerConfig *config = NULL; |
603 | + WSGIServerConfig *parent = NULL; |
604 | + WSGIServerConfig *child = NULL; |
605 | + |
606 | + config = newWSGIServerConfig(p); |
607 | + |
608 | + parent = (WSGIServerConfig *)base_conf; |
609 | + child = (WSGIServerConfig *)new_conf; |
610 | + |
611 | + if (child->alias_list && parent->alias_list) { |
612 | + config->alias_list = apr_array_append(p, child->alias_list, |
613 | + parent->alias_list); |
614 | + } |
615 | + else if (child->alias_list) { |
616 | + config->alias_list = apr_array_make(p, 20, sizeof(WSGIAliasEntry)); |
617 | + apr_array_cat(config->alias_list, child->alias_list); |
618 | + } |
619 | + else if (parent->alias_list) { |
620 | + config->alias_list = apr_array_make(p, 20, sizeof(WSGIAliasEntry)); |
621 | + apr_array_cat(config->alias_list, parent->alias_list); |
622 | + } |
623 | + |
624 | + if (child->restrict_process) |
625 | + config->restrict_process = child->restrict_process; |
626 | + else |
627 | + config->restrict_process = parent->restrict_process; |
628 | + |
629 | + if (child->process_group) |
630 | + config->process_group = child->process_group; |
631 | + else |
632 | + config->process_group = parent->process_group; |
633 | + |
634 | + if (child->application_group) |
635 | + config->application_group = child->application_group; |
636 | + else |
637 | + config->application_group = parent->application_group; |
638 | + |
639 | + if (child->callable_object) |
640 | + config->callable_object = child->callable_object; |
641 | + else |
642 | + config->callable_object = parent->callable_object; |
643 | + |
644 | + if (child->dispatch_script) |
645 | + config->dispatch_script = child->dispatch_script; |
646 | + else |
647 | + config->dispatch_script = parent->dispatch_script; |
648 | + |
649 | + if (child->pass_apache_request != -1) |
650 | + config->pass_apache_request = child->pass_apache_request; |
651 | + else |
652 | + config->pass_apache_request = parent->pass_apache_request; |
653 | + |
654 | + if (child->pass_authorization != -1) |
655 | + config->pass_authorization = child->pass_authorization; |
656 | + else |
657 | + config->pass_authorization = parent->pass_authorization; |
658 | + |
659 | + if (child->script_reloading != -1) |
660 | + config->script_reloading = child->script_reloading; |
661 | + else |
662 | + config->script_reloading = parent->script_reloading; |
663 | + |
664 | + if (child->error_override != -1) |
665 | + config->error_override = child->error_override; |
666 | + else |
667 | + config->error_override = parent->error_override; |
668 | + |
669 | + if (child->chunked_request != -1) |
670 | + config->chunked_request = child->chunked_request; |
671 | + else |
672 | + config->chunked_request = parent->chunked_request; |
673 | + |
674 | +#if AP_SERVER_MAJORVERSION_NUMBER >= 2 |
675 | + if (!child->handler_scripts) |
676 | + config->handler_scripts = parent->handler_scripts; |
677 | + else if (!parent->handler_scripts) |
678 | + config->handler_scripts = child->handler_scripts; |
679 | + else { |
680 | + config->handler_scripts = apr_hash_overlay(p, child->handler_scripts, |
681 | + parent->handler_scripts); |
682 | + } |
683 | +#endif |
684 | + |
685 | + return config; |
686 | +} |
687 | + |
688 | +typedef struct { |
689 | + apr_pool_t *pool; |
690 | + |
691 | + apr_table_t *restrict_process; |
692 | + |
693 | + const char *process_group; |
694 | + const char *application_group; |
695 | + const char *callable_object; |
696 | + |
697 | + WSGIScriptFile *dispatch_script; |
698 | + |
699 | + int pass_apache_request; |
700 | + int pass_authorization; |
701 | + int script_reloading; |
702 | + int error_override; |
703 | + int chunked_request; |
704 | + |
705 | + WSGIScriptFile *access_script; |
706 | + WSGIScriptFile *auth_user_script; |
707 | + WSGIScriptFile *auth_group_script; |
708 | + int user_authoritative; |
709 | + int group_authoritative; |
710 | + |
711 | +#if AP_SERVER_MAJORVERSION_NUMBER >= 2 |
712 | + apr_hash_t *handler_scripts; |
713 | +#endif |
714 | +} WSGIDirectoryConfig; |
715 | + |
716 | +static WSGIDirectoryConfig *newWSGIDirectoryConfig(apr_pool_t *p) |
717 | +{ |
718 | + WSGIDirectoryConfig *object = NULL; |
719 | + |
720 | + object = (WSGIDirectoryConfig *)apr_pcalloc(p, sizeof(WSGIDirectoryConfig)); |
721 | + |
722 | + object->pool = p; |
723 | + |
724 | + object->process_group = NULL; |
725 | + object->application_group = NULL; |
726 | + object->callable_object = NULL; |
727 | + |
728 | + object->dispatch_script = NULL; |
729 | + |
730 | + object->pass_apache_request = -1; |
731 | + object->pass_authorization = -1; |
732 | + object->script_reloading = -1; |
733 | + object->error_override = -1; |
734 | + object->chunked_request = -1; |
735 | + |
736 | + object->access_script = NULL; |
737 | + object->auth_user_script = NULL; |
738 | + object->auth_group_script = NULL; |
739 | + object->user_authoritative = -1; |
740 | + object->group_authoritative = -1; |
741 | + |
742 | + return object; |
743 | +} |
744 | + |
745 | +static void *wsgi_create_dir_config(apr_pool_t *p, char *dir) |
746 | +{ |
747 | + WSGIDirectoryConfig *config = NULL; |
748 | + |
749 | + config = newWSGIDirectoryConfig(p); |
750 | + |
751 | + return config; |
752 | +} |
753 | + |
754 | +static void *wsgi_merge_dir_config(apr_pool_t *p, void *base_conf, |
755 | + void *new_conf) |
756 | +{ |
757 | + WSGIDirectoryConfig *config = NULL; |
758 | + WSGIDirectoryConfig *parent = NULL; |
759 | + WSGIDirectoryConfig *child = NULL; |
760 | + |
761 | + config = newWSGIDirectoryConfig(p); |
762 | + |
763 | + parent = (WSGIDirectoryConfig *)base_conf; |
764 | + child = (WSGIDirectoryConfig *)new_conf; |
765 | + |
766 | + if (child->restrict_process) |
767 | + config->restrict_process = child->restrict_process; |
768 | + else |
769 | + config->restrict_process = parent->restrict_process; |
770 | + |
771 | + if (child->process_group) |
772 | + config->process_group = child->process_group; |
773 | + else |
774 | + config->process_group = parent->process_group; |
775 | + |
776 | + if (child->application_group) |
777 | + config->application_group = child->application_group; |
778 | + else |
779 | + config->application_group = parent->application_group; |
780 | + |
781 | + if (child->callable_object) |
782 | + config->callable_object = child->callable_object; |
783 | + else |
784 | + config->callable_object = parent->callable_object; |
785 | + |
786 | + if (child->dispatch_script) |
787 | + config->dispatch_script = child->dispatch_script; |
788 | + else |
789 | + config->dispatch_script = parent->dispatch_script; |
790 | + |
791 | + if (child->pass_apache_request != -1) |
792 | + config->pass_apache_request = child->pass_apache_request; |
793 | + else |
794 | + config->pass_apache_request = parent->pass_apache_request; |
795 | + |
796 | + if (child->pass_authorization != -1) |
797 | + config->pass_authorization = child->pass_authorization; |
798 | + else |
799 | + config->pass_authorization = parent->pass_authorization; |
800 | + |
801 | + if (child->script_reloading != -1) |
802 | + config->script_reloading = child->script_reloading; |
803 | + else |
804 | + config->script_reloading = parent->script_reloading; |
805 | + |
806 | + if (child->error_override != -1) |
807 | + config->error_override = child->error_override; |
808 | + else |
809 | + config->error_override = parent->error_override; |
810 | + |
811 | + if (child->chunked_request != -1) |
812 | + config->chunked_request = child->chunked_request; |
813 | + else |
814 | + config->chunked_request = parent->chunked_request; |
815 | + |
816 | + if (child->access_script) |
817 | + config->access_script = child->access_script; |
818 | + else |
819 | + config->access_script = parent->access_script; |
820 | + |
821 | + if (child->auth_user_script) |
822 | + config->auth_user_script = child->auth_user_script; |
823 | + else |
824 | + config->auth_user_script = parent->auth_user_script; |
825 | + |
826 | + if (child->auth_group_script) |
827 | + config->auth_group_script = child->auth_group_script; |
828 | + else |
829 | + config->auth_group_script = parent->auth_group_script; |
830 | + |
831 | + if (child->user_authoritative != -1) |
832 | + config->user_authoritative = child->user_authoritative; |
833 | + else |
834 | + config->user_authoritative = parent->user_authoritative; |
835 | + |
836 | + if (child->group_authoritative != -1) |
837 | + config->group_authoritative = child->group_authoritative; |
838 | + else |
839 | + config->group_authoritative = parent->group_authoritative; |
840 | + |
841 | +#if AP_SERVER_MAJORVERSION_NUMBER >= 2 |
842 | + if (!child->handler_scripts) |
843 | + config->handler_scripts = parent->handler_scripts; |
844 | + else if (!parent->handler_scripts) |
845 | + config->handler_scripts = child->handler_scripts; |
846 | + else { |
847 | + config->handler_scripts = apr_hash_overlay(p, child->handler_scripts, |
848 | + parent->handler_scripts); |
849 | + } |
850 | +#endif |
851 | + |
852 | + return config; |
853 | +} |
854 | + |
855 | +typedef struct { |
856 | + apr_pool_t *pool; |
857 | + |
858 | + apr_table_t *restrict_process; |
859 | + |
860 | + const char *process_group; |
861 | + const char *application_group; |
862 | + const char *callable_object; |
863 | + |
864 | + WSGIScriptFile *dispatch_script; |
865 | + |
866 | + int pass_apache_request; |
867 | + int pass_authorization; |
868 | + int script_reloading; |
869 | + int error_override; |
870 | + int chunked_request; |
871 | + |
872 | + WSGIScriptFile *access_script; |
873 | + WSGIScriptFile *auth_user_script; |
874 | + WSGIScriptFile *auth_group_script; |
875 | + int user_authoritative; |
876 | + int group_authoritative; |
877 | + |
878 | +#if AP_SERVER_MAJORVERSION_NUMBER >= 2 |
879 | + apr_hash_t *handler_scripts; |
880 | +#endif |
881 | + const char *handler_script; |
882 | +} WSGIRequestConfig; |
883 | + |
884 | +static int wsgi_find_path_info(const char *uri, const char *path_info) |
885 | +{ |
886 | + int lu = strlen(uri); |
887 | + int lp = strlen(path_info); |
888 | + |
889 | + while (lu-- && lp-- && uri[lu] == path_info[lp]) { |
890 | + if (path_info[lp] == '/') { |
891 | + while (lu && uri[lu-1] == '/') lu--; |
892 | + } |
893 | + } |
894 | + |
895 | + if (lu == -1) { |
896 | + lu = 0; |
897 | + } |
898 | + |
899 | + while (uri[lu] != '\0' && uri[lu] != '/') { |
900 | + lu++; |
901 | + } |
902 | + return lu; |
903 | +} |
904 | + |
905 | +static const char *wsgi_script_name(request_rec *r) |
906 | +{ |
907 | + char *script_name = NULL; |
908 | + int path_info_start = 0; |
909 | + |
910 | + if (!r->path_info || !*r->path_info) { |
911 | + script_name = apr_pstrdup(r->pool, r->uri); |
912 | + } |
913 | + else { |
914 | + path_info_start = wsgi_find_path_info(r->uri, r->path_info); |
915 | + |
916 | + script_name = apr_pstrndup(r->pool, r->uri, path_info_start); |
917 | + } |
918 | + |
919 | + if (*script_name) { |
920 | + while (*script_name && (*(script_name+1) == '/')) |
921 | + script_name++; |
922 | + script_name = apr_pstrdup(r->pool, script_name); |
923 | + ap_no2slash((char*)script_name); |
924 | + } |
925 | + |
926 | + ap_str_tolower(script_name); |
927 | + |
928 | + return script_name; |
929 | +} |
930 | + |
931 | +static const char *wsgi_process_group(request_rec *r, const char *s) |
932 | +{ |
933 | + const char *name = NULL; |
934 | + const char *value = NULL; |
935 | + |
936 | + if (!s) |
937 | + return ""; |
938 | + |
939 | + if (*s != '%') |
940 | + return s; |
941 | + |
942 | + name = s + 1; |
943 | + |
944 | + if (*name) { |
945 | + if (!strcmp(name, "{GLOBAL}")) |
946 | + return ""; |
947 | + |
948 | + if (strstr(name, "{ENV:") == name) { |
949 | + int len = 0; |
950 | + |
951 | + name = name + 5; |
952 | + len = strlen(name); |
953 | + |
954 | + if (len && name[len-1] == '}') { |
955 | + name = apr_pstrndup(r->pool, name, len-1); |
956 | + |
957 | + value = apr_table_get(r->notes, name); |
958 | + |
959 | + if (!value) |
960 | + value = apr_table_get(r->subprocess_env, name); |
961 | + |
962 | + if (!value) |
963 | + value = getenv(name); |
964 | + |
965 | + if (value) { |
966 | + if (*value == '%' && strstr(value, "%{ENV:") != value) |
967 | + return wsgi_process_group(r, value); |
968 | + |
969 | + return value; |
970 | + } |
971 | + } |
972 | + } |
973 | + } |
974 | + |
975 | + return s; |
976 | +} |
977 | + |
978 | +static const char *wsgi_server_group(request_rec *r, const char *s) |
979 | +{ |
980 | + const char *name = NULL; |
981 | + const char *value = NULL; |
982 | + |
983 | + const char *h = NULL; |
984 | + apr_port_t p = 0; |
985 | + |
986 | + if (!s) |
987 | + return ""; |
988 | + |
989 | + if (*s != '%') |
990 | + return s; |
991 | + |
992 | + name = s + 1; |
993 | + |
994 | + if (*name) { |
995 | + if (!strcmp(name, "{SERVER}")) { |
996 | + h = r->server->server_hostname; |
997 | + p = ap_get_server_port(r); |
998 | + |
999 | + if (p != DEFAULT_HTTP_PORT && p != DEFAULT_HTTPS_PORT) |
1000 | + return apr_psprintf(r->pool, "%s:%u", h, p); |
1001 | + else |
1002 | + return h; |
1003 | + } |
1004 | + |
1005 | + if (!strcmp(name, "{GLOBAL}")) |
1006 | + return ""; |
1007 | + } |
1008 | + |
1009 | + return s; |
1010 | +} |
1011 | + |
1012 | +static const char *wsgi_application_group(request_rec *r, const char *s) |
1013 | +{ |
1014 | + const char *name = NULL; |
1015 | + const char *value = NULL; |
1016 | + |
1017 | + const char *h = NULL; |
1018 | + apr_port_t p = 0; |
1019 | + const char *n = NULL; |
1020 | + |
1021 | + if (!s) { |
1022 | + h = r->server->server_hostname; |
1023 | + p = ap_get_server_port(r); |
1024 | + n = wsgi_script_name(r); |
1025 | + |
1026 | + if (p != DEFAULT_HTTP_PORT && p != DEFAULT_HTTPS_PORT) |
1027 | + return apr_psprintf(r->pool, "%s:%u|%s", h, p, n); |
1028 | + else |
1029 | + return apr_psprintf(r->pool, "%s|%s", h, n); |
1030 | + } |
1031 | + |
1032 | + if (*s != '%') |
1033 | + return s; |
1034 | + |
1035 | + name = s + 1; |
1036 | + |
1037 | + if (*name) { |
1038 | + if (!strcmp(name, "{RESOURCE}")) { |
1039 | + h = r->server->server_hostname; |
1040 | + p = ap_get_server_port(r); |
1041 | + n = wsgi_script_name(r); |
1042 | + |
1043 | + if (p != DEFAULT_HTTP_PORT && p != DEFAULT_HTTPS_PORT) |
1044 | + return apr_psprintf(r->pool, "%s:%u|%s", h, p, n); |
1045 | + else |
1046 | + return apr_psprintf(r->pool, "%s|%s", h, n); |
1047 | + } |
1048 | + |
1049 | + if (!strcmp(name, "{SERVER}")) { |
1050 | + h = r->server->server_hostname; |
1051 | + p = ap_get_server_port(r); |
1052 | + |
1053 | + if (p != DEFAULT_HTTP_PORT && p != DEFAULT_HTTPS_PORT) |
1054 | + return apr_psprintf(r->pool, "%s:%u", h, p); |
1055 | + else |
1056 | + return h; |
1057 | + } |
1058 | + |
1059 | + if (!strcmp(name, "{GLOBAL}")) |
1060 | + return ""; |
1061 | + |
1062 | + if (strstr(name, "{ENV:") == name) { |
1063 | + int len = 0; |
1064 | + |
1065 | + name = name + 5; |
1066 | + len = strlen(name); |
1067 | + |
1068 | + if (len && name[len-1] == '}') { |
1069 | + name = apr_pstrndup(r->pool, name, len-1); |
1070 | + |
1071 | + value = apr_table_get(r->notes, name); |
1072 | + |
1073 | + if (!value) |
1074 | + value = apr_table_get(r->subprocess_env, name); |
1075 | + |
1076 | + if (!value) |
1077 | + value = getenv(name); |
1078 | + |
1079 | + if (value) { |
1080 | + if (*value == '%' && strstr(value, "%{ENV:") != value) |
1081 | + return wsgi_application_group(r, value); |
1082 | + |
1083 | + return value; |
1084 | + } |
1085 | + } |
1086 | + } |
1087 | + } |
1088 | + |
1089 | + return s; |
1090 | +} |
1091 | + |
1092 | +static const char *wsgi_callable_object(request_rec *r, const char *s) |
1093 | +{ |
1094 | + const char *name = NULL; |
1095 | + const char *value = NULL; |
1096 | + |
1097 | + if (!s) |
1098 | + return "application"; |
1099 | + |
1100 | + if (*s != '%') |
1101 | + return s; |
1102 | + |
1103 | + name = s + 1; |
1104 | + |
1105 | + if (!*name) |
1106 | + return "application"; |
1107 | + |
1108 | + if (strstr(name, "{ENV:") == name) { |
1109 | + int len = 0; |
1110 | + |
1111 | + name = name + 5; |
1112 | + len = strlen(name); |
1113 | + |
1114 | + if (len && name[len-1] == '}') { |
1115 | + name = apr_pstrndup(r->pool, name, len-1); |
1116 | + |
1117 | + value = apr_table_get(r->notes, name); |
1118 | + |
1119 | + if (!value) |
1120 | + value = apr_table_get(r->subprocess_env, name); |
1121 | + |
1122 | + if (!value) |
1123 | + value = getenv(name); |
1124 | + |
1125 | + if (value) |
1126 | + return value; |
1127 | + } |
1128 | + } |
1129 | + |
1130 | + return "application"; |
1131 | +} |
1132 | + |
1133 | +static WSGIRequestConfig *wsgi_create_req_config(apr_pool_t *p, request_rec *r) |
1134 | +{ |
1135 | + WSGIRequestConfig *config = NULL; |
1136 | + WSGIServerConfig *sconfig = NULL; |
1137 | + WSGIDirectoryConfig *dconfig = NULL; |
1138 | + |
1139 | + config = (WSGIRequestConfig *)apr_pcalloc(p, sizeof(WSGIRequestConfig)); |
1140 | + |
1141 | + dconfig = ap_get_module_config(r->per_dir_config, &wsgi_module); |
1142 | + sconfig = ap_get_module_config(r->server->module_config, &wsgi_module); |
1143 | + |
1144 | + config->pool = p; |
1145 | + |
1146 | + config->restrict_process = dconfig->restrict_process; |
1147 | + |
1148 | + if (!config->restrict_process) |
1149 | + config->restrict_process = sconfig->restrict_process; |
1150 | + |
1151 | + config->process_group = dconfig->process_group; |
1152 | + |
1153 | + if (!config->process_group) |
1154 | + config->process_group = sconfig->process_group; |
1155 | + |
1156 | + config->process_group = wsgi_process_group(r, config->process_group); |
1157 | + |
1158 | + config->application_group = dconfig->application_group; |
1159 | + |
1160 | + if (!config->application_group) |
1161 | + config->application_group = sconfig->application_group; |
1162 | + |
1163 | + config->application_group = wsgi_application_group(r, |
1164 | + config->application_group); |
1165 | + |
1166 | + config->callable_object = dconfig->callable_object; |
1167 | + |
1168 | + if (!config->callable_object) |
1169 | + config->callable_object = sconfig->callable_object; |
1170 | + |
1171 | + config->callable_object = wsgi_callable_object(r, config->callable_object); |
1172 | + |
1173 | + config->dispatch_script = dconfig->dispatch_script; |
1174 | + |
1175 | + if (!config->dispatch_script) |
1176 | + config->dispatch_script = sconfig->dispatch_script; |
1177 | + |
1178 | + config->pass_apache_request = dconfig->pass_apache_request; |
1179 | + |
1180 | + if (config->pass_apache_request < 0) { |
1181 | + config->pass_apache_request = sconfig->pass_apache_request; |
1182 | + if (config->pass_apache_request < 0) |
1183 | + config->pass_apache_request = 0; |
1184 | + } |
1185 | + |
1186 | + config->pass_authorization = dconfig->pass_authorization; |
1187 | + |
1188 | + if (config->pass_authorization < 0) { |
1189 | + config->pass_authorization = sconfig->pass_authorization; |
1190 | + if (config->pass_authorization < 0) |
1191 | + config->pass_authorization = 0; |
1192 | + } |
1193 | + |
1194 | + config->script_reloading = dconfig->script_reloading; |
1195 | + |
1196 | + if (config->script_reloading < 0) { |
1197 | + config->script_reloading = sconfig->script_reloading; |
1198 | + if (config->script_reloading < 0) |
1199 | + config->script_reloading = 1; |
1200 | + } |
1201 | + |
1202 | + config->error_override = dconfig->error_override; |
1203 | + |
1204 | + if (config->error_override < 0) { |
1205 | + config->error_override = sconfig->error_override; |
1206 | + if (config->error_override < 0) |
1207 | + config->error_override = 0; |
1208 | + } |
1209 | + |
1210 | + config->chunked_request = dconfig->chunked_request; |
1211 | + |
1212 | + if (config->chunked_request < 0) { |
1213 | + config->chunked_request = sconfig->chunked_request; |
1214 | + if (config->chunked_request < 0) |
1215 | + config->chunked_request = 0; |
1216 | + } |
1217 | + |
1218 | + config->access_script = dconfig->access_script; |
1219 | + |
1220 | + config->auth_user_script = dconfig->auth_user_script; |
1221 | + |
1222 | + config->auth_group_script = dconfig->auth_group_script; |
1223 | + |
1224 | + config->user_authoritative = dconfig->user_authoritative; |
1225 | + |
1226 | + if (config->user_authoritative == -1) |
1227 | + config->user_authoritative = 1; |
1228 | + |
1229 | + config->group_authoritative = dconfig->group_authoritative; |
1230 | + |
1231 | + if (config->group_authoritative == -1) |
1232 | + config->group_authoritative = 1; |
1233 | + |
1234 | +#if AP_SERVER_MAJORVERSION_NUMBER >= 2 |
1235 | + if (!dconfig->handler_scripts) |
1236 | + config->handler_scripts = sconfig->handler_scripts; |
1237 | + else if (!sconfig->handler_scripts) |
1238 | + config->handler_scripts = dconfig->handler_scripts; |
1239 | + else { |
1240 | + config->handler_scripts = apr_hash_overlay(p, dconfig->handler_scripts, |
1241 | + sconfig->handler_scripts); |
1242 | + } |
1243 | +#endif |
1244 | + |
1245 | + config->handler_script = ""; |
1246 | + |
1247 | + return config; |
1248 | +} |
1249 | + |
1250 | +/* |
1251 | + * Apache 2.X and UNIX specific definitions related to |
1252 | + * distinct daemon processes. |
1253 | + */ |
1254 | + |
1255 | +#if defined(MOD_WSGI_WITH_DAEMONS) |
1256 | + |
1257 | +#include "unixd.h" |
1258 | +#include "scoreboard.h" |
1259 | +#include "mpm_common.h" |
1260 | +#include "apr_proc_mutex.h" |
1261 | +#include "apr_thread_cond.h" |
1262 | +#include "apr_atomic.h" |
1263 | +#include "http_connection.h" |
1264 | +#include "apr_buckets.h" |
1265 | +#include "apr_poll.h" |
1266 | +#include "apr_signal.h" |
1267 | +#include "http_vhost.h" |
1268 | + |
1269 | +#if APR_MAJOR_VERSION < 1 |
1270 | +#define apr_atomic_cas32 apr_atomic_cas |
1271 | +#endif |
1272 | + |
1273 | +#if APR_HAVE_SYS_SOCKET_H |
1274 | +#include <sys/socket.h> |
1275 | +#endif |
1276 | +#if APR_HAVE_UNISTD_H |
1277 | +#include <unistd.h> |
1278 | +#endif |
1279 | +#if APR_HAVE_SYS_TYPES_H |
1280 | +#include <sys/types.h> |
1281 | +#endif |
1282 | +#ifdef HAVE_SYS_SEM_H |
1283 | +#include <sys/sem.h> |
1284 | +#endif |
1285 | + |
1286 | +#include <sys/un.h> |
1287 | + |
1288 | +#ifndef WSGI_LISTEN_BACKLOG |
1289 | +#define WSGI_LISTEN_BACKLOG 100 |
1290 | +#endif |
1291 | + |
1292 | +#ifndef WSGI_CONNECT_ATTEMPTS |
1293 | +#define WSGI_CONNECT_ATTEMPTS 15 |
1294 | +#endif |
1295 | + |
1296 | +#define WSGI_STACK_HEAD 0xffff |
1297 | +#define WSGI_STACK_LAST 0xffff |
1298 | +#define WSGI_STACK_TERMINATED 0x10000 |
1299 | +#define WSGI_STACK_NO_LISTENER 0x20000 |
1300 | + |
1301 | +typedef struct { |
1302 | + server_rec *server; |
1303 | + long random; |
1304 | + int id; |
1305 | + const char *name; |
1306 | + const char *user; |
1307 | + uid_t uid; |
1308 | + const char *group; |
1309 | + gid_t gid; |
1310 | + int processes; |
1311 | + int multiprocess; |
1312 | + int threads; |
1313 | + int umask; |
1314 | + const char *root; |
1315 | + const char *home; |
1316 | + const char *python_path; |
1317 | + const char *python_eggs; |
1318 | + int stack_size; |
1319 | + int maximum_requests; |
1320 | + int shutdown_timeout; |
1321 | + apr_time_t deadlock_timeout; |
1322 | + apr_time_t inactivity_timeout; |
1323 | + const char *display_name; |
1324 | + int send_buffer_size; |
1325 | + int recv_buffer_size; |
1326 | + const char *script_user; |
1327 | + const char *script_group; |
1328 | + int cpu_time_limit; |
1329 | + int cpu_priority; |
1330 | + const char *socket; |
1331 | + int listener_fd; |
1332 | + const char* mutex_path; |
1333 | + apr_proc_mutex_t* mutex; |
1334 | +} WSGIProcessGroup; |
1335 | + |
1336 | +typedef struct { |
1337 | + WSGIProcessGroup *group; |
1338 | + int instance; |
1339 | + apr_proc_t process; |
1340 | + apr_socket_t *listener; |
1341 | +} WSGIDaemonProcess; |
1342 | + |
1343 | +typedef struct { |
1344 | + int id; |
1345 | + WSGIDaemonProcess *process; |
1346 | + apr_thread_t *thread; |
1347 | + int running; |
1348 | + int next; |
1349 | + int wakeup; |
1350 | + apr_thread_cond_t *condition; |
1351 | + apr_thread_mutex_t *mutex; |
1352 | +} WSGIDaemonThread; |
1353 | + |
1354 | +typedef struct { |
1355 | + apr_uint32_t state; |
1356 | +} WSGIThreadStack; |
1357 | + |
1358 | +typedef struct { |
1359 | + const char *name; |
1360 | + const char *socket; |
1361 | + int fd; |
1362 | +} WSGIDaemonSocket; |
1363 | + |
1364 | +static int wsgi_daemon_count = 0; |
1365 | +static apr_hash_t *wsgi_daemon_index = NULL; |
1366 | +static apr_hash_t *wsgi_daemon_listeners = NULL; |
1367 | + |
1368 | +static WSGIDaemonProcess *wsgi_daemon_process = NULL; |
1369 | + |
1370 | +static int volatile wsgi_request_count = 0; |
1371 | + |
1372 | +static WSGIDaemonThread *wsgi_worker_threads = NULL; |
1373 | + |
1374 | +static WSGIThreadStack *wsgi_worker_stack = NULL; |
1375 | + |
1376 | +#endif |
1377 | + |
1378 | +/* Class objects used by response handler. */ |
1379 | + |
1380 | +static PyTypeObject Dispatch_Type; |
1381 | + |
1382 | +typedef struct { |
1383 | + PyObject_HEAD |
1384 | + const char *target; |
1385 | + request_rec *r; |
1386 | + int level; |
1387 | + char *s; |
1388 | + int l; |
1389 | + int expired; |
1390 | +#if PY_MAJOR_VERSION < 3 |
1391 | + int softspace; |
1392 | +#endif |
1393 | +} LogObject; |
1394 | + |
1395 | +static PyTypeObject Log_Type; |
1396 | + |
1397 | +static PyObject *newLogObject(request_rec *r, int level, const char *target) |
1398 | +{ |
1399 | + LogObject *self; |
1400 | + |
1401 | +#if PY_MAJOR_VERSION >= 3 |
1402 | + PyObject *module = NULL; |
1403 | + PyObject *dict = NULL; |
1404 | + PyObject *object = NULL; |
1405 | + PyObject *args = NULL; |
1406 | + PyObject *result = NULL; |
1407 | + |
1408 | + module = PyImport_ImportModule("io"); |
1409 | + |
1410 | + if (!module) |
1411 | + return NULL; |
1412 | + |
1413 | + dict = PyModule_GetDict(module); |
1414 | + object = PyDict_GetItemString(dict, "TextIOWrapper"); |
1415 | + |
1416 | + if (!object) { |
1417 | + PyErr_SetString(PyExc_NameError, |
1418 | + "name 'TextIOWrapper' is not defined"); |
1419 | + return NULL; |
1420 | + } |
1421 | +#endif |
1422 | + |
1423 | + self = PyObject_New(LogObject, &Log_Type); |
1424 | + if (self == NULL) |
1425 | + return NULL; |
1426 | + |
1427 | + self->target = target; |
1428 | + self->r = r; |
1429 | + self->level = APLOG_NOERRNO|level; |
1430 | + self->s = NULL; |
1431 | + self->l = 0; |
1432 | + self->expired = 0; |
1433 | +#if PY_MAJOR_VERSION < 3 |
1434 | + self->softspace = 0; |
1435 | +#endif |
1436 | + |
1437 | +#if PY_MAJOR_VERSION >= 3 |
1438 | + Py_INCREF(object); |
1439 | + args = Py_BuildValue("(OssOO)", self, "utf-8", "replace", |
1440 | + Py_None, Py_True); |
1441 | + Py_DECREF(self); |
1442 | + result = PyEval_CallObject(object, args); |
1443 | + Py_DECREF(args); |
1444 | + Py_DECREF(object); |
1445 | + |
1446 | + return result; |
1447 | +#else |
1448 | + return (PyObject *)self; |
1449 | +#endif |
1450 | +} |
1451 | + |
1452 | +#if 0 |
1453 | +static void Log_file(LogObject *self, const char *s, int l) |
1454 | +{ |
1455 | + /* |
1456 | + * XXX This function is not currently being used. |
1457 | + * The intention was that it be called instead of |
1458 | + * Log_call() when 'target' is non zero. This would |
1459 | + * be the case for 'stdout' and 'stderr'. Doing |
1460 | + * this bypasses normally Apache logging mechanisms |
1461 | + * though. May reawaken this code in mod_wsgi 4.0 |
1462 | + * by way of a mechanism to divert logging from a |
1463 | + * daemon process to specfic log file or pipe using |
1464 | + * an option to WSGIDaemonProcess. |
1465 | + */ |
1466 | + |
1467 | + char errstr[MAX_STRING_LEN]; |
1468 | + |
1469 | + int plen = 0; |
1470 | + int slen = 0; |
1471 | + |
1472 | +#if AP_SERVER_MAJORVERSION_NUMBER < 2 |
1473 | + FILE *logf; |
1474 | +#else |
1475 | + apr_file_t *logf = NULL; |
1476 | +#endif |
1477 | + |
1478 | + if (self->r) |
1479 | + logf = self->r->server->error_log; |
1480 | + else |
1481 | + logf = wsgi_server->error_log; |
1482 | + |
1483 | +#if AP_SERVER_MAJORVERSION_NUMBER < 2 |
1484 | + plen = ap_snprintf(errstr, sizeof(errstr), "[%s] ", ap_get_time()); |
1485 | +#else |
1486 | + errstr[0] = '['; |
1487 | + ap_recent_ctime(errstr + 1, apr_time_now()); |
1488 | + errstr[1 + APR_CTIME_LEN - 1] = ']'; |
1489 | + errstr[1 + APR_CTIME_LEN ] = ' '; |
1490 | + plen = 1 + APR_CTIME_LEN + 1; |
1491 | +#endif |
1492 | + |
1493 | + if (self->target) { |
1494 | + int len; |
1495 | + |
1496 | + errstr[plen++] = '['; |
1497 | + |
1498 | + len = strlen(self->target); |
1499 | + memcpy(errstr+plen, self->target, len); |
1500 | + |
1501 | + plen += len; |
1502 | + |
1503 | + errstr[plen++] = ']'; |
1504 | + errstr[plen++] = ' '; |
1505 | + } |
1506 | + |
1507 | + slen = MAX_STRING_LEN - plen - 1; |
1508 | + |
1509 | + Py_BEGIN_ALLOW_THREADS |
1510 | + |
1511 | + /* |
1512 | + * We actually break long lines up into segments |
1513 | + * of around 8192 characters, with the date/time |
1514 | + * and target information prefixing each line. |
1515 | + * This is just to avoid having to allocate more |
1516 | + * memory just to format the line with prefix. |
1517 | + * We want to avoid writing the prefix separately |
1518 | + * so at least try and write line in one atomic |
1519 | + * operation. |
1520 | + */ |
1521 | + |
1522 | + while (1) { |
1523 | + if (l > slen) { |
1524 | + memcpy(errstr+plen, s, slen); |
1525 | + errstr[plen+slen] = '\n'; |
1526 | +#if AP_SERVER_MAJORVERSION_NUMBER < 2 |
1527 | + fwrite(errstr, plen+slen+1, 1, logf); |
1528 | + fflush(logf); |
1529 | +#else |
1530 | + apr_file_write_full(logf, errstr, plen+slen+1, NULL); |
1531 | + apr_file_flush(logf); |
1532 | +#endif |
1533 | + s += slen; |
1534 | + l -= slen; |
1535 | + } |
1536 | + else { |
1537 | + memcpy(errstr+plen, s, l); |
1538 | + errstr[plen+l] = '\n'; |
1539 | +#if AP_SERVER_MAJORVERSION_NUMBER < 2 |
1540 | + fwrite(errstr, plen+l+1, 1, logf); |
1541 | + fflush(logf); |
1542 | +#else |
1543 | + apr_file_write_full(logf, errstr, plen+l+1, NULL); |
1544 | + apr_file_flush(logf); |
1545 | +#endif |
1546 | + break; |
1547 | + } |
1548 | + } |
1549 | + |
1550 | + Py_END_ALLOW_THREADS |
1551 | +} |
1552 | +#endif |
1553 | + |
1554 | +static void Log_call(LogObject *self, const char *s, int l) |
1555 | +{ |
1556 | + /* |
1557 | + * The length of the string to be logged is ignored |
1558 | + * for now. We just pass the whole string to the |
1559 | + * Apache error log functions. It will actually |
1560 | + * truncate it at some value less than 8192 |
1561 | + * characters depending on the length of the prefix |
1562 | + * to go at the front. If there are embedded NULLs |
1563 | + * then truncation will occur at that point. That |
1564 | + * truncation occurs like this is also what happens |
1565 | + * if using FASTCGI solutions for Apache, so not |
1566 | + * doing anything different here. |
1567 | + */ |
1568 | + |
1569 | + if (self->r) { |
1570 | + Py_BEGIN_ALLOW_THREADS |
1571 | + ap_log_rerror(APLOG_MARK, WSGI_LOG_LEVEL(self->level), |
1572 | + self->r, "%s", s); |
1573 | + Py_END_ALLOW_THREADS |
1574 | + } |
1575 | + else { |
1576 | + Py_BEGIN_ALLOW_THREADS |
1577 | + ap_log_error(APLOG_MARK, WSGI_LOG_LEVEL(self->level), |
1578 | + wsgi_server, "%s", s); |
1579 | + Py_END_ALLOW_THREADS |
1580 | + } |
1581 | +} |
1582 | + |
1583 | +static void Log_dealloc(LogObject *self) |
1584 | +{ |
1585 | + if (self->s) { |
1586 | + if (!self->expired) |
1587 | + Log_call(self, self->s, self->l); |
1588 | + |
1589 | + free(self->s); |
1590 | + } |
1591 | + |
1592 | + PyObject_Del(self); |
1593 | +} |
1594 | + |
1595 | +static PyObject *Log_flush(LogObject *self, PyObject *args) |
1596 | +{ |
1597 | + if (self->expired) { |
1598 | + PyErr_SetString(PyExc_RuntimeError, "log object has expired"); |
1599 | + return NULL; |
1600 | + } |
1601 | + |
1602 | + if (!PyArg_ParseTuple(args, ":flush")) |
1603 | + return NULL; |
1604 | + |
1605 | + if (self->s) { |
1606 | + Log_call(self, self->s, self->l); |
1607 | + |
1608 | + free(self->s); |
1609 | + self->s = NULL; |
1610 | + self->l = 0; |
1611 | + } |
1612 | + |
1613 | + Py_INCREF(Py_None); |
1614 | + return Py_None; |
1615 | +} |
1616 | + |
1617 | +static PyObject *Log_close(LogObject *self, PyObject *args) |
1618 | +{ |
1619 | + PyObject *result = NULL; |
1620 | + |
1621 | + if (!PyArg_ParseTuple(args, ":close")) |
1622 | + return NULL; |
1623 | + |
1624 | + if (!self->expired) |
1625 | + result = Log_flush(self, args); |
1626 | + |
1627 | + Py_XDECREF(result); |
1628 | + |
1629 | + self->r = NULL; |
1630 | + self->expired = 1; |
1631 | + |
1632 | + Py_INCREF(Py_None); |
1633 | + return Py_None; |
1634 | +} |
1635 | + |
1636 | +static PyObject *Log_isatty(LogObject *self, PyObject *args) |
1637 | +{ |
1638 | + PyObject *result = NULL; |
1639 | + |
1640 | + if (!PyArg_ParseTuple(args, ":isatty")) |
1641 | + return NULL; |
1642 | + |
1643 | + Py_INCREF(Py_False); |
1644 | + return Py_False; |
1645 | +} |
1646 | + |
1647 | +static void Log_queue(LogObject *self, const char *msg, int len) |
1648 | +{ |
1649 | + const char *p = NULL; |
1650 | + const char *q = NULL; |
1651 | + const char *e = NULL; |
1652 | + |
1653 | + p = msg; |
1654 | + e = p + len; |
1655 | + |
1656 | + /* |
1657 | + * Break string on newline. This is on assumption |
1658 | + * that primarily textual information being logged. |
1659 | + */ |
1660 | + |
1661 | + q = p; |
1662 | + while (q != e) { |
1663 | + if (*q == '\n') |
1664 | + break; |
1665 | + q++; |
1666 | + } |
1667 | + |
1668 | + while (q != e) { |
1669 | + /* Output each complete line. */ |
1670 | + |
1671 | + if (self->s) { |
1672 | + /* Need to join with buffered value. */ |
1673 | + |
1674 | + int m = 0; |
1675 | + int n = 0; |
1676 | + char *s = NULL; |
1677 | + |
1678 | + m = self->l; |
1679 | + n = m+q-p+1; |
1680 | + |
1681 | + s = (char *)malloc(n); |
1682 | + memcpy(s, self->s, m); |
1683 | + memcpy(s+m, p, q-p); |
1684 | + s[n-1] = '\0'; |
1685 | + |
1686 | + free(self->s); |
1687 | + self->s = NULL; |
1688 | + self->l = 0; |
1689 | + |
1690 | + Log_call(self, s, n-1); |
1691 | + |
1692 | + free(s); |
1693 | + } |
1694 | + else { |
1695 | + int n = 0; |
1696 | + char *s = NULL; |
1697 | + |
1698 | + n = q-p+1; |
1699 | + |
1700 | + s = (char *)malloc(n); |
1701 | + memcpy(s, p, q-p); |
1702 | + s[n-1] = '\0'; |
1703 | + |
1704 | + Log_call(self, s, n-1); |
1705 | + |
1706 | + free(s); |
1707 | + } |
1708 | + |
1709 | + p = q+1; |
1710 | + |
1711 | + /* Break string on newline. */ |
1712 | + |
1713 | + q = p; |
1714 | + while (q != e) { |
1715 | + if (*q == '\n') |
1716 | + break; |
1717 | + q++; |
1718 | + } |
1719 | + } |
1720 | + |
1721 | + if (p != e) { |
1722 | + /* Save away incomplete line. */ |
1723 | + |
1724 | + if (self->s) { |
1725 | + /* Need to join with buffered value. */ |
1726 | + |
1727 | + int m = 0; |
1728 | + int n = 0; |
1729 | + |
1730 | + m = self->l; |
1731 | + n = m+e-p+1; |
1732 | + |
1733 | + self->s = (char *)realloc(self->s, n); |
1734 | + memcpy(self->s+m, p, e-p); |
1735 | + self->s[n-1] = '\0'; |
1736 | + self->l = n-1; |
1737 | + } |
1738 | + else { |
1739 | + int n = 0; |
1740 | + |
1741 | + n = e-p+1; |
1742 | + |
1743 | + self->s = (char *)malloc(n); |
1744 | + memcpy(self->s, p, n-1); |
1745 | + self->s[n-1] = '\0'; |
1746 | + self->l = n-1; |
1747 | + } |
1748 | + } |
1749 | +} |
1750 | + |
1751 | +static PyObject *Log_write(LogObject *self, PyObject *args) |
1752 | +{ |
1753 | + const char *msg = NULL; |
1754 | + int len = -1; |
1755 | + |
1756 | + if (self->expired) { |
1757 | + PyErr_SetString(PyExc_RuntimeError, "log object has expired"); |
1758 | + return NULL; |
1759 | + } |
1760 | + |
1761 | + if (!PyArg_ParseTuple(args, "s#:write", &msg, &len)) |
1762 | + return NULL; |
1763 | + |
1764 | + Log_queue(self, msg, len); |
1765 | + |
1766 | + Py_INCREF(Py_None); |
1767 | + return Py_None; |
1768 | +} |
1769 | + |
1770 | +static PyObject *Log_writelines(LogObject *self, PyObject *args) |
1771 | +{ |
1772 | + PyObject *sequence = NULL; |
1773 | + PyObject *iterator = NULL; |
1774 | + PyObject *item = NULL; |
1775 | + const char *msg = NULL; |
1776 | + |
1777 | + if (self->expired) { |
1778 | + PyErr_SetString(PyExc_RuntimeError, "log object has expired"); |
1779 | + return NULL; |
1780 | + } |
1781 | + |
1782 | + if (!PyArg_ParseTuple(args, "O:writelines", &sequence)) |
1783 | + return NULL; |
1784 | + |
1785 | + iterator = PyObject_GetIter(sequence); |
1786 | + |
1787 | + if (iterator == NULL) { |
1788 | + PyErr_SetString(PyExc_TypeError, |
1789 | + "argument must be sequence of strings"); |
1790 | + |
1791 | + return NULL; |
1792 | + } |
1793 | + |
1794 | + while ((item = PyIter_Next(iterator))) { |
1795 | + PyObject *result = NULL; |
1796 | + |
1797 | + result = Log_write(self, item); |
1798 | + |
1799 | + if (!result) { |
1800 | + Py_DECREF(iterator); |
1801 | + |
1802 | + PyErr_SetString(PyExc_TypeError, |
1803 | + "argument must be sequence of strings"); |
1804 | + |
1805 | + return NULL; |
1806 | + } |
1807 | + } |
1808 | + |
1809 | + Py_DECREF(iterator); |
1810 | + |
1811 | + Py_INCREF(Py_None); |
1812 | + return Py_None; |
1813 | +} |
1814 | + |
1815 | +#if PY_MAJOR_VERSION >= 3 |
1816 | +static PyObject *Log_readable(LogObject *self, PyObject *args) |
1817 | +{ |
1818 | + if (!PyArg_ParseTuple(args, ":readable")) |
1819 | + return NULL; |
1820 | + |
1821 | + Py_INCREF(Py_False); |
1822 | + return Py_False; |
1823 | +} |
1824 | + |
1825 | +static PyObject *Log_seekable(LogObject *self, PyObject *args) |
1826 | +{ |
1827 | + if (!PyArg_ParseTuple(args, ":seekable")) |
1828 | + return NULL; |
1829 | + |
1830 | + Py_INCREF(Py_False); |
1831 | + return Py_False; |
1832 | +} |
1833 | + |
1834 | +static PyObject *Log_writable(LogObject *self, PyObject *args) |
1835 | +{ |
1836 | + if (!PyArg_ParseTuple(args, ":writable")) |
1837 | + return NULL; |
1838 | + |
1839 | + Py_INCREF(Py_True); |
1840 | + return Py_True; |
1841 | +} |
1842 | +#endif |
1843 | + |
1844 | +static PyObject *Log_closed(LogObject *self, void *closure) |
1845 | +{ |
1846 | + Py_INCREF(Py_False); |
1847 | + return Py_False; |
1848 | +} |
1849 | + |
1850 | +#if PY_MAJOR_VERSION < 3 |
1851 | +static PyObject *Log_get_softspace(LogObject *self, void *closure) |
1852 | +{ |
1853 | + return PyInt_FromLong(self->softspace); |
1854 | +} |
1855 | + |
1856 | +static int Log_set_softspace(LogObject *self, PyObject *value) |
1857 | +{ |
1858 | + int new; |
1859 | + |
1860 | + if (value == NULL) { |
1861 | + PyErr_SetString(PyExc_TypeError, "can't delete softspace attribute"); |
1862 | + return -1; |
1863 | + } |
1864 | + |
1865 | + new = PyInt_AsLong(value); |
1866 | + if (new == -1 && PyErr_Occurred()) |
1867 | + return -1; |
1868 | + |
1869 | + self->softspace = new; |
1870 | + |
1871 | + return 0; |
1872 | +} |
1873 | + |
1874 | +#else |
1875 | + |
1876 | +static PyObject *Log_get_encoding(LogObject *self, void *closure) |
1877 | +{ |
1878 | + return PyUnicode_FromString("utf-8"); |
1879 | +} |
1880 | + |
1881 | +static PyObject *Log_get_errors(LogObject *self, void *closure) |
1882 | +{ |
1883 | + return PyUnicode_FromString("replace"); |
1884 | +} |
1885 | +#endif |
1886 | + |
1887 | +static PyMethodDef Log_methods[] = { |
1888 | + { "flush", (PyCFunction)Log_flush, METH_VARARGS, 0 }, |
1889 | + { "close", (PyCFunction)Log_close, METH_VARARGS, 0 }, |
1890 | + { "isatty", (PyCFunction)Log_isatty, METH_VARARGS, 0 }, |
1891 | + { "write", (PyCFunction)Log_write, METH_VARARGS, 0 }, |
1892 | + { "writelines", (PyCFunction)Log_writelines, METH_VARARGS, 0 }, |
1893 | +#if PY_MAJOR_VERSION >= 3 |
1894 | + { "readable", (PyCFunction)Log_readable, METH_VARARGS, 0 }, |
1895 | + { "seekable", (PyCFunction)Log_seekable, METH_VARARGS, 0 }, |
1896 | + { "writable", (PyCFunction)Log_writable, METH_VARARGS, 0 }, |
1897 | +#endif |
1898 | + { NULL, NULL} |
1899 | +}; |
1900 | + |
1901 | +static PyGetSetDef Log_getset[] = { |
1902 | + { "closed", (getter)Log_closed, NULL, 0 }, |
1903 | +#if PY_MAJOR_VERSION < 3 |
1904 | + { "softspace", (getter)Log_get_softspace, (setter)Log_set_softspace, 0 }, |
1905 | +#else |
1906 | + { "encoding", (getter)Log_get_encoding, NULL, 0 }, |
1907 | + { "errors", (getter)Log_get_errors, NULL, 0 }, |
1908 | +#endif |
1909 | + { NULL }, |
1910 | +}; |
1911 | + |
1912 | +static PyTypeObject Log_Type = { |
1913 | + PyVarObject_HEAD_INIT(NULL, 0) |
1914 | + "mod_wsgi.Log", /*tp_name*/ |
1915 | + sizeof(LogObject), /*tp_basicsize*/ |
1916 | + 0, /*tp_itemsize*/ |
1917 | + /* methods */ |
1918 | + (destructor)Log_dealloc, /*tp_dealloc*/ |
1919 | + 0, /*tp_print*/ |
1920 | + 0, /*tp_getattr*/ |
1921 | + 0, /*tp_setattr*/ |
1922 | + 0, /*tp_compare*/ |
1923 | + 0, /*tp_repr*/ |
1924 | + 0, /*tp_as_number*/ |
1925 | + 0, /*tp_as_sequence*/ |
1926 | + 0, /*tp_as_mapping*/ |
1927 | + 0, /*tp_hash*/ |
1928 | + 0, /*tp_call*/ |
1929 | + 0, /*tp_str*/ |
1930 | + 0, /*tp_getattro*/ |
1931 | + 0, /*tp_setattro*/ |
1932 | + 0, /*tp_as_buffer*/ |
1933 | + Py_TPFLAGS_DEFAULT, /*tp_flags*/ |
1934 | + 0, /*tp_doc*/ |
1935 | + 0, /*tp_traverse*/ |
1936 | + 0, /*tp_clear*/ |
1937 | + 0, /*tp_richcompare*/ |
1938 | + 0, /*tp_weaklistoffset*/ |
1939 | + 0, /*tp_iter*/ |
1940 | + 0, /*tp_iternext*/ |
1941 | + Log_methods, /*tp_methods*/ |
1942 | + 0, /*tp_members*/ |
1943 | + Log_getset, /*tp_getset*/ |
1944 | + 0, /*tp_base*/ |
1945 | + 0, /*tp_dict*/ |
1946 | + 0, /*tp_descr_get*/ |
1947 | + 0, /*tp_descr_set*/ |
1948 | + 0, /*tp_dictoffset*/ |
1949 | + 0, /*tp_init*/ |
1950 | + 0, /*tp_alloc*/ |
1951 | + 0, /*tp_new*/ |
1952 | + 0, /*tp_free*/ |
1953 | + 0, /*tp_is_gc*/ |
1954 | +}; |
1955 | + |
1956 | +static void wsgi_log_python_error(request_rec *r, PyObject *log, |
1957 | + const char *filename) |
1958 | +{ |
1959 | + PyObject *m = NULL; |
1960 | + PyObject *result = NULL; |
1961 | + |
1962 | + PyObject *type = NULL; |
1963 | + PyObject *value = NULL; |
1964 | + PyObject *traceback = NULL; |
1965 | + |
1966 | + PyObject *xlog = NULL; |
1967 | + |
1968 | + if (!PyErr_Occurred()) |
1969 | + return; |
1970 | + |
1971 | + if (!log) { |
1972 | + PyErr_Fetch(&type, &value, &traceback); |
1973 | + |
1974 | + xlog = newLogObject(r, APLOG_ERR, NULL); |
1975 | + |
1976 | + log = xlog; |
1977 | + |
1978 | + PyErr_Restore(type, value, traceback); |
1979 | + |
1980 | + type = NULL; |
1981 | + value = NULL; |
1982 | + traceback = NULL; |
1983 | + } |
1984 | + |
1985 | + if (PyErr_ExceptionMatches(PyExc_SystemExit)) { |
1986 | + Py_BEGIN_ALLOW_THREADS |
1987 | + if (r) { |
1988 | + ap_log_rerror(APLOG_MARK, WSGI_LOG_ERR(0), r, |
1989 | + "mod_wsgi (pid=%d): SystemExit exception raised by " |
1990 | + "WSGI script '%s' ignored.", getpid(), filename); |
1991 | + } |
1992 | + else { |
1993 | + ap_log_error(APLOG_MARK, WSGI_LOG_ERR(0), wsgi_server, |
1994 | + "mod_wsgi (pid=%d): SystemExit exception raised by " |
1995 | + "WSGI script '%s' ignored.", getpid(), filename); |
1996 | + } |
1997 | + Py_END_ALLOW_THREADS |
1998 | + } |
1999 | + else { |
2000 | + Py_BEGIN_ALLOW_THREADS |
2001 | + if (r) { |
2002 | + ap_log_rerror(APLOG_MARK, WSGI_LOG_ERR(0), r, |
2003 | + "mod_wsgi (pid=%d): Exception occurred processing " |
2004 | + "WSGI script '%s'.", getpid(), filename); |
2005 | + } |
2006 | + else { |
2007 | + ap_log_error(APLOG_MARK, WSGI_LOG_ERR(0), wsgi_server, |
2008 | + "mod_wsgi (pid=%d): Exception occurred processing " |
2009 | + "WSGI script '%s'.", getpid(), filename); |
2010 | + } |
2011 | + Py_END_ALLOW_THREADS |
2012 | + } |
2013 | + |
2014 | + PyErr_Fetch(&type, &value, &traceback); |
2015 | + PyErr_NormalizeException(&type, &value, &traceback); |
2016 | + |
2017 | + if (!value) { |
2018 | + value = Py_None; |
2019 | + Py_INCREF(value); |
2020 | + } |
2021 | + |
2022 | + if (!traceback) { |
2023 | + traceback = Py_None; |
2024 | + Py_INCREF(traceback); |
2025 | + } |
2026 | + |
2027 | + m = PyImport_ImportModule("traceback"); |
2028 | + |
2029 | + if (m) { |
2030 | + PyObject *d = NULL; |
2031 | + PyObject *o = NULL; |
2032 | + d = PyModule_GetDict(m); |
2033 | + o = PyDict_GetItemString(d, "print_exception"); |
2034 | + if (o) { |
2035 | + PyObject *args = NULL; |
2036 | + Py_INCREF(o); |
2037 | + args = Py_BuildValue("(OOOOO)", type, value, traceback, |
2038 | + Py_None, log); |
2039 | + result = PyEval_CallObject(o, args); |
2040 | + Py_DECREF(args); |
2041 | + Py_DECREF(o); |
2042 | + } |
2043 | + } |
2044 | + |
2045 | + if (!result) { |
2046 | + /* |
2047 | + * If can't output exception and traceback then |
2048 | + * use PyErr_Print to dump out details of the |
2049 | + * exception. For SystemExit though if we do |
2050 | + * that the process will actually be terminated |
2051 | + * so can only clear the exception information |
2052 | + * and keep going. |
2053 | + */ |
2054 | + |
2055 | + PyErr_Restore(type, value, traceback); |
2056 | + |
2057 | + if (!PyErr_ExceptionMatches(PyExc_SystemExit)) { |
2058 | + PyErr_Print(); |
2059 | + PyErr_Clear(); |
2060 | + } |
2061 | + else { |
2062 | + PyErr_Clear(); |
2063 | + } |
2064 | + } |
2065 | + else { |
2066 | + Py_XDECREF(type); |
2067 | + Py_XDECREF(value); |
2068 | + Py_XDECREF(traceback); |
2069 | + } |
2070 | + |
2071 | + Py_XDECREF(result); |
2072 | + |
2073 | + Py_XDECREF(m); |
2074 | + |
2075 | + Py_XDECREF(xlog); |
2076 | +} |
2077 | + |
2078 | +typedef struct { |
2079 | + PyObject_HEAD |
2080 | + request_rec *r; |
2081 | + int init; |
2082 | + int done; |
2083 | + char *buffer; |
2084 | + apr_size_t size; |
2085 | + apr_size_t offset; |
2086 | + apr_size_t length; |
2087 | +} InputObject; |
2088 | + |
2089 | +static PyTypeObject Input_Type; |
2090 | + |
2091 | +static InputObject *newInputObject(request_rec *r) |
2092 | +{ |
2093 | + InputObject *self; |
2094 | + |
2095 | + self = PyObject_New(InputObject, &Input_Type); |
2096 | + if (self == NULL) |
2097 | + return NULL; |
2098 | + |
2099 | + self->r = r; |
2100 | + self->init = 0; |
2101 | + self->done = 0; |
2102 | + |
2103 | + self->buffer = NULL; |
2104 | + self->size = 0; |
2105 | + self->offset = 0; |
2106 | + self->length = 0; |
2107 | + |
2108 | + return self; |
2109 | +} |
2110 | + |
2111 | +static void Input_dealloc(InputObject *self) |
2112 | +{ |
2113 | + if (self->buffer) |
2114 | + free(self->buffer); |
2115 | + |
2116 | + PyObject_Del(self); |
2117 | +} |
2118 | + |
2119 | +static PyObject *Input_close(InputObject *self, PyObject *args) |
2120 | +{ |
2121 | + if (!self->r) { |
2122 | + PyErr_SetString(PyExc_RuntimeError, "request object has expired"); |
2123 | + return NULL; |
2124 | + } |
2125 | + |
2126 | + if (!PyArg_ParseTuple(args, ":close")) |
2127 | + return NULL; |
2128 | + |
2129 | + Py_INCREF(Py_None); |
2130 | + return Py_None; |
2131 | +} |
2132 | + |
2133 | +static PyObject *Input_read(InputObject *self, PyObject *args) |
2134 | +{ |
2135 | + long size = -1; |
2136 | + |
2137 | + PyObject *result = NULL; |
2138 | + char *buffer = NULL; |
2139 | + apr_size_t length = 0; |
2140 | + int init = 0; |
2141 | + |
2142 | + apr_size_t n; |
2143 | + |
2144 | + if (!self->r) { |
2145 | + PyErr_SetString(PyExc_RuntimeError, "request object has expired"); |
2146 | + return NULL; |
2147 | + } |
2148 | + |
2149 | + if (!PyArg_ParseTuple(args, "|l:read", &size)) |
2150 | + return NULL; |
2151 | + |
2152 | +#if defined(MOD_WSGI_WITH_DAEMONS) |
2153 | + if (wsgi_inactivity_timeout) { |
2154 | + apr_thread_mutex_lock(wsgi_shutdown_lock); |
2155 | + wsgi_inactivity_shutdown_time = apr_time_now(); |
2156 | + wsgi_inactivity_shutdown_time += wsgi_inactivity_timeout; |
2157 | + apr_thread_mutex_unlock(wsgi_shutdown_lock); |
2158 | + } |
2159 | +#endif |
2160 | + |
2161 | + init = self->init; |
2162 | + |
2163 | + if (!self->init) { |
2164 | + if (!ap_should_client_block(self->r)) |
2165 | + self->done = 1; |
2166 | + |
2167 | + self->init = 1; |
2168 | + } |
2169 | + |
2170 | + /* No point continuing if no more data to be consumed. */ |
2171 | + |
2172 | + if (self->done && self->length == 0) |
2173 | + return PyString_FromString(""); |
2174 | + |
2175 | + /* |
2176 | + * If requested size is zero bytes, then still need to pass |
2177 | + * this through to Apache input filters so that any |
2178 | + * 100-continue response is triggered. Only do this if very |
2179 | + * first attempt to read data. Note that this will cause an |
2180 | + * assertion failure in HTTP_IN input filter when Apache |
2181 | + * maintainer mode is enabled. It is arguable that the |
2182 | + * assertion check, which prohibits a zero length read, |
2183 | + * shouldn't exist, as why should a zero length read be not |
2184 | + * allowed if input filter processing still works when it |
2185 | + * does occur. |
2186 | + */ |
2187 | + |
2188 | + if (size == 0) { |
2189 | + if (!init) { |
2190 | + char dummy[1]; |
2191 | + |
2192 | + Py_BEGIN_ALLOW_THREADS |
2193 | + n = ap_get_client_block(self->r, dummy, 0); |
2194 | + Py_END_ALLOW_THREADS |
2195 | + |
2196 | + if (n == -1) { |
2197 | + PyErr_SetString(PyExc_IOError, "request data read error"); |
2198 | + return NULL; |
2199 | + } |
2200 | + } |
2201 | + |
2202 | + return PyString_FromString(""); |
2203 | + } |
2204 | + |
2205 | + /* |
2206 | + * First deal with case where size has been specified. After |
2207 | + * that deal with case where expected that all remaining |
2208 | + * data is to be read in and returned as one string. |
2209 | + */ |
2210 | + |
2211 | + if (size > 0) { |
2212 | + /* Allocate string of the exact size required. */ |
2213 | + |
2214 | + result = PyString_FromStringAndSize(NULL, size); |
2215 | + |
2216 | + if (!result) |
2217 | + return NULL; |
2218 | + |
2219 | + buffer = PyString_AS_STRING((PyStringObject *)result); |
2220 | + |
2221 | + /* Copy any residual data from use of readline(). */ |
2222 | + |
2223 | + if (self->buffer && self->length) { |
2224 | + if (size >= self->length) { |
2225 | + length = self->length; |
2226 | + memcpy(buffer, self->buffer + self->offset, length); |
2227 | + self->offset = 0; |
2228 | + self->length = 0; |
2229 | + } |
2230 | + else { |
2231 | + length = size; |
2232 | + memcpy(buffer, self->buffer + self->offset, length); |
2233 | + self->offset += length; |
2234 | + self->length -= length; |
2235 | + } |
2236 | + } |
2237 | + |
2238 | + /* If all data residual buffer consumed then free it. */ |
2239 | + |
2240 | + if (!self->length) { |
2241 | + free(self->buffer); |
2242 | + self->buffer = NULL; |
2243 | + } |
2244 | + |
2245 | + /* Read in remaining data required to achieve size. */ |
2246 | + |
2247 | + if (length < size) { |
2248 | + while (length != size) { |
2249 | + Py_BEGIN_ALLOW_THREADS |
2250 | + n = ap_get_client_block(self->r, buffer + length, |
2251 | + size - length); |
2252 | + Py_END_ALLOW_THREADS |
2253 | + |
2254 | + if (n == -1) { |
2255 | + PyErr_SetString(PyExc_IOError, "request data read error"); |
2256 | + Py_DECREF(result); |
2257 | + return NULL; |
2258 | + } |
2259 | + else if (n == 0) { |
2260 | + /* Have exhausted all the available input data. */ |
2261 | + |
2262 | + self->done = 1; |
2263 | + break; |
2264 | + } |
2265 | + |
2266 | + length += n; |
2267 | + } |
2268 | + |
2269 | + /* |
2270 | + * Resize the final string. If the size reduction is |
2271 | + * by more than 25% of the string size, then Python |
2272 | + * will allocate a new block of memory and copy the |
2273 | + * data into it. |
2274 | + */ |
2275 | + |
2276 | + if (length != size) { |
2277 | + if (_PyString_Resize(&result, length)) |
2278 | + return NULL; |
2279 | + } |
2280 | + } |
2281 | + } |
2282 | + else { |
2283 | + /* |
2284 | + * Here we are going to try and read in all the |
2285 | + * remaining data. First we have to allocate a suitably |
2286 | + * large string, but we can't fully trust the amount |
2287 | + * that the request structure says is remaining based on |
2288 | + * the original content length though, as an input |
2289 | + * filter can insert/remove data from the input stream |
2290 | + * thereby invalidating the original content length. |
2291 | + * What we do is allow for an extra 25% above what we |
2292 | + * have already buffered and what the request structure |
2293 | + * says is remaining. A value of 25% has been chosen so |
2294 | + * as to match best how Python handles resizing of |
2295 | + * strings. Note that even though we do this and allow |
2296 | + * all available content, strictly speaking the WSGI |
2297 | + * specification says we should only read up until content |
2298 | + * length. This though is because the WSGI specification |
2299 | + * is deficient in dealing with the concept of mutating |
2300 | + * input filters. Since read() with no argument is also |
2301 | + * not allowed by WSGI specification implement it in the |
2302 | + * way which is most logical and ensure that input data |
2303 | + * is not truncated. |
2304 | + */ |
2305 | + |
2306 | + size = self->length; |
2307 | + |
2308 | + if (!self->r->read_chunked && self->r->remaining > 0) |
2309 | + size += self->r->remaining; |
2310 | + |
2311 | + size = size + (size >> 2); |
2312 | + |
2313 | + if (size < 256) |
2314 | + size = self->r->read_chunked ? 8192 : 256; |
2315 | + |
2316 | + /* Allocate string of the estimated size. */ |
2317 | + |
2318 | + result = PyString_FromStringAndSize(NULL, size); |
2319 | + |
2320 | + if (!result) |
2321 | + return NULL; |
2322 | + |
2323 | + buffer = PyString_AS_STRING((PyStringObject *)result); |
2324 | + |
2325 | + /* |
2326 | + * Copy any residual data from use of readline(). The |
2327 | + * residual should always be less in size than the |
2328 | + * string we have allocated to hold it, so can consume |
2329 | + * all of it. |
2330 | + */ |
2331 | + |
2332 | + if (self->buffer && self->length) { |
2333 | + length = self->length; |
2334 | + memcpy(buffer, self->buffer + self->offset, length); |
2335 | + self->offset = 0; |
2336 | + self->length = 0; |
2337 | + |
2338 | + free(self->buffer); |
2339 | + self->buffer = NULL; |
2340 | + } |
2341 | + |
2342 | + /* Now make first attempt at reading remaining data. */ |
2343 | + |
2344 | + Py_BEGIN_ALLOW_THREADS |
2345 | + n = ap_get_client_block(self->r, buffer + length, size - length); |
2346 | + Py_END_ALLOW_THREADS |
2347 | + |
2348 | + if (n == -1) { |
2349 | + PyErr_SetString(PyExc_IOError, "request data read error"); |
2350 | + Py_DECREF(result); |
2351 | + return NULL; |
2352 | + } |
2353 | + else if (n == 0) { |
2354 | + /* Have exhausted all the available input data. */ |
2355 | + |
2356 | + self->done = 1; |
2357 | + } |
2358 | + |
2359 | + length += n; |
2360 | + |
2361 | + /* |
2362 | + * Don't just assume that all data has been read if |
2363 | + * amount read was less than that requested. Still must |
2364 | + * perform a read which returns that no more data found. |
2365 | + */ |
2366 | + |
2367 | + while (!self->done) { |
2368 | + if (length == size) { |
2369 | + /* Increase the size of the string by 25%. */ |
2370 | + |
2371 | + size = size + (size >> 2); |
2372 | + |
2373 | + if (_PyString_Resize(&result, size)) |
2374 | + return NULL; |
2375 | + |
2376 | + buffer = PyString_AS_STRING((PyStringObject *)result); |
2377 | + } |
2378 | + |
2379 | + /* Now make succesive attempt at reading data. */ |
2380 | + |
2381 | + Py_BEGIN_ALLOW_THREADS |
2382 | + n = ap_get_client_block(self->r, buffer + length, size - length); |
2383 | + Py_END_ALLOW_THREADS |
2384 | + |
2385 | + if (n == -1) { |
2386 | + PyErr_SetString(PyExc_IOError, "request data read error"); |
2387 | + Py_DECREF(result); |
2388 | + return NULL; |
2389 | + } |
2390 | + else if (n == 0) { |
2391 | + /* Have exhausted all the available input data. */ |
2392 | + |
2393 | + self->done = 1; |
2394 | + } |
2395 | + |
2396 | + length += n; |
2397 | + } |
2398 | + |
2399 | + /* |
2400 | + * Resize the final string. If the size reduction is by |
2401 | + * more than 25% of the string size, then Python will |
2402 | + * allocate a new block of memory and copy the data into |
2403 | + * it. |
2404 | + */ |
2405 | + |
2406 | + if (length != size) { |
2407 | + if (_PyString_Resize(&result, length)) |
2408 | + return NULL; |
2409 | + } |
2410 | + } |
2411 | + |
2412 | + return result; |
2413 | +} |
2414 | + |
2415 | +static PyObject *Input_readline(InputObject *self, PyObject *args) |
2416 | +{ |
2417 | + long size = -1; |
2418 | + |
2419 | + PyObject *result = NULL; |
2420 | + char *buffer = NULL; |
2421 | + apr_size_t length = 0; |
2422 | + |
2423 | + apr_size_t n; |
2424 | + |
2425 | + if (!self->r) { |
2426 | + PyErr_SetString(PyExc_RuntimeError, "request object has expired"); |
2427 | + return NULL; |
2428 | + } |
2429 | + |
2430 | + if (!PyArg_ParseTuple(args, "|l:readline", &size)) |
2431 | + return NULL; |
2432 | + |
2433 | + if (!self->init) { |
2434 | + if (!ap_should_client_block(self->r)) |
2435 | + self->done = 1; |
2436 | + |
2437 | + self->init = 1; |
2438 | + } |
2439 | + |
2440 | + /* |
2441 | + * No point continuing if requested size is zero or if no |
2442 | + * more data to read and no buffered data. |
2443 | + */ |
2444 | + |
2445 | + if ((self->done && self->length == 0) || size == 0) |
2446 | + return PyString_FromString(""); |
2447 | + |
2448 | + /* |
2449 | + * First deal with case where size has been specified. After |
2450 | + * that deal with case where expected that a complete line |
2451 | + * is returned regardless of the size. |
2452 | + */ |
2453 | + |
2454 | + if (size > 0) { |
2455 | + /* Allocate string of the exact size required. */ |
2456 | + |
2457 | + result = PyString_FromStringAndSize(NULL, size); |
2458 | + |
2459 | + if (!result) |
2460 | + return NULL; |
2461 | + |
2462 | + buffer = PyString_AS_STRING((PyStringObject *)result); |
2463 | + |
2464 | + /* Copy any residual data from use of readline(). */ |
2465 | + |
2466 | + if (self->buffer && self->length) { |
2467 | + char *p = NULL; |
2468 | + const char *q = NULL; |
2469 | + |
2470 | + p = buffer; |
2471 | + q = self->buffer + self->offset; |
2472 | + |
2473 | + while (self->length && length < size) { |
2474 | + self->offset++; |
2475 | + self->length--; |
2476 | + length++; |
2477 | + if ((*p++ = *q++) == '\n') |
2478 | + break; |
2479 | + } |
2480 | + |
2481 | + /* If all data in residual buffer consumed then free it. */ |
2482 | + |
2483 | + if (!self->length) { |
2484 | + free(self->buffer); |
2485 | + self->buffer = NULL; |
2486 | + } |
2487 | + } |
2488 | + |
2489 | + /* |
2490 | + * Read in remaining data required to achieve size. Note |
2491 | + * that can't just return whatever the first read might |
2492 | + * have returned if no EOL encountered as must return |
2493 | + * exactly the required size if no EOL unless that would |
2494 | + * have exhausted all input. |
2495 | + */ |
2496 | + |
2497 | + while ((!length || buffer[length-1] != '\n') && |
2498 | + !self->done && length < size) { |
2499 | + |
2500 | + char *p = NULL; |
2501 | + char *q = NULL; |
2502 | + |
2503 | + Py_BEGIN_ALLOW_THREADS |
2504 | + n = ap_get_client_block(self->r, buffer + length, size - length); |
2505 | + Py_END_ALLOW_THREADS |
2506 | + |
2507 | + if (n == -1) { |
2508 | + PyErr_SetString(PyExc_IOError, "request data read error"); |
2509 | + Py_DECREF(result); |
2510 | + return NULL; |
2511 | + } |
2512 | + else if (n == 0) { |
2513 | + /* Have exhausted all the available input data. */ |
2514 | + |
2515 | + self->done = 1; |
2516 | + } |
2517 | + else { |
2518 | + /* |
2519 | + * Search for embedded EOL in what was read and if |
2520 | + * found copy any residual into a buffer for use |
2521 | + * next time the read functions are called. |
2522 | + */ |
2523 | + |
2524 | + p = buffer + length; |
2525 | + q = p + n; |
2526 | + |
2527 | + while (p != q) { |
2528 | + length++; |
2529 | + if (*p++ == '\n') |
2530 | + break; |
2531 | + } |
2532 | + |
2533 | + if (p != q) { |
2534 | + self->size = q - p; |
2535 | + self->buffer = (char *)malloc(self->size); |
2536 | + self->offset = 0; |
2537 | + self->length = self->size; |
2538 | + |
2539 | + memcpy(self->buffer, p, self->size); |
2540 | + } |
2541 | + } |
2542 | + } |
2543 | + |
2544 | + /* |
2545 | + * Resize the final string. If the size reduction is |
2546 | + * by more than 25% of the string size, then Python |
2547 | + * will allocate a new block of memory and copy the |
2548 | + * data into it. |
2549 | + */ |
2550 | + |
2551 | + if (length != size) { |
2552 | + if (_PyString_Resize(&result, length)) |
2553 | + return NULL; |
2554 | + } |
2555 | + } |
2556 | + else { |
2557 | + /* |
2558 | + * Here we have to read in a line but where we have no |
2559 | + * idea how long it may be. What we can do first is if |
2560 | + * we have any residual data from a previous read |
2561 | + * operation, see if it contains an EOL. This means we |
2562 | + * have to do a search, but this is likely going to be |
2563 | + * better than having to resize and copy memory later on. |
2564 | + */ |
2565 | + |
2566 | + if (self->buffer && self->length) { |
2567 | + const char *p = NULL; |
2568 | + const char *q = NULL; |
2569 | + |
2570 | + p = self->buffer + self->offset; |
2571 | + q = memchr(p, '\n', self->length); |
2572 | + |
2573 | + if (q) |
2574 | + size = q - p; |
2575 | + } |
2576 | + |
2577 | + /* |
2578 | + * If residual data buffer didn't contain an EOL, all we |
2579 | + * can do is allocate a reasonably sized string and if |
2580 | + * that isn't big enough keep increasing it in size. For |
2581 | + * this we will start out with a buffer 25% greater in |
2582 | + * size than what is stored in the residual data buffer |
2583 | + * or one the same size as Apache string size, whichever |
2584 | + * is greater. |
2585 | + */ |
2586 | + |
2587 | + if (self->buffer && size < 0) { |
2588 | + size = self->length; |
2589 | + size = size + (size >> 2); |
2590 | + } |
2591 | + |
2592 | + if (size < HUGE_STRING_LEN) |
2593 | + size = HUGE_STRING_LEN; |
2594 | + |
2595 | + /* Allocate string of the initial size. */ |
2596 | + |
2597 | + result = PyString_FromStringAndSize(NULL, size); |
2598 | + |
2599 | + if (!result) |
2600 | + return NULL; |
2601 | + |
2602 | + buffer = PyString_AS_STRING((PyStringObject *)result); |
2603 | + |
2604 | + /* Copy any residual data from use of readline(). */ |
2605 | + |
2606 | + if (self->buffer && self->length) { |
2607 | + char *p = NULL; |
2608 | + const char *q = NULL; |
2609 | + |
2610 | + p = buffer; |
2611 | + q = self->buffer + self->offset; |
2612 | + |
2613 | + while (self->length && length < size) { |
2614 | + self->offset++; |
2615 | + self->length--; |
2616 | + length++; |
2617 | + if ((*p++ = *q++) == '\n') |
2618 | + break; |
2619 | + } |
2620 | + |
2621 | + /* If all data in residual buffer consumed then free it. */ |
2622 | + |
2623 | + if (!self->length) { |
2624 | + free(self->buffer); |
2625 | + self->buffer = NULL; |
2626 | + } |
2627 | + } |
2628 | + |
2629 | + /* |
2630 | + * Read in remaining data until find an EOL, or until all |
2631 | + * data has been consumed. |
2632 | + */ |
2633 | + |
2634 | + while ((!length || buffer[length-1] != '\n') && !self->done) { |
2635 | + |
2636 | + char *p = NULL; |
2637 | + char *q = NULL; |
2638 | + |
2639 | + Py_BEGIN_ALLOW_THREADS |
2640 | + n = ap_get_client_block(self->r, buffer + length, size - length); |
2641 | + Py_END_ALLOW_THREADS |
2642 | + |
2643 | + if (n == -1) { |
2644 | + PyErr_SetString(PyExc_IOError, "request data read error"); |
2645 | + Py_DECREF(result); |
2646 | + return NULL; |
2647 | + } |
2648 | + else if (n == 0) { |
2649 | + /* Have exhausted all the available input data. */ |
2650 | + |
2651 | + self->done = 1; |
2652 | + } |
2653 | + else { |
2654 | + /* |
2655 | + * Search for embedded EOL in what was read and if |
2656 | + * found copy any residual into a buffer for use |
2657 | + * next time the read functions are called. |
2658 | + */ |
2659 | + |
2660 | + p = buffer + length; |
2661 | + q = p + n; |
2662 | + |
2663 | + while (p != q) { |
2664 | + length++; |
2665 | + if (*p++ == '\n') |
2666 | + break; |
2667 | + } |
2668 | + |
2669 | + if (p != q) { |
2670 | + self->size = q - p; |
2671 | + self->buffer = (char *)malloc(self->size); |
2672 | + self->offset = 0; |
2673 | + self->length = self->size; |
2674 | + |
2675 | + memcpy(self->buffer, p, self->size); |
2676 | + } |
2677 | + |
2678 | + if (buffer[length-1] != '\n' && length == size) { |
2679 | + /* Increase size of string and keep going. */ |
2680 | + |
2681 | + size = size + (size >> 2); |
2682 | + |
2683 | + if (_PyString_Resize(&result, size)) |
2684 | + return NULL; |
2685 | + |
2686 | + buffer = PyString_AS_STRING((PyStringObject *)result); |
2687 | + } |
2688 | + } |
2689 | + } |
2690 | + |
2691 | + /* |
2692 | + * Resize the final string. If the size reduction is by |
2693 | + * more than 25% of the string size, then Python will |
2694 | + * allocate a new block of memory and copy the data into |
2695 | + * it. |
2696 | + */ |
2697 | + |
2698 | + if (length != size) { |
2699 | + if (_PyString_Resize(&result, length)) |
2700 | + return NULL; |
2701 | + } |
2702 | + } |
2703 | + |
2704 | + return result; |
2705 | +} |
2706 | + |
2707 | +static PyObject *Input_readlines(InputObject *self, PyObject *args) |
2708 | +{ |
2709 | + long hint = 0; |
2710 | + long length = 0; |
2711 | + |
2712 | + PyObject *result = NULL; |
2713 | + PyObject *line = NULL; |
2714 | + PyObject *rlargs = NULL; |
2715 | + |
2716 | + if (!self->r) { |
2717 | + PyErr_SetString(PyExc_RuntimeError, "request object has expired"); |
2718 | + return NULL; |
2719 | + } |
2720 | + |
2721 | + if (!PyArg_ParseTuple(args, "|l:readlines", &hint)) |
2722 | + return NULL; |
2723 | + |
2724 | + result = PyList_New(0); |
2725 | + if (!result) |
2726 | + return NULL; |
2727 | + |
2728 | + rlargs = PyTuple_New(0); |
2729 | + if (!rlargs) { |
2730 | + Py_DECREF(result); |
2731 | + return NULL; |
2732 | + } |
2733 | + |
2734 | + while (1) { |
2735 | + int n; |
2736 | + |
2737 | + if (!(line = Input_readline(self, rlargs))) { |
2738 | + Py_DECREF(result); |
2739 | + result = NULL; |
2740 | + break; |
2741 | + } |
2742 | + |
2743 | + if ((n = PyString_Size(line)) == 0) { |
2744 | + Py_DECREF(line); |
2745 | + break; |
2746 | + } |
2747 | + |
2748 | + if (PyList_Append(result, line) == -1) { |
2749 | + Py_DECREF(line); |
2750 | + Py_DECREF(result); |
2751 | + result = NULL; |
2752 | + break; |
2753 | + } |
2754 | + |
2755 | + Py_DECREF(line); |
2756 | + |
2757 | + length += n; |
2758 | + if (hint > 0 && length >= hint) |
2759 | + break; |
2760 | + } |
2761 | + |
2762 | + Py_DECREF(rlargs); |
2763 | + |
2764 | + return result; |
2765 | +} |
2766 | + |
2767 | +static PyMethodDef Input_methods[] = { |
2768 | + { "close", (PyCFunction)Input_close, METH_VARARGS, 0 }, |
2769 | + { "read", (PyCFunction)Input_read, METH_VARARGS, 0 }, |
2770 | + { "readline", (PyCFunction)Input_readline, METH_VARARGS, 0 }, |
2771 | + { "readlines", (PyCFunction)Input_readlines, METH_VARARGS, 0 }, |
2772 | + { NULL, NULL} |
2773 | +}; |
2774 | + |
2775 | +static PyObject *Input_iter(InputObject *self) |
2776 | +{ |
2777 | + if (!self->r) { |
2778 | + PyErr_SetString(PyExc_RuntimeError, "request object has expired"); |
2779 | + return NULL; |
2780 | + } |
2781 | + |
2782 | + Py_INCREF(self); |
2783 | + return (PyObject *)self; |
2784 | +} |
2785 | + |
2786 | +static PyObject *Input_iternext(InputObject *self) |
2787 | +{ |
2788 | + PyObject *line = NULL; |
2789 | + PyObject *rlargs = NULL; |
2790 | + |
2791 | + if (!self->r) { |
2792 | + PyErr_SetString(PyExc_RuntimeError, "request object has expired"); |
2793 | + return NULL; |
2794 | + } |
2795 | + |
2796 | + rlargs = PyTuple_New(0); |
2797 | + |
2798 | + if (!rlargs) |
2799 | + return NULL; |
2800 | + |
2801 | + line = Input_readline(self, rlargs); |
2802 | + |
2803 | + Py_DECREF(rlargs); |
2804 | + |
2805 | + if (!line) |
2806 | + return NULL; |
2807 | + |
2808 | + if (PyString_GET_SIZE(line) == 0) { |
2809 | + PyErr_SetObject(PyExc_StopIteration, Py_None); |
2810 | + Py_DECREF(line); |
2811 | + return NULL; |
2812 | + } |
2813 | + |
2814 | + return line; |
2815 | +} |
2816 | + |
2817 | +static PyTypeObject Input_Type = { |
2818 | + PyVarObject_HEAD_INIT(NULL, 0) |
2819 | + "mod_wsgi.Input", /*tp_name*/ |
2820 | + sizeof(InputObject), /*tp_basicsize*/ |
2821 | + 0, /*tp_itemsize*/ |
2822 | + /* methods */ |
2823 | + (destructor)Input_dealloc, /*tp_dealloc*/ |
2824 | + 0, /*tp_print*/ |
2825 | + 0, /*tp_getattr*/ |
2826 | + 0, /*tp_setattr*/ |
2827 | + 0, /*tp_compare*/ |
2828 | + 0, /*tp_repr*/ |
2829 | + 0, /*tp_as_number*/ |
2830 | + 0, /*tp_as_sequence*/ |
2831 | + 0, /*tp_as_mapping*/ |
2832 | + 0, /*tp_hash*/ |
2833 | + 0, /*tp_call*/ |
2834 | + 0, /*tp_str*/ |
2835 | + 0, /*tp_getattro*/ |
2836 | + 0, /*tp_setattro*/ |
2837 | + 0, /*tp_as_buffer*/ |
2838 | +#if defined(Py_TPFLAGS_HAVE_ITER) |
2839 | + Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_ITER, /*tp_flags*/ |
2840 | +#else |
2841 | + Py_TPFLAGS_DEFAULT, /*tp_flags*/ |
2842 | +#endif |
2843 | + 0, /*tp_doc*/ |
2844 | + 0, /*tp_traverse*/ |
2845 | + 0, /*tp_clear*/ |
2846 | + 0, /*tp_richcompare*/ |
2847 | + 0, /*tp_weaklistoffset*/ |
2848 | + (getiterfunc)Input_iter, /*tp_iter*/ |
2849 | + (iternextfunc)Input_iternext, /*tp_iternext*/ |
2850 | + Input_methods, /*tp_methods*/ |
2851 | + 0, /*tp_members*/ |
2852 | + 0, /*tp_getset*/ |
2853 | + 0, /*tp_base*/ |
2854 | + 0, /*tp_dict*/ |
2855 | + 0, /*tp_descr_get*/ |
2856 | + 0, /*tp_descr_set*/ |
2857 | + 0, /*tp_dictoffset*/ |
2858 | + 0, /*tp_init*/ |
2859 | + 0, /*tp_alloc*/ |
2860 | + 0, /*tp_new*/ |
2861 | + 0, /*tp_free*/ |
2862 | + 0, /*tp_is_gc*/ |
2863 | +}; |
2864 | + |
2865 | +typedef struct { |
2866 | + PyObject_HEAD |
2867 | + int result; |
2868 | + request_rec *r; |
2869 | +#if defined(MOD_WSGI_WITH_BUCKETS) |
2870 | + apr_bucket_brigade *bb; |
2871 | +#endif |
2872 | + WSGIRequestConfig *config; |
2873 | + InputObject *input; |
2874 | + PyObject *log; |
2875 | + int status; |
2876 | + const char *status_line; |
2877 | + PyObject *headers; |
2878 | + PyObject *sequence; |
2879 | + int content_length_set; |
2880 | + apr_off_t content_length; |
2881 | + apr_off_t output_length; |
2882 | +} AdapterObject; |
2883 | + |
2884 | +static PyTypeObject Adapter_Type; |
2885 | + |
2886 | +typedef struct { |
2887 | + PyObject_HEAD |
2888 | + AdapterObject *adapter; |
2889 | + PyObject *filelike; |
2890 | + apr_size_t blksize; |
2891 | +} StreamObject; |
2892 | + |
2893 | +static PyTypeObject Stream_Type; |
2894 | + |
2895 | +static AdapterObject *newAdapterObject(request_rec *r) |
2896 | +{ |
2897 | + AdapterObject *self; |
2898 | + |
2899 | + self = PyObject_New(AdapterObject, &Adapter_Type); |
2900 | + if (self == NULL) |
2901 | + return NULL; |
2902 | + |
2903 | + self->result = HTTP_INTERNAL_SERVER_ERROR; |
2904 | + |
2905 | + self->r = r; |
2906 | + |
2907 | +#if defined(MOD_WSGI_WITH_BUCKETS) |
2908 | + self->bb = NULL; |
2909 | +#endif |
2910 | + |
2911 | + self->config = (WSGIRequestConfig *)ap_get_module_config(r->request_config, |
2912 | + &wsgi_module); |
2913 | + |
2914 | + self->status = HTTP_INTERNAL_SERVER_ERROR; |
2915 | + self->status_line = NULL; |
2916 | + self->headers = NULL; |
2917 | + self->sequence = NULL; |
2918 | + |
2919 | + self->content_length_set = 0; |
2920 | + self->content_length = 0; |
2921 | + self->output_length = 0; |
2922 | + |
2923 | + self->input = newInputObject(r); |
2924 | + self->log = newLogObject(r, APLOG_ERR, NULL); |
2925 | + |
2926 | + return self; |
2927 | +} |
2928 | + |
2929 | +static void Adapter_dealloc(AdapterObject *self) |
2930 | +{ |
2931 | + Py_XDECREF(self->headers); |
2932 | + Py_XDECREF(self->sequence); |
2933 | + |
2934 | + Py_DECREF(self->input); |
2935 | + Py_DECREF(self->log); |
2936 | + |
2937 | + PyObject_Del(self); |
2938 | +} |
2939 | + |
2940 | +static PyObject *Adapter_start_response(AdapterObject *self, PyObject *args) |
2941 | +{ |
2942 | + const char *status = NULL; |
2943 | + PyObject *headers = NULL; |
2944 | + PyObject *exc_info = NULL; |
2945 | + |
2946 | + PyObject *item = NULL; |
2947 | + PyObject *latin_item = NULL; |
2948 | + |
2949 | + char* value = NULL; |
2950 | + |
2951 | + if (!self->r) { |
2952 | + PyErr_SetString(PyExc_RuntimeError, "request object has expired"); |
2953 | + return NULL; |
2954 | + } |
2955 | + |
2956 | + if (!PyArg_ParseTuple(args, "OO|O:start_response", |
2957 | + &item, &headers, &exc_info)) { |
2958 | + return NULL; |
2959 | + } |
2960 | + |
2961 | +#if PY_MAJOR_VERSION >= 3 |
2962 | + if (PyUnicode_Check(item)) { |
2963 | + latin_item = PyUnicode_AsLatin1String(item); |
2964 | + if (!latin_item) { |
2965 | + PyErr_Format(PyExc_TypeError, "expected byte string object for " |
2966 | + "status, value containing non 'latin-1' characters " |
2967 | + "found"); |
2968 | + return NULL; |
2969 | + } |
2970 | + |
2971 | + item = latin_item; |
2972 | + } |
2973 | +#endif |
2974 | + |
2975 | + if (!PyString_Check(item)) { |
2976 | + PyErr_Format(PyExc_TypeError, "expected byte string object for " |
2977 | + "status, value of type %.200s found", |
2978 | + item->ob_type->tp_name); |
2979 | + Py_XDECREF(latin_item); |
2980 | + return NULL; |
2981 | + } |
2982 | + |
2983 | + status = PyString_AsString(item); |
2984 | + |
2985 | + if (!PyList_Check(headers)) { |
2986 | + PyErr_SetString(PyExc_TypeError, "response headers must be a list"); |
2987 | + Py_XDECREF(latin_item); |
2988 | + return NULL; |
2989 | + } |
2990 | + |
2991 | + if (exc_info && exc_info != Py_None) { |
2992 | + if (self->status_line && !self->headers) { |
2993 | + PyObject *type = NULL; |
2994 | + PyObject *value = NULL; |
2995 | + PyObject *traceback = NULL; |
2996 | + |
2997 | + if (!PyArg_ParseTuple(exc_info, "OOO", &type, |
2998 | + &value, &traceback)) { |
2999 | + Py_XDECREF(latin_item); |
3000 | + return NULL; |
3001 | + } |
3002 | + |
3003 | + Py_INCREF(type); |
3004 | + Py_INCREF(value); |
3005 | + Py_INCREF(traceback); |
3006 | + |
3007 | + PyErr_Restore(type, value, traceback); |
3008 | + |
3009 | + Py_XDECREF(latin_item); |
3010 | + |
3011 | + return NULL; |
3012 | + } |
3013 | + } |
3014 | + else if (self->status_line && !self->headers) { |
3015 | + PyErr_SetString(PyExc_RuntimeError, "headers have already been sent"); |
3016 | + Py_XDECREF(latin_item); |
3017 | + return NULL; |
3018 | + } |
3019 | + |
3020 | + self->status_line = apr_pstrdup(self->r->pool, status); |
3021 | + |
3022 | + value = ap_getword(self->r->pool, &status, ' '); |
3023 | + |
3024 | + errno = 0; |
3025 | + self->status = strtol(value, &value, 10); |
3026 | + |
3027 | + if (*value || errno == ERANGE) { |
3028 | + PyErr_SetString(PyExc_TypeError, "status value is not an integer"); |
3029 | + Py_XDECREF(latin_item); |
3030 | + return NULL; |
3031 | + } |
3032 | + |
3033 | + if (!*status) { |
3034 | + PyErr_SetString(PyExc_ValueError, "status message was not supplied"); |
3035 | + Py_XDECREF(latin_item); |
3036 | + return NULL; |
3037 | + } |
3038 | + |
3039 | + Py_XDECREF(self->headers); |
3040 | + |
3041 | + self->headers = headers; |
3042 | + |
3043 | + Py_INCREF(self->headers); |
3044 | + |
3045 | + Py_XDECREF(latin_item); |
3046 | + |
3047 | + return PyObject_GetAttrString((PyObject *)self, "write"); |
3048 | +} |
3049 | + |
3050 | +static int Adapter_output(AdapterObject *self, const char *data, int length, |
3051 | + int exception_when_aborted) |
3052 | +{ |
3053 | + int i = 0; |
3054 | + int n = 0; |
3055 | + apr_status_t rv; |
3056 | + request_rec *r; |
3057 | + |
3058 | +#if defined(MOD_WSGI_WITH_DAEMONS) |
3059 | + if (wsgi_inactivity_timeout) { |
3060 | + apr_thread_mutex_lock(wsgi_shutdown_lock); |
3061 | + wsgi_inactivity_shutdown_time = apr_time_now(); |
3062 | + wsgi_inactivity_shutdown_time += wsgi_inactivity_timeout; |
3063 | + apr_thread_mutex_unlock(wsgi_shutdown_lock); |
3064 | + } |
3065 | +#endif |
3066 | + |
3067 | + if (!self->status_line) { |
3068 | + PyErr_SetString(PyExc_RuntimeError, "response has not been started"); |
3069 | + return 0; |
3070 | + } |
3071 | + |
3072 | + r = self->r; |
3073 | + |
3074 | + /* Have response headers yet been sent. */ |
3075 | + |
3076 | + if (self->headers) { |
3077 | + /* |
3078 | + * Apache prior to Apache 2.2.8 has a bug in it |
3079 | + * whereby it doesn't force '100 Continue' |
3080 | + * response before responding with headers if no |
3081 | + * read. So, force a zero length read before |
3082 | + * sending the headers if haven't yet attempted |
3083 | + * to read anything. This will ensure that if no |
3084 | + * request content has been read that any '100 |
3085 | + * Continue' response will be flushed and sent |
3086 | + * back to the client if client was expecting |
3087 | + * one. Only want to do this for 2xx and 3xx |
3088 | + * status values. Note that even though Apple |
3089 | + * supplied version of Apache on MacOS X Leopard |
3090 | + * is newer than version 2.2.8, the header file |
3091 | + * has never been patched when they make updates |
3092 | + * and so anything compiled against it thinks it |
3093 | + * is older. |
3094 | + */ |
3095 | + |
3096 | +#if (AP_SERVER_MAJORVERSION_NUMBER == 1) || \ |
3097 | + (AP_SERVER_MAJORVERSION_NUMBER == 2 && \ |
3098 | + AP_SERVER_MINORVERSION_NUMBER < 2) || \ |
3099 | + (AP_SERVER_MAJORVERSION_NUMBER == 2 && \ |
3100 | + AP_SERVER_MINORVERSION_NUMBER == 2 && \ |
3101 | + AP_SERVER_PATCHLEVEL_NUMBER < 8) |
3102 | + |
3103 | + if (!self->input->init) { |
3104 | + if (self->status >= 200 && self->status < 400) { |
3105 | + PyObject *args = NULL; |
3106 | + PyObject *result = NULL; |
3107 | + args = Py_BuildValue("(i)", 0); |
3108 | + result = Input_read(self->input, args); |
3109 | + if (PyErr_Occurred()) |
3110 | + PyErr_Clear(); |
3111 | + Py_DECREF(args); |
3112 | + Py_XDECREF(result); |
3113 | + } |
3114 | + } |
3115 | + |
3116 | +#endif |
3117 | + |
3118 | + /* Now setup response headers in request object. */ |
3119 | + |
3120 | + r->status = self->status; |
3121 | + r->status_line = self->status_line; |
3122 | + |
3123 | + for (i = 0; i < PyList_Size(self->headers); i++) { |
3124 | + PyObject *tuple = NULL; |
3125 | + |
3126 | + PyObject *object1 = NULL; |
3127 | + PyObject *object2 = NULL; |
3128 | + |
3129 | + char *name = NULL; |
3130 | + char *value = NULL; |
3131 | + |
3132 | + tuple = PyList_GetItem(self->headers, i); |
3133 | + |
3134 | + if (!PyTuple_Check(tuple)) { |
3135 | + PyErr_Format(PyExc_TypeError, "list of tuple values " |
3136 | + "expected, value of type %.200s found", |
3137 | + tuple->ob_type->tp_name); |
3138 | + return 0; |
3139 | + } |
3140 | + |
3141 | + if (PyTuple_Size(tuple) != 2) { |
3142 | + PyErr_Format(PyExc_ValueError, "tuple of length 2 " |
3143 | + "expected, length is %d", |
3144 | + (int)PyTuple_Size(tuple)); |
3145 | + return 0; |
3146 | + } |
3147 | + |
3148 | + object1 = PyTuple_GetItem(tuple, 0); |
3149 | + object2 = PyTuple_GetItem(tuple, 1); |
3150 | + |
3151 | + if (PyString_Check(object1)) { |
3152 | + name = PyString_AsString(object1); |
3153 | + } |
3154 | +#if PY_MAJOR_VERSION >= 3 |
3155 | + else if (PyUnicode_Check(object1)) { |
3156 | + PyObject *latin_object; |
3157 | + latin_object = PyUnicode_AsLatin1String(object1); |
3158 | + if (!latin_object) { |
3159 | + PyErr_Format(PyExc_TypeError, "header name " |
3160 | + "contained non 'latin-1' characters "); |
3161 | + return 0; |
3162 | + } |
3163 | + |
3164 | + name = apr_pstrdup(r->pool, PyString_AsString(latin_object)); |
3165 | + Py_DECREF(latin_object); |
3166 | + } |
3167 | +#endif |
3168 | + else { |
3169 | + PyErr_Format(PyExc_TypeError, "expected byte string object " |
3170 | + "for header name, value of type %.200s " |
3171 | + "found", object1->ob_type->tp_name); |
3172 | + return 0; |
3173 | + } |
3174 | + |
3175 | + if (PyString_Check(object2)) { |
3176 | + value = PyString_AsString(object2); |
3177 | + } |
3178 | +#if PY_MAJOR_VERSION >= 3 |
3179 | + else if (PyUnicode_Check(object2)) { |
3180 | + PyObject *latin_object; |
3181 | + latin_object = PyUnicode_AsLatin1String(object2); |
3182 | + if (!latin_object) { |
3183 | + PyErr_Format(PyExc_TypeError, "header value " |
3184 | + "contained non 'latin-1' characters "); |
3185 | + return 0; |
3186 | + } |
3187 | + |
3188 | + value = apr_pstrdup(r->pool, PyString_AsString(latin_object)); |
3189 | + Py_DECREF(latin_object); |
3190 | + } |
3191 | +#endif |
3192 | + else { |
3193 | + PyErr_Format(PyExc_TypeError, "expected byte string object " |
3194 | + "for header value, value of type %.200s " |
3195 | + "found", object2->ob_type->tp_name); |
3196 | + return 0; |
3197 | + } |
3198 | + |
3199 | + if (strchr(name, '\n') != 0 || strchr(value, '\n') != 0) { |
3200 | + PyErr_Format(PyExc_ValueError, "embedded newline in " |
3201 | + "response header with name '%s' and value '%s'", |
3202 | + name, value); |
3203 | + return 0; |
3204 | + } |
3205 | + |
3206 | + if (!strcasecmp(name, "Content-Type")) { |
3207 | +#if AP_SERVER_MAJORVERSION_NUMBER < 2 |
3208 | + r->content_type = apr_pstrdup(r->pool, value); |
3209 | +#else |
3210 | + /* |
3211 | + * In a daemon child process we cannot call the |
3212 | + * function ap_set_content_type() as want to |
3213 | + * avoid adding any output filters based on the |
3214 | + * type of file being served as this will be |
3215 | + * done in the main Apache child process which |
3216 | + * proxied the request to the daemon process. |
3217 | + */ |
3218 | + |
3219 | + if (*self->config->process_group) |
3220 | + r->content_type = apr_pstrdup(r->pool, value); |
3221 | + else |
3222 | + ap_set_content_type(r, value); |
3223 | +#endif |
3224 | + } |
3225 | + else if (!strcasecmp(name, "Content-Length")) { |
3226 | + char *v = value; |
3227 | + long l = 0; |
3228 | + |
3229 | + errno = 0; |
3230 | + l = strtol(v, &v, 10); |
3231 | + if (*v || errno == ERANGE || l < 0) { |
3232 | + PyErr_SetString(PyExc_ValueError, |
3233 | + "invalid content length"); |
3234 | + return 0; |
3235 | + } |
3236 | + |
3237 | + ap_set_content_length(r, l); |
3238 | + |
3239 | + self->content_length_set = 1; |
3240 | + self->content_length = l; |
3241 | + } |
3242 | + else if (!strcasecmp(name, "WWW-Authenticate")) { |
3243 | + apr_table_add(r->err_headers_out, name, value); |
3244 | + } |
3245 | + else { |
3246 | + apr_table_add(r->headers_out, name, value); |
3247 | + } |
3248 | + } |
3249 | + |
3250 | + /* Need to force output of headers when using Apache 1.3. */ |
3251 | + |
3252 | + Py_BEGIN_ALLOW_THREADS |
3253 | + ap_send_http_header(r); |
3254 | + Py_END_ALLOW_THREADS |
3255 | + |
3256 | + /* |
3257 | + * Reset flag indicating whether '100 Continue' response |
3258 | + * expected. If we don't do this then if an attempt to read |
3259 | + * input for the first time is after headers have been |
3260 | + * sent, then Apache is wrongly generate the '100 Continue' |
3261 | + * response into the response content. Not sure if this is |
3262 | + * a bug in Apache, or that it truly believes that input |
3263 | + * will never be read after the response headers have been |
3264 | + * sent. |
3265 | + */ |
3266 | + |
3267 | + r->expecting_100 = 0; |
3268 | + |
3269 | + /* No longer need headers now that they have been sent. */ |
3270 | + |
3271 | + Py_DECREF(self->headers); |
3272 | + self->headers = NULL; |
3273 | + } |
3274 | + |
3275 | + /* |
3276 | + * If content length was specified, ensure that we don't |
3277 | + * actually output more data than was specified as being |
3278 | + * sent as otherwise technically in violation of HTTP RFC. |
3279 | + */ |
3280 | + |
3281 | + if (length) { |
3282 | + int output_length = length; |
3283 | + |
3284 | + if (self->content_length_set) { |
3285 | + if (self->output_length < self->content_length) { |
3286 | + if (self->output_length + length > self->content_length) { |
3287 | + length = self->content_length - self->output_length; |
3288 | + } |
3289 | + } |
3290 | + else |
3291 | + length = 0; |
3292 | + } |
3293 | + |
3294 | + self->output_length += output_length; |
3295 | + } |
3296 | + |
3297 | + /* Now output any data. */ |
3298 | + |
3299 | + if (length) { |
3300 | +#if defined(MOD_WSGI_WITH_BUCKETS) |
3301 | + apr_bucket *b; |
3302 | + |
3303 | + /* |
3304 | + * When using Apache 2.X can use lower level |
3305 | + * bucket brigade APIs. This is preferred as |
3306 | + * ap_rwrite()/ap_rflush() will grow memory in |
3307 | + * the request pool on each call, which will |
3308 | + * result in an increase in memory use over time |
3309 | + * when streaming of data is being performed. |
3310 | + * The memory is still reclaimed, but only at |
3311 | + * the end of the request. Using bucket brigade |
3312 | + * API avoids this, and also avoids any copying |
3313 | + * of response data due to buffering performed |
3314 | + * by ap_rwrite(). |
3315 | + */ |
3316 | + |
3317 | + if (r->connection->aborted) { |
3318 | + if (!exception_when_aborted) { |
3319 | + ap_log_rerror(APLOG_MARK, WSGI_LOG_DEBUG(0), self->r, |
3320 | + "mod_wsgi (pid=%d): Client closed connection.", |
3321 | + getpid()); |
3322 | + } |
3323 | + else |
3324 | + PyErr_SetString(PyExc_IOError, "client connection closed"); |
3325 | + |
3326 | + return 0; |
3327 | + } |
3328 | + |
3329 | + if (!self->bb) { |
3330 | + self->bb = apr_brigade_create(r->pool, |
3331 | + r->connection->bucket_alloc); |
3332 | + } |
3333 | + |
3334 | + b = apr_bucket_transient_create(data, length, |
3335 | + r->connection->bucket_alloc); |
3336 | + APR_BRIGADE_INSERT_TAIL(self->bb, b); |
3337 | + |
3338 | + b = apr_bucket_flush_create(r->connection->bucket_alloc); |
3339 | + APR_BRIGADE_INSERT_TAIL(self->bb, b); |
3340 | + |
3341 | + Py_BEGIN_ALLOW_THREADS |
3342 | + rv = ap_pass_brigade(r->output_filters, self->bb); |
3343 | + Py_END_ALLOW_THREADS |
3344 | + |
3345 | + if (rv != APR_SUCCESS) { |
3346 | + PyErr_SetString(PyExc_IOError, "failed to write data"); |
3347 | + return 0; |
3348 | + } |
3349 | + |
3350 | + Py_BEGIN_ALLOW_THREADS |
3351 | + apr_brigade_cleanup(self->bb); |
3352 | + Py_END_ALLOW_THREADS |
3353 | +#else |
3354 | + /* |
3355 | + * In Apache 1.3, the bucket brigade system doesn't exist, |
3356 | + * so have no choice but to use ap_rwrite()/ap_rflush(). |
3357 | + * It is not believed that Apache 1.3 suffers the memory |
3358 | + * accumulation problem when streaming lots of data. |
3359 | + */ |
3360 | + |
3361 | + Py_BEGIN_ALLOW_THREADS |
3362 | + n = ap_rwrite(data, length, r); |
3363 | + Py_END_ALLOW_THREADS |
3364 | + |
3365 | + if (n == -1) { |
3366 | + PyErr_SetString(PyExc_IOError, "failed to write data"); |
3367 | + return 0; |
3368 | + } |
3369 | + |
3370 | + Py_BEGIN_ALLOW_THREADS |
3371 | + n = ap_rflush(r); |
3372 | + Py_END_ALLOW_THREADS |
3373 | + |
3374 | + if (n == -1) { |
3375 | + PyErr_SetString(PyExc_IOError, "failed to flush data"); |
3376 | + return 0; |
3377 | + } |
3378 | +#endif |
3379 | + } |
3380 | + |
3381 | + /* |
3382 | + * Check whether aborted connection was found when data |
3383 | + * being written, otherwise will not be flagged until next |
3384 | + * time that data is being written. Early detection is |
3385 | + * better as it may have been the last data block being |
3386 | + * written and application may think that data has all |
3387 | + * been written. In a streaming application, we also want |
3388 | + * to avoid any additional data processing to generate any |
3389 | + * successive data. |
3390 | + */ |
3391 | + |
3392 | + if (r->connection->aborted) { |
3393 | + if (!exception_when_aborted) { |
3394 | + ap_log_rerror(APLOG_MARK, WSGI_LOG_DEBUG(0), self->r, |
3395 | + "mod_wsgi (pid=%d): Client closed connection.", |
3396 | + getpid()); |
3397 | + } |
3398 | + else |
3399 | + PyErr_SetString(PyExc_IOError, "client connection closed"); |
3400 | + |
3401 | + return 0; |
3402 | + } |
3403 | + |
3404 | + return 1; |
3405 | +} |
3406 | + |
3407 | +#if AP_SERVER_MAJORVERSION_NUMBER >= 2 |
3408 | + |
3409 | +/* Split buckets at 1GB when sending large files. */ |
3410 | + |
3411 | +#define MAX_BUCKET_SIZE (0x40000000) |
3412 | + |
3413 | +static int Adapter_output_file(AdapterObject *self, apr_file_t* tmpfile, |
3414 | + apr_off_t offset, apr_off_t len) |
3415 | +{ |
3416 | + request_rec *r; |
3417 | + apr_bucket *b; |
3418 | + apr_status_t rv; |
3419 | + apr_bucket_brigade *bb; |
3420 | + |
3421 | + r = self->r; |
3422 | + |
3423 | + if (r->connection->aborted) { |
3424 | + PyErr_SetString(PyExc_IOError, "client connection closed"); |
3425 | + return 0; |
3426 | + } |
3427 | + |
3428 | + if (len == 0) |
3429 | + return 1; |
3430 | + |
3431 | + bb = apr_brigade_create(r->pool, r->connection->bucket_alloc); |
3432 | + |
3433 | + if (sizeof(apr_off_t) == sizeof(apr_size_t) || len < MAX_BUCKET_SIZE) { |
3434 | + /* Can use a single bucket to send file. */ |
3435 | + |
3436 | + b = apr_bucket_file_create(tmpfile, offset, (apr_size_t)len, r->pool, |
3437 | + r->connection->bucket_alloc); |
3438 | + } |
3439 | + else { |
3440 | + /* Need to create multiple buckets to send file. */ |
3441 | + |
3442 | + b = apr_bucket_file_create(tmpfile, offset, MAX_BUCKET_SIZE, r->pool, |
3443 | + r->connection->bucket_alloc); |
3444 | + |
3445 | + while (len > MAX_BUCKET_SIZE) { |
3446 | + apr_bucket *cb; |
3447 | + apr_bucket_copy(b, &cb); |
3448 | + APR_BRIGADE_INSERT_TAIL(bb, cb); |
3449 | + b->start += MAX_BUCKET_SIZE; |
3450 | + len -= MAX_BUCKET_SIZE; |
3451 | + } |
3452 | + |
3453 | + /* Resize just the last bucket */ |
3454 | + |
3455 | + b->length = (apr_size_t)len; |
3456 | + } |
3457 | + |
3458 | + APR_BRIGADE_INSERT_TAIL(bb, b); |
3459 | + |
3460 | + b = apr_bucket_flush_create(r->connection->bucket_alloc); |
3461 | + APR_BRIGADE_INSERT_TAIL(bb, b); |
3462 | + |
3463 | + b = apr_bucket_eos_create(r->connection->bucket_alloc); |
3464 | + APR_BRIGADE_INSERT_TAIL(bb, b); |
3465 | + |
3466 | + Py_BEGIN_ALLOW_THREADS |
3467 | + rv = ap_pass_brigade(r->output_filters, bb); |
3468 | + Py_END_ALLOW_THREADS |
3469 | + |
3470 | + if (rv != APR_SUCCESS) { |
3471 | + PyErr_SetString(PyExc_IOError, "failed to write data"); |
3472 | + return 0; |
3473 | + } |
3474 | + |
3475 | + Py_BEGIN_ALLOW_THREADS |
3476 | + apr_brigade_destroy(bb); |
3477 | + Py_END_ALLOW_THREADS |
3478 | + |
3479 | + if (r->connection->aborted) { |
3480 | + PyErr_SetString(PyExc_IOError, "client connection closed"); |
3481 | + return 0; |
3482 | + } |
3483 | + |
3484 | + return 1; |
3485 | +} |
3486 | + |
3487 | +#endif |
3488 | + |
3489 | +#if AP_SERVER_MAJORVERSION_NUMBER >= 2 |
3490 | +APR_DECLARE_OPTIONAL_FN(int, ssl_is_https, (conn_rec *)); |
3491 | +static APR_OPTIONAL_FN_TYPE(ssl_is_https) *wsgi_is_https = NULL; |
3492 | +#endif |
3493 | + |
3494 | +static PyObject *Adapter_environ(AdapterObject *self) |
3495 | +{ |
3496 | + request_rec *r = NULL; |
3497 | + |
3498 | + PyObject *vars = NULL; |
3499 | + PyObject *object = NULL; |
3500 | + |
3501 | + const apr_array_header_t *head = NULL; |
3502 | + const apr_table_entry_t *elts = NULL; |
3503 | + |
3504 | + int i = 0; |
3505 | + |
3506 | + const char *scheme = NULL; |
3507 | + |
3508 | + /* Create the WSGI environment dictionary. */ |
3509 | + |
3510 | + vars = PyDict_New(); |
3511 | + |
3512 | + /* Merge the CGI environment into the WSGI environment. */ |
3513 | + |
3514 | + r = self->r; |
3515 | + |
3516 | + head = apr_table_elts(r->subprocess_env); |
3517 | + elts = (apr_table_entry_t *)head->elts; |
3518 | + |
3519 | + for (i = 0; i < head->nelts; ++i) { |
3520 | + if (elts[i].key) { |
3521 | + if (elts[i].val) { |
3522 | +#if PY_MAJOR_VERSION >= 3 |
3523 | + if (!strcmp(elts[i].val, "DOCUMENT_ROOT")) { |
3524 | + object = PyUnicode_Decode(elts[i].val, strlen(elts[i].val), |
3525 | + Py_FileSystemDefaultEncoding, |
3526 | + "surrogateescape"); |
3527 | + } |
3528 | + else if (!strcmp(elts[i].val, "SCRIPT_FILENAME")) { |
3529 | + object = PyUnicode_Decode(elts[i].val, strlen(elts[i].val), |
3530 | + Py_FileSystemDefaultEncoding, |
3531 | + "surrogateescape"); |
3532 | + } |
3533 | + else { |
3534 | + object = PyUnicode_DecodeLatin1(elts[i].val, |
3535 | + strlen(elts[i].val), NULL); |
3536 | + } |
3537 | +#else |
3538 | + object = PyString_FromString(elts[i].val); |
3539 | +#endif |
3540 | + PyDict_SetItemString(vars, elts[i].key, object); |
3541 | + Py_DECREF(object); |
3542 | + } |
3543 | + else |
3544 | + PyDict_SetItemString(vars, elts[i].key, Py_None); |
3545 | + } |
3546 | + } |
3547 | + |
3548 | + PyDict_DelItemString(vars, "PATH"); |
3549 | + |
3550 | + /* Now setup all the WSGI specific environment values. */ |
3551 | + |
3552 | + object = Py_BuildValue("(ii)", 1, 1); |
3553 | + PyDict_SetItemString(vars, "wsgi.version", object); |
3554 | + Py_DECREF(object); |
3555 | + |
3556 | + object = PyBool_FromLong(wsgi_multithread); |
3557 | + PyDict_SetItemString(vars, "wsgi.multithread", object); |
3558 | + Py_DECREF(object); |
3559 | + |
3560 | + object = PyBool_FromLong(wsgi_multiprocess); |
3561 | + PyDict_SetItemString(vars, "wsgi.multiprocess", object); |
3562 | + Py_DECREF(object); |
3563 | + |
3564 | +#if defined(MOD_WSGI_WITH_DAEMONS) |
3565 | + if (wsgi_daemon_process) { |
3566 | + if (wsgi_daemon_process->group->threads == 1 && |
3567 | + wsgi_daemon_process->group->maximum_requests == 1) { |
3568 | + PyDict_SetItemString(vars, "wsgi.run_once", Py_True); |
3569 | + } |
3570 | + else |
3571 | + PyDict_SetItemString(vars, "wsgi.run_once", Py_False); |
3572 | + } |
3573 | + else |
3574 | + PyDict_SetItemString(vars, "wsgi.run_once", Py_False); |
3575 | +#else |
3576 | + PyDict_SetItemString(vars, "wsgi.run_once", Py_False); |
3577 | +#endif |
3578 | + |
3579 | + scheme = apr_table_get(r->subprocess_env, "HTTPS"); |
3580 | + |
3581 | + if (scheme && (!strcasecmp(scheme, "On") || !strcmp(scheme, "1"))) { |
3582 | +#if PY_MAJOR_VERSION >= 3 |
3583 | + object = PyUnicode_FromString("https"); |
3584 | +#else |
3585 | + object = PyString_FromString("https"); |
3586 | +#endif |
3587 | + PyDict_SetItemString(vars, "wsgi.url_scheme", object); |
3588 | + Py_DECREF(object); |
3589 | + } |
3590 | + else { |
3591 | +#if PY_MAJOR_VERSION >= 3 |
3592 | + object = PyUnicode_FromString("http"); |
3593 | +#else |
3594 | + object = PyString_FromString("http"); |
3595 | +#endif |
3596 | + PyDict_SetItemString(vars, "wsgi.url_scheme", object); |
3597 | + Py_DECREF(object); |
3598 | + } |
3599 | + |
3600 | + /* |
3601 | + * Setup log object for WSGI errors. Don't decrement |
3602 | + * reference to log object as keep reference to it. |
3603 | + */ |
3604 | + |
3605 | + object = (PyObject *)self->log; |
3606 | + PyDict_SetItemString(vars, "wsgi.errors", object); |
3607 | + |
3608 | + /* Setup input object for request content. */ |
3609 | + |
3610 | + object = (PyObject *)self->input; |
3611 | + PyDict_SetItemString(vars, "wsgi.input", object); |
3612 | + |
3613 | + /* Setup file wrapper object for efficient file responses. */ |
3614 | + |
3615 | + object = PyObject_GetAttrString((PyObject *)self, "file_wrapper"); |
3616 | + PyDict_SetItemString(vars, "wsgi.file_wrapper", object); |
3617 | + Py_DECREF(object); |
3618 | + |
3619 | + /* Add mod_wsgi version information. */ |
3620 | + |
3621 | + object = Py_BuildValue("(ii)", MOD_WSGI_MAJORVERSION_NUMBER, |
3622 | + MOD_WSGI_MINORVERSION_NUMBER); |
3623 | + PyDict_SetItemString(vars, "mod_wsgi.version", object); |
3624 | + Py_DECREF(object); |
3625 | + |
3626 | + /* |
3627 | + * If Apache extensions are enabled and running in embedded |
3628 | + * mode add a CObject reference to the Apache request_rec |
3629 | + * structure instance. |
3630 | + */ |
3631 | + |
3632 | + if (!wsgi_daemon_pool && self->config->pass_apache_request) { |
3633 | + object = PyCObject_FromVoidPtr(self->r, 0); |
3634 | + PyDict_SetItemString(vars, "apache.request_rec", object); |
3635 | + Py_DECREF(object); |
3636 | + } |
3637 | + |
3638 | + return vars; |
3639 | +} |
3640 | + |
3641 | +static int Adapter_process_file_wrapper(AdapterObject *self) |
3642 | +{ |
3643 | + int done = 0; |
3644 | + |
3645 | +#ifndef WIN32 |
3646 | +#if AP_SERVER_MAJORVERSION_NUMBER >= 2 |
3647 | + |
3648 | + PyObject *filelike = NULL; |
3649 | + PyObject *method = NULL; |
3650 | + PyObject *object = NULL; |
3651 | + |
3652 | + apr_status_t rv = 0; |
3653 | + |
3654 | + apr_os_file_t fd = -1; |
3655 | + apr_file_t *tmpfile = NULL; |
3656 | + apr_finfo_t finfo; |
3657 | + |
3658 | + apr_off_t fd_offset = 0; |
3659 | + apr_off_t fo_offset = 0; |
3660 | + |
3661 | + apr_off_t length = 0; |
3662 | + |
3663 | + /* Perform file wrapper optimisations where possible. */ |
3664 | + |
3665 | + if (self->sequence->ob_type != &Stream_Type) |
3666 | + return 0; |
3667 | + |
3668 | + /* |
3669 | + * Only attempt to perform optimisations if the |
3670 | + * write() function returned by start_response() |
3671 | + * function has not been called with non zero length |
3672 | + * data. In other words if no prior response content |
3673 | + * generated. Technically it could be done, but want |
3674 | + * to have a consistent rule about how specifying a |
3675 | + * content length affects how much of a file is |
3676 | + * sent. Don't want to have to take into |
3677 | + * consideration whether write() function has been |
3678 | + * called or not as just complicates things. |
3679 | + */ |
3680 | + |
3681 | + if (self->output_length != 0) |
3682 | + return 0; |
3683 | + |
3684 | + /* |
3685 | + * Work out if file wrapper is associated with a |
3686 | + * file like object, where that file object is |
3687 | + * associated with a regular file. If it does then |
3688 | + * we can optimise how the contents of the file are |
3689 | + * sent out. If no such associated file descriptor |
3690 | + * then it needs to be processed like any other |
3691 | + * iterable value. |
3692 | + */ |
3693 | + |
3694 | + filelike = ((StreamObject *)self->sequence)->filelike; |
3695 | + |
3696 | + fd = PyObject_AsFileDescriptor(filelike); |
3697 | + if (fd == -1) { |
3698 | + PyErr_Clear(); |
3699 | + return 0; |
3700 | + } |
3701 | + |
3702 | + /* |
3703 | + * On some platforms, such as Linux, sendfile() system call |
3704 | + * will not work on UNIX sockets. Thus when using daemon mode |
3705 | + * cannot enable that feature. |
3706 | + */ |
3707 | + |
3708 | + if (!wsgi_daemon_pool) |
3709 | + apr_os_file_put(&tmpfile, &fd, APR_SENDFILE_ENABLED, self->r->pool); |
3710 | + else |
3711 | + apr_os_file_put(&tmpfile, &fd, 0, self->r->pool); |
3712 | + |
3713 | + rv = apr_file_info_get(&finfo, APR_FINFO_SIZE|APR_FINFO_TYPE, tmpfile); |
3714 | + if (rv != APR_SUCCESS || finfo.filetype != APR_REG) |
3715 | + return 0; |
3716 | + |
3717 | + /* |
3718 | + * Because Python file like objects potentially have |
3719 | + * their own buffering layering, or use an operating |
3720 | + * system FILE object which also has a buffering |
3721 | + * layer on top of a normal file descriptor, need to |
3722 | + * determine from the file like object its position |
3723 | + * within the file and use that as starting position. |
3724 | + * Note that it is assumed that user had flushed any |
3725 | + * modifications to the file as necessary. Also, we |
3726 | + * need to make sure we remember the original file |
3727 | + * descriptor position as will need to restore that |
3728 | + * position so it matches the upper buffering layers |
3729 | + * when done. This is done to avoid any potential |
3730 | + * problems if file like object does anything strange |
3731 | + * in its close() method which relies on file position |
3732 | + * being what it thought it should be. |
3733 | + */ |
3734 | + |
3735 | + rv = apr_file_seek(tmpfile, APR_CUR, &fd_offset); |
3736 | + if (rv != APR_SUCCESS) |
3737 | + return 0; |
3738 | + |
3739 | + method = PyObject_GetAttrString(filelike, "tell"); |
3740 | + if (!method) |
3741 | + return 0; |
3742 | + |
3743 | + object = PyEval_CallObject(method, NULL); |
3744 | + Py_DECREF(method); |
3745 | + |
3746 | + if (!object) { |
3747 | + PyErr_Clear(); |
3748 | + return 0; |
3749 | + } |
3750 | + |
3751 | + if (PyLong_Check(object)) { |
3752 | +#if defined(HAVE_LONG_LONG) |
3753 | + fo_offset = PyLong_AsLongLong(object); |
3754 | +#else |
3755 | + fo_offset = PyLong_AsLong(object); |
3756 | +#endif |
3757 | + } |
3758 | +#if PY_MAJOR_VERSION < 3 |
3759 | + else if (PyInt_Check(object)) { |
3760 | + fo_offset = PyInt_AsLong(object); |
3761 | + } |
3762 | +#endif |
3763 | + else { |
3764 | + Py_DECREF(object); |
3765 | + return 0; |
3766 | + } |
3767 | + |
3768 | + if (PyErr_Occurred()){ |
3769 | + Py_DECREF(object); |
3770 | + PyErr_Clear(); |
3771 | + return 0; |
3772 | + } |
3773 | + |
3774 | + Py_DECREF(object); |
3775 | + |
3776 | + /* |
3777 | + * For a file wrapper object need to always ensure |
3778 | + * that response headers are parsed. This is done so |
3779 | + * that if the content length header has been |
3780 | + * defined we can get its value and use it to limit |
3781 | + * how much of a file is being sent. The WSGI 1.0 |
3782 | + * specification says that we are meant to send all |
3783 | + * available bytes from the file, however this is |
3784 | + * questionable as sending more than content length |
3785 | + * would violate HTTP RFC. Note that this doesn't |
3786 | + * actually flush the headers out when using Apache |
3787 | + * 2.X. This is good, as we want to still be able to |
3788 | + * set the content length header if none set and file |
3789 | + * is seekable. If processing response headers fails, |
3790 | + * then need to return as if done, with error being |
3791 | + * logged later. |
3792 | + */ |
3793 | + |
3794 | + if (!Adapter_output(self, "", 0, 0)) |
3795 | + return 1; |
3796 | + |
3797 | + /* |
3798 | + * If content length wasn't defined then determine |
3799 | + * the amount of data which is available to send and |
3800 | + * set the content length response header. Either |
3801 | + * way, if can work out length then send data |
3802 | + * otherwise fall through and treat it as normal |
3803 | + * iterable. |
3804 | + */ |
3805 | + |
3806 | + if (!self->content_length_set) { |
3807 | + length = finfo.size - fo_offset; |
3808 | + self->output_length += length; |
3809 | + |
3810 | + ap_set_content_length(self->r, length); |
3811 | + |
3812 | + self->content_length_set = 1; |
3813 | + self->content_length = length; |
3814 | + |
3815 | + if (Adapter_output_file(self, tmpfile, fo_offset, length)) |
3816 | + self->result = OK; |
3817 | + |
3818 | + done = 1; |
3819 | + } |
3820 | + else { |
3821 | + length = finfo.size - fo_offset; |
3822 | + self->output_length += length; |
3823 | + |
3824 | + /* Use user specified content length instead. */ |
3825 | + |
3826 | + length = self->content_length; |
3827 | + |
3828 | + if (Adapter_output_file(self, tmpfile, fo_offset, length)) |
3829 | + self->result = OK; |
3830 | + |
3831 | + done = 1; |
3832 | + } |
3833 | + |
3834 | + /* |
3835 | + * Restore position of underlying file descriptor. |
3836 | + * If this fails, then not much we can do about it. |
3837 | + */ |
3838 | + |
3839 | + apr_file_seek(tmpfile, APR_SET, &fd_offset); |
3840 | + |
3841 | +#endif |
3842 | +#endif |
3843 | + |
3844 | + return done; |
3845 | +} |
3846 | + |
3847 | +static int Adapter_run(AdapterObject *self, PyObject *object) |
3848 | +{ |
3849 | + PyObject *vars = NULL; |
3850 | + PyObject *start = NULL; |
3851 | + PyObject *args = NULL; |
3852 | + PyObject *iterator = NULL; |
3853 | + PyObject *close = NULL; |
3854 | + |
3855 | + const char *msg = NULL; |
3856 | + int length = 0; |
3857 | + |
3858 | +#if defined(MOD_WSGI_WITH_DAEMONS) |
3859 | + if (wsgi_inactivity_timeout) { |
3860 | + apr_thread_mutex_lock(wsgi_shutdown_lock); |
3861 | + wsgi_inactivity_shutdown_time = apr_time_now(); |
3862 | + wsgi_inactivity_shutdown_time += wsgi_inactivity_timeout; |
3863 | + apr_thread_mutex_unlock(wsgi_shutdown_lock); |
3864 | + } |
3865 | +#endif |
3866 | + |
3867 | + vars = Adapter_environ(self); |
3868 | + |
3869 | + start = PyObject_GetAttrString((PyObject *)self, "start_response"); |
3870 | + |
3871 | + args = Py_BuildValue("(OO)", vars, start); |
3872 | + |
3873 | + self->sequence = PyEval_CallObject(object, args); |
3874 | + |
3875 | + if (self->sequence != NULL) { |
3876 | + if (!Adapter_process_file_wrapper(self)) { |
3877 | + int aborted = 0; |
3878 | + |
3879 | + iterator = PyObject_GetIter(self->sequence); |
3880 | + |
3881 | + if (iterator != NULL) { |
3882 | + PyObject *item = NULL; |
3883 | + |
3884 | + while ((item = PyIter_Next(iterator))) { |
3885 | +#if PY_MAJOR_VERSION >= 3 |
3886 | + if (PyUnicode_Check(item)) { |
3887 | + PyObject *latin_item; |
3888 | + latin_item = PyUnicode_AsLatin1String(item); |
3889 | + if (!latin_item) { |
3890 | + PyErr_Format(PyExc_TypeError, "sequence of " |
3891 | + "byte string values expected, value " |
3892 | + "containing non 'latin-1' characters " |
3893 | + "found"); |
3894 | + Py_DECREF(item); |
3895 | + break; |
3896 | + } |
3897 | + |
3898 | + Py_DECREF(item); |
3899 | + item = latin_item; |
3900 | + } |
3901 | +#endif |
3902 | + |
3903 | + if (!PyString_Check(item)) { |
3904 | + PyErr_Format(PyExc_TypeError, "sequence of byte " |
3905 | + "string values expected, value of " |
3906 | + "type %.200s found", |
3907 | + item->ob_type->tp_name); |
3908 | + Py_DECREF(item); |
3909 | + break; |
3910 | + } |
3911 | + |
3912 | + msg = PyString_AsString(item); |
3913 | + length = PyString_Size(item); |
3914 | + |
3915 | + if (!msg) { |
3916 | + Py_DECREF(item); |
3917 | + break; |
3918 | + } |
3919 | + |
3920 | + if (length && !Adapter_output(self, msg, length, 0)) { |
3921 | + if (!PyErr_Occurred()) |
3922 | + aborted = 1; |
3923 | + Py_DECREF(item); |
3924 | + break; |
3925 | + } |
3926 | + |
3927 | + Py_DECREF(item); |
3928 | + } |
3929 | + } |
3930 | + |
3931 | + if (!PyErr_Occurred() && !aborted) { |
3932 | + if (Adapter_output(self, "", 0, 0)) |
3933 | + self->result = OK; |
3934 | + } |
3935 | + |
3936 | + Py_XDECREF(iterator); |
3937 | + } |
3938 | + |
3939 | + if (PyErr_Occurred()) { |
3940 | + /* |
3941 | + * Response content has already been sent, so cannot |
3942 | + * return an internal server error as Apache will |
3943 | + * append its own error page. Thus need to return OK |
3944 | + * and just truncate the response. |
3945 | + */ |
3946 | + |
3947 | + if (self->status_line && !self->headers) |
3948 | + self->result = OK; |
3949 | + |
3950 | + wsgi_log_python_error(self->r, self->log, self->r->filename); |
3951 | + } |
3952 | + |
3953 | + if (PyObject_HasAttrString(self->sequence, "close")) { |
3954 | + PyObject *args = NULL; |
3955 | + PyObject *data = NULL; |
3956 | + |
3957 | + close = PyObject_GetAttrString(self->sequence, "close"); |
3958 | + |
3959 | + args = Py_BuildValue("()"); |
3960 | + data = PyEval_CallObject(close, args); |
3961 | + |
3962 | + Py_DECREF(args); |
3963 | + Py_XDECREF(data); |
3964 | + Py_DECREF(close); |
3965 | + } |
3966 | + |
3967 | + if (PyErr_Occurred()) |
3968 | + wsgi_log_python_error(self->r, self->log, self->r->filename); |
3969 | + |
3970 | + Py_DECREF(self->sequence); |
3971 | + |
3972 | + self->sequence = NULL; |
3973 | + } |
3974 | + |
3975 | + Py_DECREF(args); |
3976 | + Py_DECREF(start); |
3977 | + Py_DECREF(vars); |
3978 | + |
3979 | + /* |
3980 | + * Log warning if more response content generated than was |
3981 | + * indicated, or less if there was no errors generated by |
3982 | + * the application. |
3983 | + */ |
3984 | + |
3985 | + if (self->content_length_set && ((!PyErr_Occurred() && |
3986 | + self->output_length != self->content_length) || |
3987 | + (self->output_length > self->content_length))) { |
3988 | + ap_log_rerror(APLOG_MARK, WSGI_LOG_DEBUG(0), self->r, |
3989 | + "mod_wsgi (pid=%d): Content length mismatch, " |
3990 | + "expected %s, response generated %s: %s", getpid(), |
3991 | + apr_off_t_toa(self->r->pool, self->content_length), |
3992 | + apr_off_t_toa(self->r->pool, self->output_length), |
3993 | + self->r->filename); |
3994 | + } |
3995 | + |
3996 | + /* Log details of any final Python exceptions. */ |
3997 | + |
3998 | + if (PyErr_Occurred()) |
3999 | + wsgi_log_python_error(self->r, self->log, self->r->filename); |
4000 | + |
4001 | + /* |
4002 | + * If result indicates an internal server error, then |
4003 | + * replace the status line in the request object else |
4004 | + * that provided by the application will be what is used |
4005 | + * in any error page automatically generated by Apache. |
4006 | + */ |
4007 | + |
4008 | + if (self->result == HTTP_INTERNAL_SERVER_ERROR) |
4009 | + self->r->status_line = "500 Internal Server Error"; |
4010 | + |
4011 | + return self->result; |
4012 | +} |
4013 | + |
4014 | +static PyObject *Adapter_write(AdapterObject *self, PyObject *args) |
4015 | +{ |
4016 | + PyObject *item = NULL; |
4017 | + const char *data = NULL; |
4018 | + int length = 0; |
4019 | + |
4020 | + if (!self->r) { |
4021 | + PyErr_SetString(PyExc_RuntimeError, "request object has expired"); |
4022 | + return NULL; |
4023 | + } |
4024 | + |
4025 | + if (!PyArg_ParseTuple(args, "O:write", &item)) |
4026 | + return NULL; |
4027 | + |
4028 | +#if PY_MAJOR_VERSION >= 3 |
4029 | + if (PyUnicode_Check(item)) { |
4030 | + PyObject *latin_item; |
4031 | + latin_item = PyUnicode_AsLatin1String(item); |
4032 | + if (!latin_item) { |
4033 | + PyErr_Format(PyExc_TypeError, "byte string value expected, " |
4034 | + "value containing non 'latin-1' characters found"); |
4035 | + Py_DECREF(item); |
4036 | + return NULL; |
4037 | + } |
4038 | + |
4039 | + Py_DECREF(item); |
4040 | + item = latin_item; |
4041 | + } |
4042 | +#endif |
4043 | + |
4044 | + if (!PyString_Check(item)) { |
4045 | + PyErr_Format(PyExc_TypeError, "byte string value expected, value " |
4046 | + "of type %.200s found", item->ob_type->tp_name); |
4047 | + Py_DECREF(item); |
4048 | + return NULL; |
4049 | + } |
4050 | + |
4051 | + data = PyString_AsString(item); |
4052 | + length = PyString_Size(item); |
4053 | + |
4054 | + if (!Adapter_output(self, data, length, 1)) |
4055 | + return NULL; |
4056 | + |
4057 | + Py_INCREF(Py_None); |
4058 | + return Py_None; |
4059 | +} |
4060 | + |
4061 | +static PyObject *newStreamObject(AdapterObject *adapter, PyObject *filelike, |
4062 | + apr_size_t blksize); |
4063 | + |
4064 | +static PyObject *Adapter_file_wrapper(AdapterObject *self, PyObject *args) |
4065 | +{ |
4066 | + PyObject *filelike = NULL; |
4067 | + apr_size_t blksize = HUGE_STRING_LEN; |
4068 | + PyObject *result = NULL; |
4069 | + |
4070 | + if (!self->r) { |
4071 | + PyErr_SetString(PyExc_RuntimeError, "request object has expired"); |
4072 | + return NULL; |
4073 | + } |
4074 | + |
4075 | + if (!PyArg_ParseTuple(args, "O|l:file_wrapper", &filelike, &blksize)) |
4076 | + return NULL; |
4077 | + |
4078 | + return newStreamObject(self, filelike, blksize); |
4079 | +} |
4080 | + |
4081 | +static PyMethodDef Adapter_methods[] = { |
4082 | + { "start_response", (PyCFunction)Adapter_start_response, METH_VARARGS, 0 }, |
4083 | + { "write", (PyCFunction)Adapter_write, METH_VARARGS, 0 }, |
4084 | + { "file_wrapper", (PyCFunction)Adapter_file_wrapper, METH_VARARGS, 0 }, |
4085 | + { NULL, NULL} |
4086 | +}; |
4087 | + |
4088 | +static PyTypeObject Adapter_Type = { |
4089 | + PyVarObject_HEAD_INIT(NULL, 0) |
4090 | + "mod_wsgi.Adapter", /*tp_name*/ |
4091 | + sizeof(AdapterObject), /*tp_basicsize*/ |
4092 | + 0, /*tp_itemsize*/ |
4093 | + /* methods */ |
4094 | + (destructor)Adapter_dealloc, /*tp_dealloc*/ |
4095 | + 0, /*tp_print*/ |
4096 | + 0, /*tp_getattr*/ |
4097 | + 0, /*tp_setattr*/ |
4098 | + 0, /*tp_compare*/ |
4099 | + 0, /*tp_repr*/ |
4100 | + 0, /*tp_as_number*/ |
4101 | + 0, /*tp_as_sequence*/ |
4102 | + 0, /*tp_as_mapping*/ |
4103 | + 0, /*tp_hash*/ |
4104 | + 0, /*tp_call*/ |
4105 | + 0, /*tp_str*/ |
4106 | + 0, /*tp_getattro*/ |
4107 | + 0, /*tp_setattro*/ |
4108 | + 0, /*tp_as_buffer*/ |
4109 | + Py_TPFLAGS_DEFAULT, /*tp_flags*/ |
4110 | + 0, /*tp_doc*/ |
4111 | + 0, /*tp_traverse*/ |
4112 | + 0, /*tp_clear*/ |
4113 | + 0, /*tp_richcompare*/ |
4114 | + 0, /*tp_weaklistoffset*/ |
4115 | + 0, /*tp_iter*/ |
4116 | + 0, /*tp_iternext*/ |
4117 | + Adapter_methods, /*tp_methods*/ |
4118 | + 0, /*tp_members*/ |
4119 | + 0, /*tp_getset*/ |
4120 | + 0, /*tp_base*/ |
4121 | + 0, /*tp_dict*/ |
4122 | + 0, /*tp_descr_get*/ |
4123 | + 0, /*tp_descr_set*/ |
4124 | + 0, /*tp_dictoffset*/ |
4125 | + 0, /*tp_init*/ |
4126 | + 0, /*tp_alloc*/ |
4127 | + 0, /*tp_new*/ |
4128 | + 0, /*tp_free*/ |
4129 | + 0, /*tp_is_gc*/ |
4130 | +}; |
4131 | + |
4132 | +static PyObject *newStreamObject(AdapterObject *adapter, PyObject *filelike, |
4133 | + apr_size_t blksize) |
4134 | +{ |
4135 | + StreamObject *self; |
4136 | + |
4137 | + self = PyObject_New(StreamObject, &Stream_Type); |
4138 | + if (self == NULL) |
4139 | + return NULL; |
4140 | + |
4141 | + self->adapter = adapter; |
4142 | + self->filelike = filelike; |
4143 | + self->blksize = blksize; |
4144 | + |
4145 | + Py_INCREF(self->adapter); |
4146 | + Py_INCREF(self->filelike); |
4147 | + |
4148 | + return (PyObject *)self; |
4149 | +} |
4150 | + |
4151 | +static void Stream_dealloc(StreamObject *self) |
4152 | +{ |
4153 | + Py_DECREF(self->filelike); |
4154 | + Py_DECREF(self->adapter); |
4155 | + |
4156 | + PyObject_Del(self); |
4157 | +} |
4158 | + |
4159 | +static PyObject *Stream_iter(StreamObject *self) |
4160 | +{ |
4161 | + if (!self->adapter->r) { |
4162 | + PyErr_SetString(PyExc_RuntimeError, "request object has expired"); |
4163 | + return NULL; |
4164 | + } |
4165 | + |
4166 | + Py_INCREF(self); |
4167 | + return (PyObject *)self; |
4168 | +} |
4169 | + |
4170 | +static PyObject *Stream_iternext(StreamObject *self) |
4171 | +{ |
4172 | + PyObject *method = NULL; |
4173 | + PyObject *args = NULL; |
4174 | + PyObject *result = NULL; |
4175 | + |
4176 | + if (!self->adapter->r) { |
4177 | + PyErr_SetString(PyExc_RuntimeError, "request object has expired"); |
4178 | + return NULL; |
4179 | + } |
4180 | + |
4181 | + method = PyObject_GetAttrString(self->filelike, "read"); |
4182 | + |
4183 | + if (!method) { |
4184 | + PyErr_SetString(PyExc_KeyError, |
4185 | + "file like object has no read() method"); |
4186 | + return 0; |
4187 | + } |
4188 | + |
4189 | + args = Py_BuildValue("(l)", self->blksize); |
4190 | + result = PyEval_CallObject(method, args); |
4191 | + |
4192 | + Py_DECREF(method); |
4193 | + Py_DECREF(args); |
4194 | + |
4195 | + if (!result) |
4196 | + return 0; |
4197 | + |
4198 | + if (PyString_Check(result)) { |
4199 | + if (PyString_Size(result) == 0) { |
4200 | + PyErr_SetObject(PyExc_StopIteration, Py_None); |
4201 | + Py_DECREF(result); |
4202 | + return 0; |
4203 | + } |
4204 | + |
4205 | + return result; |
4206 | + } |
4207 | + |
4208 | +#if PY_MAJOR_VERSION >= 3 |
4209 | + if (PyUnicode_Check(result)) { |
4210 | + if (PyUnicode_GetSize(result) == 0) { |
4211 | + PyErr_SetObject(PyExc_StopIteration, Py_None); |
4212 | + Py_DECREF(result); |
4213 | + return 0; |
4214 | + } |
4215 | + |
4216 | + return result; |
4217 | + } |
4218 | +#endif |
4219 | + |
4220 | + Py_DECREF(result); |
4221 | + |
4222 | + PyErr_SetString(PyExc_TypeError, |
4223 | + "file like object yielded non string type"); |
4224 | + |
4225 | + return 0; |
4226 | +} |
4227 | + |
4228 | +static PyObject *Stream_close(StreamObject *self, PyObject *args) |
4229 | +{ |
4230 | + PyObject *method = NULL; |
4231 | + PyObject *result = NULL; |
4232 | + |
4233 | + method = PyObject_GetAttrString(self->filelike, "close"); |
4234 | + |
4235 | + if (method) { |
4236 | + result = PyEval_CallObject(method, (PyObject *)NULL); |
4237 | + if (!result) |
4238 | + PyErr_Clear(); |
4239 | + Py_DECREF(method); |
4240 | + } |
4241 | + |
4242 | + Py_XDECREF(result); |
4243 | + |
4244 | + Py_INCREF(Py_None); |
4245 | + return Py_None; |
4246 | +} |
4247 | + |
4248 | +static PyMethodDef Stream_methods[] = { |
4249 | + { "close", (PyCFunction)Stream_close, METH_VARARGS, 0 }, |
4250 | + { NULL, NULL} |
4251 | +}; |
4252 | + |
4253 | +static PyTypeObject Stream_Type = { |
4254 | + PyVarObject_HEAD_INIT(NULL, 0) |
4255 | + "mod_wsgi.Stream", /*tp_name*/ |
4256 | + sizeof(StreamObject), /*tp_basicsize*/ |
4257 | + 0, /*tp_itemsize*/ |
4258 | + /* methods */ |
4259 | + (destructor)Stream_dealloc, /*tp_dealloc*/ |
4260 | + 0, /*tp_print*/ |
4261 | + 0, /*tp_getattr*/ |
4262 | + 0, /*tp_setattr*/ |
4263 | + 0, /*tp_compare*/ |
4264 | + 0, /*tp_repr*/ |
4265 | + 0, /*tp_as_number*/ |
4266 | + 0, /*tp_as_sequence*/ |
4267 | + 0, /*tp_as_mapping*/ |
4268 | + 0, /*tp_hash*/ |
4269 | + 0, /*tp_call*/ |
4270 | + 0, /*tp_str*/ |
4271 | + 0, /*tp_getattro*/ |
4272 | + 0, /*tp_setattro*/ |
4273 | + 0, /*tp_as_buffer*/ |
4274 | +#if defined(Py_TPFLAGS_HAVE_ITER) |
4275 | + Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_ITER, /*tp_flags*/ |
4276 | +#else |
4277 | + Py_TPFLAGS_DEFAULT, /*tp_flags*/ |
4278 | +#endif |
4279 | + 0, /*tp_doc*/ |
4280 | + 0, /*tp_traverse*/ |
4281 | + 0, /*tp_clear*/ |
4282 | + 0, /*tp_richcompare*/ |
4283 | + 0, /*tp_weaklistoffset*/ |
4284 | + (getiterfunc)Stream_iter, /*tp_iter*/ |
4285 | + (iternextfunc)Stream_iternext, /*tp_iternext*/ |
4286 | + Stream_methods, /*tp_methods*/ |
4287 | + 0, /*tp_members*/ |
4288 | + 0, /*tp_getset*/ |
4289 | + 0, /*tp_base*/ |
4290 | + 0, /*tp_dict*/ |
4291 | + 0, /*tp_descr_get*/ |
4292 | + 0, /*tp_descr_set*/ |
4293 | + 0, /*tp_dictoffset*/ |
4294 | + 0, /*tp_init*/ |
4295 | + 0, /*tp_alloc*/ |
4296 | + 0, /*tp_new*/ |
4297 | + 0, /*tp_free*/ |
4298 | + 0, /*tp_is_gc*/ |
4299 | +}; |
4300 | + |
4301 | +/* Restricted object to stop access to STDIN/STDOUT. */ |
4302 | + |
4303 | +typedef struct { |
4304 | + PyObject_HEAD |
4305 | + const char *s; |
4306 | +} RestrictedObject; |
4307 | + |
4308 | +static PyTypeObject Restricted_Type; |
4309 | + |
4310 | +static RestrictedObject *newRestrictedObject(const char *s) |
4311 | +{ |
4312 | + RestrictedObject *self; |
4313 | + |
4314 | + self = PyObject_New(RestrictedObject, &Restricted_Type); |
4315 | + if (self == NULL) |
4316 | + return NULL; |
4317 | + |
4318 | + self->s = s; |
4319 | + |
4320 | + return self; |
4321 | +} |
4322 | + |
4323 | +static void Restricted_dealloc(RestrictedObject *self) |
4324 | +{ |
4325 | + PyObject_Del(self); |
4326 | +} |
4327 | + |
4328 | +static PyObject *Restricted_getattr(RestrictedObject *self, char *name) |
4329 | +{ |
4330 | + PyErr_Format(PyExc_IOError, "%s access restricted by mod_wsgi", self->s); |
4331 | + |
4332 | + return NULL; |
4333 | +} |
4334 | + |
4335 | +static PyTypeObject Restricted_Type = { |
4336 | + PyVarObject_HEAD_INIT(NULL, 0) |
4337 | + "mod_wsgi.Restricted", /*tp_name*/ |
4338 | + sizeof(RestrictedObject), /*tp_basicsize*/ |
4339 | + 0, /*tp_itemsize*/ |
4340 | + /* methods */ |
4341 | + (destructor)Restricted_dealloc, /*tp_dealloc*/ |
4342 | + 0, /*tp_print*/ |
4343 | + (getattrfunc)Restricted_getattr, /*tp_getattr*/ |
4344 | + 0, /*tp_setattr*/ |
4345 | + 0, /*tp_compare*/ |
4346 | + 0, /*tp_repr*/ |
4347 | + 0, /*tp_as_number*/ |
4348 | + 0, /*tp_as_sequence*/ |
4349 | + 0, /*tp_as_mapping*/ |
4350 | + 0, /*tp_hash*/ |
4351 | + 0, /*tp_call*/ |
4352 | + 0, /*tp_str*/ |
4353 | + 0, /*tp_getattro*/ |
4354 | + 0, /*tp_setattro*/ |
4355 | + 0, /*tp_as_buffer*/ |
4356 | + Py_TPFLAGS_DEFAULT, /*tp_flags*/ |
4357 | + 0, /*tp_doc*/ |
4358 | + 0, /*tp_traverse*/ |
4359 | + 0, /*tp_clear*/ |
4360 | + 0, /*tp_richcompare*/ |
4361 | + 0, /*tp_weaklistoffset*/ |
4362 | + 0, /*tp_iter*/ |
4363 | + 0, /*tp_iternext*/ |
4364 | + 0, /*tp_methods*/ |
4365 | + 0, /*tp_members*/ |
4366 | + 0, /*tp_getset*/ |
4367 | + 0, /*tp_base*/ |
4368 | + 0, /*tp_dict*/ |
4369 | + 0, /*tp_descr_get*/ |
4370 | + 0, /*tp_descr_set*/ |
4371 | + 0, /*tp_dictoffset*/ |
4372 | + 0, /*tp_init*/ |
4373 | + 0, /*tp_alloc*/ |
4374 | + 0, /*tp_new*/ |
4375 | + 0, /*tp_free*/ |
4376 | + 0, /*tp_is_gc*/ |
4377 | +}; |
4378 | + |
4379 | +/* Function to restrict access to use of signal(). */ |
4380 | + |
4381 | +static PyObject *wsgi_signal_intercept(PyObject *self, PyObject *args) |
4382 | +{ |
4383 | + PyObject *h = NULL; |
4384 | + int n = 0; |
4385 | + |
4386 | + PyObject *m = NULL; |
4387 | + |
4388 | + if (!PyArg_ParseTuple(args, "iO:signal", &n, &h)) |
4389 | + return NULL; |
4390 | + |
4391 | + Py_BEGIN_ALLOW_THREADS |
4392 | + ap_log_error(APLOG_MARK, WSGI_LOG_WARNING(0), wsgi_server, |
4393 | + "mod_wsgi (pid=%d): Callback registration for " |
4394 | + "signal %d ignored.", getpid(), n); |
4395 | + Py_END_ALLOW_THREADS |
4396 | + |
4397 | + m = PyImport_ImportModule("traceback"); |
4398 | + |
4399 | + if (m) { |
4400 | + PyObject *d = NULL; |
4401 | + PyObject *o = NULL; |
4402 | + d = PyModule_GetDict(m); |
4403 | + o = PyDict_GetItemString(d, "print_stack"); |
4404 | + if (o) { |
4405 | + PyObject *log = NULL; |
4406 | + PyObject *args = NULL; |
4407 | + PyObject *result = NULL; |
4408 | + Py_INCREF(o); |
4409 | + log = newLogObject(NULL, APLOG_WARNING, NULL); |
4410 | + args = Py_BuildValue("(OOO)", Py_None, Py_None, log); |
4411 | + result = PyEval_CallObject(o, args); |
4412 | + Py_XDECREF(result); |
4413 | + Py_DECREF(args); |
4414 | + Py_DECREF(log); |
4415 | + Py_DECREF(o); |
4416 | + } |
4417 | + } |
4418 | + |
4419 | + Py_XDECREF(m); |
4420 | + |
4421 | + Py_INCREF(h); |
4422 | + |
4423 | + return h; |
4424 | +} |
4425 | + |
4426 | +static PyMethodDef wsgi_signal_method[] = { |
4427 | + { "signal", (PyCFunction)wsgi_signal_intercept, METH_VARARGS, 0 }, |
4428 | + { NULL, NULL } |
4429 | +}; |
4430 | + |
4431 | +/* Wrapper around Python interpreter instances. */ |
4432 | + |
4433 | +static const char *wsgi_python_path = NULL; |
4434 | +static const char *wsgi_python_eggs = NULL; |
4435 | + |
4436 | +#if APR_HAS_THREADS |
4437 | +static int wsgi_thread_count = 0; |
4438 | +static apr_threadkey_t *wsgi_thread_key; |
4439 | +#endif |
4440 | + |
4441 | +typedef struct { |
4442 | + PyObject_HEAD |
4443 | + char *name; |
4444 | + PyInterpreterState *interp; |
4445 | + int owner; |
4446 | +#if APR_HAS_THREADS |
4447 | + apr_hash_t *tstate_table; |
4448 | +#else |
4449 | + PyThreadState *tstate; |
4450 | +#endif |
4451 | +} InterpreterObject; |
4452 | + |
4453 | +static PyTypeObject Interpreter_Type; |
4454 | + |
4455 | +static InterpreterObject *newInterpreterObject(const char *name) |
4456 | +{ |
4457 | + PyInterpreterState *interp = NULL; |
4458 | + InterpreterObject *self = NULL; |
4459 | + PyThreadState *tstate = NULL; |
4460 | + PyThreadState *save_tstate = NULL; |
4461 | + PyObject *module = NULL; |
4462 | + PyObject *object = NULL; |
4463 | + PyObject *item = NULL; |
4464 | + |
4465 | + /* Create handle for interpreter and local data. */ |
4466 | + |
4467 | + self = PyObject_New(InterpreterObject, &Interpreter_Type); |
4468 | + if (self == NULL) |
4469 | + return NULL; |
4470 | + |
4471 | + /* |
4472 | + * If interpreter not named, then we want to bind |
4473 | + * to the first Python interpreter instance created. |
4474 | + * Give this interpreter an empty string as name. |
4475 | + */ |
4476 | + |
4477 | + if (!name) { |
4478 | + interp = PyInterpreterState_Head(); |
4479 | + while (interp->next) |
4480 | + interp = interp->next; |
4481 | + |
4482 | + name = ""; |
4483 | + } |
4484 | + |
4485 | + /* Save away the interpreter name. */ |
4486 | + |
4487 | + self->name = strdup(name); |
4488 | + |
4489 | + if (interp) { |
4490 | + /* |
4491 | + * Interpreter provided to us so will not be |
4492 | + * responsible for deleting it later. This will |
4493 | + * be the case for the main Python interpreter. |
4494 | + */ |
4495 | + |
4496 | + ap_log_error(APLOG_MARK, WSGI_LOG_INFO(0), wsgi_server, |
4497 | + "mod_wsgi (pid=%d): Attach interpreter '%s'.", |
4498 | + getpid(), name); |
4499 | + |
4500 | + self->interp = interp; |
4501 | + self->owner = 0; |
4502 | + } |
4503 | + else { |
4504 | + /* |
4505 | + * Remember active thread state so can restore |
4506 | + * it. This is actually the thread state |
4507 | + * associated with simplified GIL state API. |
4508 | + */ |
4509 | + |
4510 | + save_tstate = PyThreadState_Swap(NULL); |
4511 | + |
4512 | + /* |
4513 | + * Create the interpreter. If creation of the |
4514 | + * interpreter fails it will restore the |
4515 | + * existing active thread state for us so don't |
4516 | + * need to worry about it in that case. |
4517 | + */ |
4518 | + |
4519 | + tstate = Py_NewInterpreter(); |
4520 | + |
4521 | + if (!tstate) { |
4522 | + PyErr_SetString(PyExc_RuntimeError, "Py_NewInterpreter() failed"); |
4523 | + |
4524 | + Py_DECREF(self); |
4525 | + |
4526 | + return NULL; |
4527 | + } |
4528 | + |
4529 | + Py_BEGIN_ALLOW_THREADS |
4530 | + ap_log_error(APLOG_MARK, WSGI_LOG_INFO(0), wsgi_server, |
4531 | + "mod_wsgi (pid=%d): Create interpreter '%s'.", |
4532 | + getpid(), name); |
4533 | + Py_END_ALLOW_THREADS |
4534 | + |
4535 | + self->interp = tstate->interp; |
4536 | + self->owner = 1; |
4537 | + } |
4538 | + |
4539 | + /* |
4540 | + * Install restricted objects for STDIN and STDOUT, |
4541 | + * or log object for STDOUT as appropriate. Don't do |
4542 | + * this if not running on Win32 and we believe we |
4543 | + * are running in single process mode, otherwise |
4544 | + * it prevents use of interactive debuggers such as |
4545 | + * the 'pdb' module. |
4546 | + */ |
4547 | + |
4548 | + object = newLogObject(NULL, APLOG_ERR, "stderr"); |
4549 | + PySys_SetObject("stderr", object); |
4550 | + Py_DECREF(object); |
4551 | + |
4552 | +#ifndef WIN32 |
4553 | + if (wsgi_parent_pid != getpid()) { |
4554 | +#endif |
4555 | + if (wsgi_server_config->restrict_stdout == 1) { |
4556 | + object = (PyObject *)newRestrictedObject("sys.stdout"); |
4557 | + PySys_SetObject("stdout", object); |
4558 | + Py_DECREF(object); |
4559 | + } |
4560 | + else { |
4561 | + object = newLogObject(NULL, APLOG_ERR, "stdout"); |
4562 | + PySys_SetObject("stdout", object); |
4563 | + Py_DECREF(object); |
4564 | + } |
4565 | + |
4566 | + if (wsgi_server_config->restrict_stdin == 1) { |
4567 | + object = (PyObject *)newRestrictedObject("sys.stdin"); |
4568 | + PySys_SetObject("stdin", object); |
4569 | + Py_DECREF(object); |
4570 | + } |
4571 | +#ifndef WIN32 |
4572 | + } |
4573 | +#endif |
4574 | + |
4575 | + /* |
4576 | + * Set sys.argv to one element list to fake out |
4577 | + * modules that look there for Python command |
4578 | + * line arguments as appropriate. |
4579 | + */ |
4580 | + |
4581 | + object = PyList_New(0); |
4582 | +#if PY_MAJOR_VERSION >= 3 |
4583 | + item = PyUnicode_FromString("mod_wsgi"); |
4584 | +#else |
4585 | + item = PyString_FromString("mod_wsgi"); |
4586 | +#endif |
4587 | + PyList_Append(object, item); |
4588 | + PySys_SetObject("argv", object); |
4589 | + Py_DECREF(item); |
4590 | + Py_DECREF(object); |
4591 | + |
4592 | + /* |
4593 | + * Install intercept for signal handler registration |
4594 | + * if appropriate. |
4595 | + */ |
4596 | + |
4597 | + if (wsgi_server_config->restrict_signal != 0) { |
4598 | + module = PyImport_ImportModule("signal"); |
4599 | + PyModule_AddObject(module, "signal", PyCFunction_New( |
4600 | + &wsgi_signal_method[0], NULL)); |
4601 | + Py_DECREF(module); |
4602 | + } |
4603 | + |
4604 | + /* |
4605 | + * If running in daemon process, override as appropriate |
4606 | + * the USER, USERNAME or LOGNAME environment variables |
4607 | + * so that they match the user that the process is running |
4608 | + * as. Need to do this else we inherit the value from the |
4609 | + * Apache parent process which is likely wrong as will be |
4610 | + * root or the user than ran sudo when Apache started. |
4611 | + * Can't update these for normal Apache child processes |
4612 | + * as that would change the expected environment of other |
4613 | + * Apache modules. |
4614 | + */ |
4615 | + |
4616 | +#ifndef WIN32 |
4617 | + if (wsgi_daemon_pool) { |
4618 | + module = PyImport_ImportModule("os"); |
4619 | + |
4620 | + if (module) { |
4621 | + PyObject *dict = NULL; |
4622 | + PyObject *key = NULL; |
4623 | + PyObject *value = NULL; |
4624 | + |
4625 | + dict = PyModule_GetDict(module); |
4626 | + object = PyDict_GetItemString(dict, "environ"); |
4627 | + |
4628 | + if (object) { |
4629 | + struct passwd *pwent; |
4630 | + |
4631 | + pwent = getpwuid(geteuid()); |
4632 | + |
4633 | + if (getenv("USER")) { |
4634 | +#if PY_MAJOR_VERSION >= 3 |
4635 | + key = PyUnicode_FromString("USER"); |
4636 | + value = PyUnicode_Decode(pwent->pw_name, |
4637 | + strlen(pwent->pw_name), |
4638 | + Py_FileSystemDefaultEncoding, |
4639 | + "surrogateescape"); |
4640 | +#else |
4641 | + key = PyString_FromString("USER"); |
4642 | + value = PyString_FromString(pwent->pw_name); |
4643 | +#endif |
4644 | + |
4645 | + PyObject_SetItem(object, key, value); |
4646 | + |
4647 | + Py_DECREF(key); |
4648 | + Py_DECREF(value); |
4649 | + } |
4650 | + |
4651 | + if (getenv("USERNAME")) { |
4652 | +#if PY_MAJOR_VERSION >= 3 |
4653 | + key = PyUnicode_FromString("USERNAME"); |
4654 | + value = PyUnicode_Decode(pwent->pw_name, |
4655 | + strlen(pwent->pw_name), |
4656 | + Py_FileSystemDefaultEncoding, |
4657 | + "surrogateescape"); |
4658 | +#else |
4659 | + key = PyString_FromString("USERNAME"); |
4660 | + value = PyString_FromString(pwent->pw_name); |
4661 | +#endif |
4662 | + |
4663 | + PyObject_SetItem(object, key, value); |
4664 | + |
4665 | + Py_DECREF(key); |
4666 | + Py_DECREF(value); |
4667 | + } |
4668 | + |
4669 | + if (getenv("LOGNAME")) { |
4670 | +#if PY_MAJOR_VERSION >= 3 |
4671 | + key = PyUnicode_FromString("LOGNAME"); |
4672 | + value = PyUnicode_Decode(pwent->pw_name, |
4673 | + strlen(pwent->pw_name), |
4674 | + Py_FileSystemDefaultEncoding, |
4675 | + "surrogateescape"); |
4676 | +#else |
4677 | + key = PyString_FromString("LOGNAME"); |
4678 | + value = PyString_FromString(pwent->pw_name); |
4679 | +#endif |
4680 | + |
4681 | + PyObject_SetItem(object, key, value); |
4682 | + |
4683 | + Py_DECREF(key); |
4684 | + Py_DECREF(value); |
4685 | + } |
4686 | + } |
4687 | + |
4688 | + Py_DECREF(module); |
4689 | + } |
4690 | + } |
4691 | +#endif |
4692 | + |
4693 | + /* |
4694 | + * If running in daemon process, override HOME environment |
4695 | + * variable so that is matches the home directory of the |
4696 | + * user that the process is running as. Need to do this as |
4697 | + * Apache will inherit HOME from root user or user that ran |
4698 | + * sudo and started Apache and this would be wrong. Can't |
4699 | + * update HOME for normal Apache child processes as that |
4700 | + * would change the expected environment of other Apache |
4701 | + * modules. |
4702 | + */ |
4703 | + |
4704 | +#ifndef WIN32 |
4705 | + if (wsgi_daemon_pool) { |
4706 | + module = PyImport_ImportModule("os"); |
4707 | + |
4708 | + if (module) { |
4709 | + PyObject *dict = NULL; |
4710 | + PyObject *key = NULL; |
4711 | + PyObject *value = NULL; |
4712 | + |
4713 | + dict = PyModule_GetDict(module); |
4714 | + object = PyDict_GetItemString(dict, "environ"); |
4715 | + |
4716 | + if (object) { |
4717 | + struct passwd *pwent; |
4718 | + |
4719 | + pwent = getpwuid(geteuid()); |
4720 | +#if PY_MAJOR_VERSION >= 3 |
4721 | + key = PyUnicode_FromString("HOME"); |
4722 | + value = PyUnicode_Decode(pwent->pw_dir, strlen(pwent->pw_dir), |
4723 | + Py_FileSystemDefaultEncoding, |
4724 | + "surrogateescape"); |
4725 | +#else |
4726 | + key = PyString_FromString("HOME"); |
4727 | + value = PyString_FromString(pwent->pw_dir); |
4728 | +#endif |
4729 | + |
4730 | + PyObject_SetItem(object, key, value); |
4731 | + |
4732 | + Py_DECREF(key); |
4733 | + Py_DECREF(value); |
4734 | + } |
4735 | + |
4736 | + Py_DECREF(module); |
4737 | + } |
4738 | + } |
4739 | +#endif |
4740 | + |
4741 | + /* |
4742 | + * Explicitly override the PYTHON_EGG_CACHE variable if it |
4743 | + * was defined by Apache configuration. For embedded processes |
4744 | + * this would have been done by using WSGIPythonEggs directive. |
4745 | + * For daemon processes the 'python-eggs' option to the |
4746 | + * WSGIDaemonProcess directive would have needed to be used. |
4747 | + */ |
4748 | + |
4749 | + if (!wsgi_daemon_pool) |
4750 | + wsgi_python_eggs = wsgi_server_config->python_eggs; |
4751 | + |
4752 | + if (wsgi_python_eggs) { |
4753 | + module = PyImport_ImportModule("os"); |
4754 | + |
4755 | + if (module) { |
4756 | + PyObject *dict = NULL; |
4757 | + PyObject *key = NULL; |
4758 | + PyObject *value = NULL; |
4759 | + |
4760 | + dict = PyModule_GetDict(module); |
4761 | + object = PyDict_GetItemString(dict, "environ"); |
4762 | + |
4763 | + if (object) { |
4764 | +#if PY_MAJOR_VERSION >= 3 |
4765 | + key = PyUnicode_FromString("PYTHON_EGG_CACHE"); |
4766 | + value = PyUnicode_Decode(wsgi_python_eggs, |
4767 | + strlen(wsgi_python_eggs), |
4768 | + Py_FileSystemDefaultEncoding, |
4769 | + "surrogateescape"); |
4770 | +#else |
4771 | + key = PyString_FromString("PYTHON_EGG_CACHE"); |
4772 | + value = PyString_FromString(wsgi_python_eggs); |
4773 | +#endif |
4774 | + |
4775 | + PyObject_SetItem(object, key, value); |
4776 | + |
4777 | + Py_DECREF(key); |
4778 | + Py_DECREF(value); |
4779 | + } |
4780 | + |
4781 | + Py_DECREF(module); |
4782 | + } |
4783 | + } |
4784 | + |
4785 | + /* |
4786 | + * Install user defined Python module search path. This is |
4787 | + * added using site.addsitedir() so that any Python .pth |
4788 | + * files are opened and additional directories so defined |
4789 | + * are added to default Python search path as well. This |
4790 | + * allows virtual Python environments to work. Note that |
4791 | + * site.addsitedir() adds new directories at the end of |
4792 | + * sys.path when they really need to be added in order at |
4793 | + * the start. We therefore need to do a fiddle and shift |
4794 | + * any newly added directories to the start of sys.path. |
4795 | + */ |
4796 | + |
4797 | + if (!wsgi_daemon_pool) |
4798 | + wsgi_python_path = wsgi_server_config->python_path; |
4799 | + |
4800 | + if (wsgi_python_path) { |
4801 | + PyObject *path = NULL; |
4802 | + |
4803 | + module = PyImport_ImportModule("site"); |
4804 | + path = PySys_GetObject("path"); |
4805 | + |
4806 | + if (module && path) { |
4807 | + PyObject *dict = NULL; |
4808 | + |
4809 | + PyObject *old = NULL; |
4810 | + PyObject *new = NULL; |
4811 | + PyObject *tmp = NULL; |
4812 | + |
4813 | + PyObject *item = NULL; |
4814 | + |
4815 | + int i = 0; |
4816 | + |
4817 | + old = PyList_New(0); |
4818 | + new = PyList_New(0); |
4819 | + tmp = PyList_New(0); |
4820 | + |
4821 | + for (i=0; i<PyList_Size(path); i++) |
4822 | + PyList_Append(old, PyList_GetItem(path, i)); |
4823 | + |
4824 | + dict = PyModule_GetDict(module); |
4825 | + object = PyDict_GetItemString(dict, "addsitedir"); |
4826 | + |
4827 | + if (object) { |
4828 | + const char *start; |
4829 | + const char *end; |
4830 | + const char *value; |
4831 | + |
4832 | + PyObject *item; |
4833 | + PyObject *args; |
4834 | + |
4835 | + PyObject *result = NULL; |
4836 | + |
4837 | + Py_INCREF(object); |
4838 | + |
4839 | + start = wsgi_python_path; |
4840 | + end = strchr(start, DELIM); |
4841 | + |
4842 | + if (end) { |
4843 | +#if PY_MAJOR_VERSION >= 3 |
4844 | + item = PyUnicode_Decode(start, end-start, |
4845 | + Py_FileSystemDefaultEncoding, |
4846 | + "surrogateescape"); |
4847 | +#else |
4848 | + item = PyString_FromStringAndSize(start, end-start); |
4849 | +#endif |
4850 | + start = end+1; |
4851 | + |
4852 | + value = PyString_AsString(item); |
4853 | + |
4854 | + Py_BEGIN_ALLOW_THREADS |
4855 | + ap_log_error(APLOG_MARK, WSGI_LOG_INFO(0), wsgi_server, |
4856 | + "mod_wsgi (pid=%d): Adding '%s' to " |
4857 | + "path.", getpid(), value); |
4858 | + Py_END_ALLOW_THREADS |
4859 | + |
4860 | + args = Py_BuildValue("(O)", item); |
4861 | + result = PyEval_CallObject(object, args); |
4862 | + |
4863 | + if (!result) { |
4864 | + Py_BEGIN_ALLOW_THREADS |
4865 | + ap_log_error(APLOG_MARK, WSGI_LOG_ERR(0), wsgi_server, |
4866 | + "mod_wsgi (pid=%d): Call to " |
4867 | + "'site.addsitedir()' failed for '%s', " |
4868 | + "stopping.", getpid(), value); |
4869 | + Py_END_ALLOW_THREADS |
4870 | + } |
4871 | + |
4872 | + Py_XDECREF(result); |
4873 | + Py_DECREF(item); |
4874 | + Py_DECREF(args); |
4875 | + |
4876 | + end = strchr(start, DELIM); |
4877 | + |
4878 | + while (result && end) { |
4879 | +#if PY_MAJOR_VERSION >= 3 |
4880 | + item = PyUnicode_Decode(start, end-start, |
4881 | + Py_FileSystemDefaultEncoding, |
4882 | + "surrogateescape"); |
4883 | +#else |
4884 | + item = PyString_FromStringAndSize(start, end-start); |
4885 | +#endif |
4886 | + start = end+1; |
4887 | + |
4888 | + value = PyString_AsString(item); |
4889 | + |
4890 | + Py_BEGIN_ALLOW_THREADS |
4891 | + ap_log_error(APLOG_MARK, WSGI_LOG_INFO(0), wsgi_server, |
4892 | + "mod_wsgi (pid=%d): Adding '%s' to " |
4893 | + "path.", getpid(), value); |
4894 | + Py_END_ALLOW_THREADS |
4895 | + |
4896 | + args = Py_BuildValue("(O)", item); |
4897 | + result = PyEval_CallObject(object, args); |
4898 | + |
4899 | + if (!result) { |
4900 | + Py_BEGIN_ALLOW_THREADS |
4901 | + ap_log_error(APLOG_MARK, WSGI_LOG_ERR(0), |
4902 | + wsgi_server, "mod_wsgi (pid=%d): " |
4903 | + "Call to 'site.addsitedir()' failed " |
4904 | + "for '%s', stopping.", |
4905 | + getpid(), value); |
4906 | + Py_END_ALLOW_THREADS |
4907 | + } |
4908 | + |
4909 | + Py_XDECREF(result); |
4910 | + Py_DECREF(item); |
4911 | + Py_DECREF(args); |
4912 | + |
4913 | + end = strchr(start, DELIM); |
4914 | + } |
4915 | + } |
4916 | + |
4917 | + Py_BEGIN_ALLOW_THREADS |
4918 | + ap_log_error(APLOG_MARK, WSGI_LOG_INFO(0), wsgi_server, |
4919 | + "mod_wsgi (pid=%d): Adding '%s' to " |
4920 | + "path.", getpid(), start); |
4921 | + Py_END_ALLOW_THREADS |
4922 | + |
4923 | + args = Py_BuildValue("(s)", start); |
4924 | + result = PyEval_CallObject(object, args); |
4925 | + |
4926 | + if (!result) { |
4927 | + Py_BEGIN_ALLOW_THREADS |
4928 | + ap_log_error(APLOG_MARK, WSGI_LOG_ERR(0), wsgi_server, |
4929 | + "mod_wsgi (pid=%d): Call to " |
4930 | + "'site.addsitedir()' failed for '%s'.", |
4931 | + getpid(), start); |
4932 | + Py_END_ALLOW_THREADS |
4933 | + } |
4934 | + |
4935 | + Py_XDECREF(result); |
4936 | + Py_DECREF(args); |
4937 | + |
4938 | + Py_DECREF(object); |
4939 | + } |
4940 | + else { |
4941 | + Py_BEGIN_ALLOW_THREADS |
4942 | + ap_log_error(APLOG_MARK, WSGI_LOG_ERR(0), wsgi_server, |
4943 | + "mod_wsgi (pid=%d): Unable to locate " |
4944 | + "'site.addsitedir()'.", getpid()); |
4945 | + Py_END_ALLOW_THREADS |
4946 | + } |
4947 | + |
4948 | + for (i=0; i<PyList_Size(path); i++) |
4949 | + PyList_Append(tmp, PyList_GetItem(path, i)); |
4950 | + |
4951 | + for (i=0; i<PyList_Size(tmp); i++) { |
4952 | + item = PyList_GetItem(tmp, i); |
4953 | + if (!PySequence_Contains(old, item)) { |
4954 | + int index = PySequence_Index(path, item); |
4955 | + PyList_Append(new, item); |
4956 | + if (index != -1) |
4957 | + PySequence_DelItem(path, index); |
4958 | + } |
4959 | + } |
4960 | + |
4961 | + PyList_SetSlice(path, 0, 0, new); |
4962 | + |
4963 | + Py_DECREF(old); |
4964 | + Py_DECREF(new); |
4965 | + Py_DECREF(tmp); |
4966 | + } |
4967 | + else { |
4968 | + if (!module) { |
4969 | + Py_BEGIN_ALLOW_THREADS |
4970 | + ap_log_error(APLOG_MARK, WSGI_LOG_ERR(0), wsgi_server, |
4971 | + "mod_wsgi (pid=%d): Unable to import 'site' " |
4972 | + "module.", getpid()); |
4973 | + Py_END_ALLOW_THREADS |
4974 | + } |
4975 | + |
4976 | + if (!path) { |
4977 | + Py_BEGIN_ALLOW_THREADS |
4978 | + ap_log_error(APLOG_MARK, WSGI_LOG_ERR(0), wsgi_server, |
4979 | + "mod_wsgi (pid=%d): Lookup for 'sys.path' " |
4980 | + "failed.", getpid()); |
4981 | + Py_END_ALLOW_THREADS |
4982 | + } |
4983 | + } |
4984 | + |
4985 | + Py_XDECREF(module); |
4986 | + } |
4987 | + |
4988 | + /* |
4989 | + * Create 'mod_wsgi' Python module. We first try and import an |
4990 | + * external Python module of the same name. The intent is |
4991 | + * that this external module would provide optional features |
4992 | + * implementable using pure Python code. Don't want to |
4993 | + * include them in the main Apache mod_wsgi package as that |
4994 | + * complicates that package and also wouldn't allow them to |
4995 | + * be released to a separate schedule. It is easier for |
4996 | + * people to replace Python modules package with a new |
4997 | + * version than it is to replace Apache module package. |
4998 | + */ |
4999 | + |
5000 | + module = PyImport_ImportModule("mod_wsgi"); |
The diff has been truncated for viewing.
There's conflicts. This can't be merged as is.