~ubuntu-branches/ubuntu/saucy/mod-wsgi/saucy-updates

« back to all changes in this revision

Viewing changes to mod_wsgi.c

  • Committer: Bazaar Package Importer
  • Author(s): Piotr Ożarowski
  • Date: 2010-03-22 20:05:19 UTC
  • mto: (3.1.7 sid) (1.4.2 upstream) (13.1.1 sid)
  • mto: This revision was merged to the branch mainline in revision 13.
  • Revision ID: james.westby@ubuntu.com-20100322200519-avmnljamf88nc0xb
Import upstream version 3.2

Show diffs side-by-side

added added

removed removed

Lines of Context:
33
33
 
34
34
#include "httpd.h"
35
35
 
 
36
#if !defined(HTTPD_ROOT)
 
37
#error Sorry, Apache developer package does not appear to be installed.
 
38
#endif
 
39
 
36
40
#if !defined(AP_SERVER_MAJORVERSION_NUMBER)
37
41
#if AP_MODULE_MAGIC_AT_LEAST(20010224,0)
38
42
#define AP_SERVER_MAJORVERSION_NUMBER 2
39
43
#define AP_SERVER_MINORVERSION_NUMBER 0
 
44
#define AP_SERVER_PATCHLEVEL_NUMBER 0
40
45
#else
41
46
#define AP_SERVER_MAJORVERSION_NUMBER 1
42
47
#define AP_SERVER_MINORVERSION_NUMBER 3
 
48
#define AP_SERVER_PATCHLEVEL_NUMBER 0
43
49
#endif
44
50
#endif
45
51
 
52
58
#define APR_SUCCESS 0
53
59
typedef pool apr_pool_t;
54
60
typedef unsigned int apr_port_t;
 
61
#include "ap_ctype.h"
55
62
#include "ap_alloc.h"
 
63
#define apr_isspace ap_isspace
56
64
#define apr_table_make ap_make_table
57
65
#define apr_table_get ap_table_get
58
66
#define apr_table_set ap_table_set
74
82
#define apr_pstrcat ap_pstrcat
75
83
#define apr_pcalloc ap_pcalloc
76
84
#define apr_palloc ap_palloc
 
85
#define apr_isalnum isalnum
 
86
#define apr_toupper toupper
77
87
typedef time_t apr_time_t;
78
88
#include "http_config.h"
79
89
typedef int apr_lockmech_e;
80
90
#else
 
91
#include "apr_lib.h"
81
92
#include "ap_mpm.h"
82
93
#include "ap_compat.h"
83
94
#include "apr_tables.h"
96
107
#include "util_script.h"
97
108
#include "util_md5.h"
98
109
 
 
110
#ifndef APR_FPROT_GWRITE
 
111
#define APR_FPROT_GWRITE APR_GWRITE
 
112
#endif
 
113
#ifndef APR_FPROT_WWRITE
 
114
#define APR_FPROT_WWRITE APR_WWRITE
 
115
#endif
 
116
 
99
117
#if !AP_MODULE_MAGIC_AT_LEAST(20050127,0)
100
118
/* Debian backported ap_regex_t to Apache 2.0 and
101
119
 * thus made official version checking break. */
106
124
#endif
107
125
#endif
108
126
 
 
127
#if !AP_MODULE_MAGIC_AT_LEAST(20081201,0)
 
128
#define ap_unixd_config unixd_config
 
129
#endif
 
130
 
109
131
#ifndef WIN32
110
132
#include <pwd.h>
111
133
#endif
112
134
 
113
135
#include "Python.h"
 
136
 
 
137
#if !defined(PY_VERSION_HEX)
 
138
#error Sorry, Python developer package does not appear to be installed.
 
139
#endif
 
140
 
 
141
#if PY_VERSION_HEX <= 0x02030000
 
142
#error Sorry, mod_wsgi requires at least Python 2.3.0 for Python 2.X.
 
143
#endif
 
144
 
 
145
#if PY_VERSION_HEX >= 0x03000000 && PY_VERSION_HEX < 0x03010000
 
146
#error Sorry, mod_wsgi requires at least Python 3.1.0 for Python 3.X.
 
147
#endif
 
148
 
 
149
#if !defined(WITH_THREAD)
 
150
#error Sorry, mod_wsgi requires that Python supporting thread.
 
151
#endif
 
152
 
114
153
#include "compile.h"
115
154
#include "node.h"
116
155
#include "osdefs.h"
117
156
 
118
 
#if !defined(PY_VERSION_HEX) || PY_VERSION_HEX <= 0x02030000
119
 
#error Sorry, mod_wsgi requires at least Python 2.3.0.
 
157
#ifndef PyVarObject_HEAD_INIT
 
158
#define PyVarObject_HEAD_INIT(type, size)       \
 
159
        PyObject_HEAD_INIT(type) size,
120
160
#endif
121
161
 
122
 
#if !defined(WITH_THREAD)
123
 
#error Sorry, mod_wsgi requires that Python supporting thread.
 
162
#if PY_MAJOR_VERSION >= 3
 
163
#define PyStringObject PyBytesObject
 
164
#define PyString_Check PyBytes_Check
 
165
#define PyString_Size PyBytes_Size
 
166
#define PyString_AsString PyBytes_AsString
 
167
#define PyString_FromString PyBytes_FromString
 
168
#define PyString_FromStringAndSize PyBytes_FromStringAndSize
 
169
#define PyString_AS_STRING PyBytes_AS_STRING
 
170
#define PyString_GET_SIZE PyBytes_GET_SIZE
 
171
#define _PyString_Resize _PyBytes_Resize
124
172
#endif
125
173
 
126
174
#ifndef WIN32
140
188
static PyTypeObject Auth_Type;
141
189
#if AP_SERVER_MAJORVERSION_NUMBER >= 2
142
190
#if AP_SERVER_MINORVERSION_NUMBER >= 2
143
 
#define MOD_WSGI_WITH_AUTH_PROVIDER 1
144
 
#endif
 
191
#define MOD_WSGI_WITH_AUTHN_PROVIDER 1
 
192
#endif
 
193
#endif
 
194
#if AP_MODULE_MAGIC_AT_LEAST(20060110,0)
 
195
#define MOD_WSGI_WITH_AUTHZ_PROVIDER 1
145
196
#endif
146
197
#endif
147
198
 
148
 
#if defined(MOD_WSGI_WITH_AUTH_PROVIDER)
 
199
#if defined(MOD_WSGI_WITH_AUTHN_PROVIDER)
149
200
#include "mod_auth.h"
150
201
#include "ap_provider.h"
 
202
#ifndef AUTHN_PROVIDER_VERSION
 
203
#define AUTHN_PROVIDER_VERSION "0"
 
204
#endif
151
205
#endif
152
206
 
153
207
#if defined(MOD_WSGI_WITH_DAEMONS)
223
277
 
224
278
#endif
225
279
 
 
280
#if defined(WIN32) && defined(APR_HAS_UNICODE_FS)
 
281
typedef apr_uint16_t apr_wchar_t;
 
282
 
 
283
APR_DECLARE(apr_status_t) apr_conv_utf8_to_ucs2(const char *in,
 
284
                                                apr_size_t *inbytes,
 
285
                                                apr_wchar_t *out,
 
286
                                                apr_size_t *outwords);
 
287
 
 
288
static apr_status_t wsgi_utf8_to_unicode_path(apr_wchar_t* retstr,
 
289
                                              apr_size_t retlen, 
 
290
                                              const char* srcstr)
 
291
{
 
292
    /* TODO: The computations could preconvert the string to determine
 
293
     * the true size of the retstr, but that's a memory over speed
 
294
     * tradeoff that isn't appropriate this early in development.
 
295
     *
 
296
     * Allocate the maximum string length based on leading 4 
 
297
     * characters of \\?\ (allowing nearly unlimited path lengths) 
 
298
     * plus the trailing null, then transform /'s into \\'s since
 
299
     * the \\?\ form doesn't allow '/' path seperators.
 
300
     *
 
301
     * Note that the \\?\ form only works for local drive paths, and
 
302
     * \\?\UNC\ is needed UNC paths.
 
303
     */
 
304
    apr_size_t srcremains = strlen(srcstr) + 1;
 
305
    apr_wchar_t *t = retstr;
 
306
    apr_status_t rv;
 
307
 
 
308
    /* This is correct, we don't twist the filename if it is will
 
309
     * definately be shorter than 248 characters.  It merits some 
 
310
     * performance testing to see if this has any effect, but there
 
311
     * seem to be applications that get confused by the resulting
 
312
     * Unicode \\?\ style file names, especially if they use argv[0]
 
313
     * or call the Win32 API functions such as GetModuleName, etc.
 
314
     * Not every application is prepared to handle such names.
 
315
     * 
 
316
     * Note also this is shorter than MAX_PATH, as directory paths 
 
317
     * are actually limited to 248 characters. 
 
318
     *
 
319
     * Note that a utf-8 name can never result in more wide chars
 
320
     * than the original number of utf-8 narrow chars.
 
321
     */
 
322
    if (srcremains > 248) {
 
323
        if (srcstr[1] == ':' && (srcstr[2] == '/' || srcstr[2] == '\\')) {
 
324
            wcscpy (retstr, L"\\\\?\\");
 
325
            retlen -= 4;
 
326
            t += 4;
 
327
        }
 
328
        else if ((srcstr[0] == '/' || srcstr[0] == '\\')
 
329
              && (srcstr[1] == '/' || srcstr[1] == '\\')
 
330
              && (srcstr[2] != '?')) {
 
331
            /* Skip the slashes */
 
332
            srcstr += 2;
 
333
            srcremains -= 2;
 
334
            wcscpy (retstr, L"\\\\?\\UNC\\");
 
335
            retlen -= 8;
 
336
            t += 8;
 
337
        }
 
338
    }
 
339
 
 
340
    if (rv = apr_conv_utf8_to_ucs2(srcstr, &srcremains, t, &retlen)) {
 
341
        return (rv == APR_INCOMPLETE) ? APR_EINVAL : rv;
 
342
    }
 
343
    if (srcremains) {
 
344
        return APR_ENAMETOOLONG;
 
345
    }
 
346
    for (; *t; ++t)
 
347
        if (*t == L'/')
 
348
            *t = L'\\';
 
349
    return APR_SUCCESS;
 
350
}
 
351
#endif
 
352
 
226
353
/* Compatibility macros for log level and status. */
227
354
 
228
355
#if AP_SERVER_MAJORVERSION_NUMBER < 2
244
371
 
245
372
/* Version and module information. */
246
373
 
247
 
#define MOD_WSGI_MAJORVERSION_NUMBER 2
248
 
#define MOD_WSGI_MINORVERSION_NUMBER 8
249
 
#define MOD_WSGI_VERSION_STRING "2.8"
 
374
#define MOD_WSGI_MAJORVERSION_NUMBER 3
 
375
#define MOD_WSGI_MINORVERSION_NUMBER 2
 
376
#define MOD_WSGI_VERSION_STRING "3.2"
250
377
 
251
378
#if AP_SERVER_MAJORVERSION_NUMBER < 2
252
379
module MODULE_VAR_EXPORT wsgi_module;
288
415
static apr_thread_mutex_t* wsgi_shutdown_lock = NULL;
289
416
#endif
290
417
 
 
418
/* Script information. */
 
419
 
 
420
static apr_array_header_t *wsgi_import_list = NULL;
 
421
 
291
422
/* Configuration objects. */
292
423
 
293
424
typedef struct {
294
425
    const char *location;
295
426
    const char *application;
296
427
    ap_regex_t *regexp;
 
428
    const char *process_group;
 
429
    const char *application_group;
 
430
    const char *callable_object;
 
431
    int pass_authorization;
297
432
} WSGIAliasEntry;
298
433
 
299
434
typedef struct {
300
435
    const char *handler_script;
301
436
    const char *process_group;
302
437
    const char *application_group;
 
438
    const char *callable_object;
 
439
    const char *pass_authorization;
303
440
} WSGIScriptFile;
304
441
 
305
442
typedef struct {
310
447
    const char *socket_prefix;
311
448
    apr_lockmech_e lock_mechanism;
312
449
 
 
450
    int verbose_debugging;
 
451
 
 
452
    apr_array_header_t *python_warnings;
 
453
 
313
454
    int python_optimize;
 
455
    int py3k_warning_flag;
 
456
 
314
457
    const char *python_home;
315
458
    const char *python_path;
316
459
    const char *python_eggs;
328
471
    const char *application_group;
329
472
    const char *callable_object;
330
473
 
331
 
    apr_array_header_t *import_list;
332
474
    WSGIScriptFile *dispatch_script;
333
475
 
334
 
    int apache_extensions;
 
476
    int pass_apache_request;
335
477
    int pass_authorization;
336
478
    int script_reloading;
337
 
    int reload_mechanism;
 
479
    int error_override;
 
480
    int chunked_request;
 
481
 
 
482
#if AP_SERVER_MAJORVERSION_NUMBER >= 2
 
483
    apr_hash_t *handler_scripts;
 
484
#endif
338
485
} WSGIServerConfig;
339
486
 
340
487
static WSGIServerConfig *wsgi_server_config = NULL;
369
516
    object->socket_prefix = ap_server_root_relative(p, object->socket_prefix);
370
517
#endif
371
518
 
 
519
    object->verbose_debugging = 0;
 
520
 
 
521
    object->python_warnings = NULL;
 
522
 
 
523
    object->py3k_warning_flag = -1;
372
524
    object->python_optimize = -1;
 
525
 
373
526
    object->python_home = NULL;
374
527
    object->python_path = NULL;
375
528
    object->python_eggs = NULL;
391
544
    object->application_group = NULL;
392
545
    object->callable_object = NULL;
393
546
 
394
 
    object->import_list = NULL;
395
547
    object->dispatch_script = NULL;
396
548
 
397
 
    object->apache_extensions = -1;
 
549
    object->pass_apache_request = -1;
398
550
    object->pass_authorization = -1;
399
551
    object->script_reloading = -1;
400
 
    object->reload_mechanism = -1;
 
552
    object->error_override = -1;
 
553
    object->chunked_request = -1;
401
554
 
402
555
    return object;
403
556
}
461
614
    else
462
615
        config->dispatch_script = parent->dispatch_script;
463
616
 
464
 
    if (child->apache_extensions != -1)
465
 
        config->apache_extensions = child->apache_extensions;
 
617
    if (child->pass_apache_request != -1)
 
618
        config->pass_apache_request = child->pass_apache_request;
466
619
    else
467
 
        config->apache_extensions = parent->apache_extensions;
 
620
        config->pass_apache_request = parent->pass_apache_request;
468
621
 
469
622
    if (child->pass_authorization != -1)
470
623
        config->pass_authorization = child->pass_authorization;
476
629
    else
477
630
        config->script_reloading = parent->script_reloading;
478
631
 
479
 
    if (child->reload_mechanism != -1)
480
 
        config->reload_mechanism = child->reload_mechanism;
481
 
    else
482
 
        config->reload_mechanism = parent->reload_mechanism;
 
632
    if (child->error_override != -1)
 
633
        config->error_override = child->error_override;
 
634
    else
 
635
        config->error_override = parent->error_override;
 
636
 
 
637
    if (child->chunked_request != -1)
 
638
        config->chunked_request = child->chunked_request;
 
639
    else
 
640
        config->chunked_request = parent->chunked_request;
 
641
 
 
642
#if AP_SERVER_MAJORVERSION_NUMBER >= 2
 
643
    if (!child->handler_scripts)
 
644
        config->handler_scripts = parent->handler_scripts;
 
645
    else if (!parent->handler_scripts)
 
646
        config->handler_scripts = child->handler_scripts;
 
647
    else {
 
648
        config->handler_scripts = apr_hash_overlay(p, child->handler_scripts,
 
649
                                                   parent->handler_scripts);
 
650
    }
 
651
#endif
483
652
 
484
653
    return config;
485
654
}
495
664
 
496
665
    WSGIScriptFile *dispatch_script;
497
666
 
498
 
    int apache_extensions;
 
667
    int pass_apache_request;
499
668
    int pass_authorization;
500
669
    int script_reloading;
501
 
    int reload_mechanism;
 
670
    int error_override;
 
671
    int chunked_request;
502
672
 
503
673
    WSGIScriptFile *access_script;
504
674
    WSGIScriptFile *auth_user_script;
505
675
    WSGIScriptFile *auth_group_script;
506
676
    int user_authoritative;
507
677
    int group_authoritative;
 
678
 
 
679
#if AP_SERVER_MAJORVERSION_NUMBER >= 2
 
680
    apr_hash_t *handler_scripts;
 
681
#endif
508
682
} WSGIDirectoryConfig;
509
683
 
510
684
static WSGIDirectoryConfig *newWSGIDirectoryConfig(apr_pool_t *p)
521
695
 
522
696
    object->dispatch_script = NULL;
523
697
 
524
 
    object->apache_extensions = -1;
 
698
    object->pass_apache_request = -1;
525
699
    object->pass_authorization = -1;
526
700
    object->script_reloading = -1;
527
 
    object->reload_mechanism = -1;
 
701
    object->error_override = -1;
 
702
    object->chunked_request = -1;
528
703
 
529
704
    object->access_script = NULL;
530
705
    object->auth_user_script = NULL;
581
756
    else
582
757
        config->dispatch_script = parent->dispatch_script;
583
758
 
584
 
    if (child->apache_extensions != -1)
585
 
        config->apache_extensions = child->apache_extensions;
 
759
    if (child->pass_apache_request != -1)
 
760
        config->pass_apache_request = child->pass_apache_request;
586
761
    else
587
 
        config->apache_extensions = parent->apache_extensions;
 
762
        config->pass_apache_request = parent->pass_apache_request;
588
763
 
589
764
    if (child->pass_authorization != -1)
590
765
        config->pass_authorization = child->pass_authorization;
596
771
    else
597
772
        config->script_reloading = parent->script_reloading;
598
773
 
599
 
    if (child->reload_mechanism != -1)
600
 
        config->reload_mechanism = child->reload_mechanism;
601
 
    else
602
 
        config->reload_mechanism = parent->reload_mechanism;
 
774
    if (child->error_override != -1)
 
775
        config->error_override = child->error_override;
 
776
    else
 
777
        config->error_override = parent->error_override;
 
778
 
 
779
    if (child->chunked_request != -1)
 
780
        config->chunked_request = child->chunked_request;
 
781
    else
 
782
        config->chunked_request = parent->chunked_request;
603
783
 
604
784
    if (child->access_script)
605
785
        config->access_script = child->access_script;
626
806
    else
627
807
        config->group_authoritative = parent->group_authoritative;
628
808
 
 
809
#if AP_SERVER_MAJORVERSION_NUMBER >= 2
 
810
    if (!child->handler_scripts)
 
811
        config->handler_scripts = parent->handler_scripts;
 
812
    else if (!parent->handler_scripts)
 
813
        config->handler_scripts = child->handler_scripts;
 
814
    else {
 
815
        config->handler_scripts = apr_hash_overlay(p, child->handler_scripts,
 
816
                                                   parent->handler_scripts);
 
817
    }
 
818
#endif
 
819
 
629
820
    return config;
630
821
}
631
822
 
640
831
 
641
832
    WSGIScriptFile *dispatch_script;
642
833
 
643
 
    int apache_extensions;
 
834
    int pass_apache_request;
644
835
    int pass_authorization;
645
836
    int script_reloading;
646
 
    int reload_mechanism;
 
837
    int error_override;
 
838
    int chunked_request;
647
839
 
648
840
    WSGIScriptFile *access_script;
649
841
    WSGIScriptFile *auth_user_script;
650
842
    WSGIScriptFile *auth_group_script;
651
843
    int user_authoritative;
652
844
    int group_authoritative;
 
845
 
 
846
#if AP_SERVER_MAJORVERSION_NUMBER >= 2
 
847
    apr_hash_t *handler_scripts;
 
848
#endif
 
849
    const char *handler_script;
653
850
} WSGIRequestConfig;
654
851
 
655
852
static int wsgi_find_path_info(const char *uri, const char *path_info)
946
1143
    if (!config->dispatch_script)
947
1144
        config->dispatch_script = sconfig->dispatch_script;
948
1145
 
949
 
    config->apache_extensions = dconfig->apache_extensions;
 
1146
    config->pass_apache_request = dconfig->pass_apache_request;
950
1147
 
951
 
    if (config->apache_extensions < 0) {
952
 
        config->apache_extensions = sconfig->apache_extensions;
953
 
        if (config->apache_extensions < 0)
954
 
            config->apache_extensions = 0;
 
1148
    if (config->pass_apache_request < 0) {
 
1149
        config->pass_apache_request = sconfig->pass_apache_request;
 
1150
        if (config->pass_apache_request < 0)
 
1151
            config->pass_apache_request = 0;
955
1152
    }
956
1153
 
957
1154
    config->pass_authorization = dconfig->pass_authorization;
970
1167
            config->script_reloading = 1;
971
1168
    }
972
1169
 
973
 
    config->reload_mechanism = dconfig->reload_mechanism;
974
 
 
975
 
    if (config->reload_mechanism == -1) {
976
 
        config->reload_mechanism = sconfig->reload_mechanism;
977
 
        if (config->reload_mechanism == -1) {
978
 
            if (*config->process_group)
979
 
                config->reload_mechanism = WSGI_RELOAD_PROCESS;
980
 
            else
981
 
                config->reload_mechanism = WSGI_RELOAD_MODULE;
982
 
        }
 
1170
    config->error_override = dconfig->error_override;
 
1171
 
 
1172
    if (config->error_override < 0) {
 
1173
        config->error_override = sconfig->error_override;
 
1174
        if (config->error_override < 0)
 
1175
            config->error_override = 0;
 
1176
    }
 
1177
 
 
1178
    config->chunked_request = dconfig->chunked_request;
 
1179
 
 
1180
    if (config->chunked_request < 0) {
 
1181
        config->chunked_request = sconfig->chunked_request;
 
1182
        if (config->chunked_request < 0)
 
1183
            config->chunked_request = 0;
983
1184
    }
984
1185
 
985
1186
    config->access_script = dconfig->access_script;
998
1199
    if (config->group_authoritative == -1)
999
1200
        config->group_authoritative = 1;
1000
1201
 
 
1202
#if AP_SERVER_MAJORVERSION_NUMBER >= 2
 
1203
    if (!dconfig->handler_scripts)
 
1204
        config->handler_scripts = sconfig->handler_scripts;
 
1205
    else if (!sconfig->handler_scripts)
 
1206
        config->handler_scripts = dconfig->handler_scripts;
 
1207
    else {
 
1208
        config->handler_scripts = apr_hash_overlay(p, dconfig->handler_scripts,
 
1209
                                                   sconfig->handler_scripts);
 
1210
    }
 
1211
#endif
 
1212
 
 
1213
    config->handler_script = "";
 
1214
 
1001
1215
    return config;
1002
1216
}
1003
1217
 
 
1218
/*
 
1219
 * Apache 2.X and UNIX specific definitions related to
 
1220
 * distinct daemon processes.
 
1221
 */
 
1222
 
 
1223
#if defined(MOD_WSGI_WITH_DAEMONS)
 
1224
 
 
1225
#include "unixd.h"
 
1226
#include "scoreboard.h"
 
1227
#include "mpm_common.h"
 
1228
#include "apr_proc_mutex.h"
 
1229
#include "apr_thread_cond.h"
 
1230
#include "apr_atomic.h"
 
1231
#include "http_connection.h"
 
1232
#include "apr_buckets.h"
 
1233
#include "apr_poll.h"
 
1234
#include "apr_signal.h"
 
1235
#include "http_vhost.h"
 
1236
 
 
1237
#if APR_MAJOR_VERSION < 1
 
1238
#define apr_atomic_cas32 apr_atomic_cas
 
1239
#endif
 
1240
 
 
1241
#if APR_HAVE_SYS_SOCKET_H
 
1242
#include <sys/socket.h>
 
1243
#endif
 
1244
#if APR_HAVE_UNISTD_H
 
1245
#include <unistd.h>
 
1246
#endif
 
1247
#if APR_HAVE_SYS_TYPES_H
 
1248
#include <sys/types.h>
 
1249
#endif
 
1250
#ifdef HAVE_SYS_SEM_H
 
1251
#include <sys/sem.h>
 
1252
#endif
 
1253
 
 
1254
#include <sys/un.h>
 
1255
 
 
1256
#ifndef WSGI_LISTEN_BACKLOG
 
1257
#define WSGI_LISTEN_BACKLOG 100
 
1258
#endif
 
1259
 
 
1260
#ifndef WSGI_CONNECT_ATTEMPTS
 
1261
#define WSGI_CONNECT_ATTEMPTS 15
 
1262
#endif
 
1263
 
 
1264
#define WSGI_STACK_HEAD  0xffff
 
1265
#define WSGI_STACK_LAST  0xffff
 
1266
#define WSGI_STACK_TERMINATED 0x10000
 
1267
#define WSGI_STACK_NO_LISTENER 0x20000
 
1268
 
 
1269
typedef struct {
 
1270
    server_rec *server;
 
1271
    long random;
 
1272
    int id;
 
1273
    const char *name;
 
1274
    const char *user;
 
1275
    uid_t uid;
 
1276
    const char *group;
 
1277
    gid_t gid;
 
1278
    int processes;
 
1279
    int multiprocess;
 
1280
    int threads;
 
1281
    int umask;
 
1282
    const char *root;
 
1283
    const char *home;
 
1284
    const char *python_path;
 
1285
    const char *python_eggs;
 
1286
    int stack_size;
 
1287
    int maximum_requests;
 
1288
    int shutdown_timeout;
 
1289
    apr_time_t deadlock_timeout;
 
1290
    apr_time_t inactivity_timeout;
 
1291
    const char *display_name;
 
1292
    int send_buffer_size;
 
1293
    int recv_buffer_size;
 
1294
    const char *script_user;
 
1295
    const char *script_group;
 
1296
    int cpu_time_limit;
 
1297
    int cpu_priority;
 
1298
    const char *socket;
 
1299
    int listener_fd;
 
1300
    const char* mutex_path;
 
1301
    apr_proc_mutex_t* mutex;
 
1302
} WSGIProcessGroup;
 
1303
 
 
1304
typedef struct {
 
1305
    WSGIProcessGroup *group;
 
1306
    int instance;
 
1307
    apr_proc_t process;
 
1308
    apr_socket_t *listener;
 
1309
} WSGIDaemonProcess;
 
1310
 
 
1311
typedef struct {
 
1312
    int id;
 
1313
    WSGIDaemonProcess *process;
 
1314
    apr_thread_t *thread;
 
1315
    int running;
 
1316
    int next;
 
1317
    int wakeup;
 
1318
    apr_thread_cond_t *condition;
 
1319
    apr_thread_mutex_t *mutex;
 
1320
} WSGIDaemonThread;
 
1321
 
 
1322
typedef struct {
 
1323
    apr_uint32_t state;
 
1324
} WSGIThreadStack;
 
1325
 
 
1326
typedef struct {
 
1327
    const char *name;
 
1328
    const char *socket;
 
1329
    int fd;
 
1330
} WSGIDaemonSocket;
 
1331
 
 
1332
static int wsgi_daemon_count = 0;
 
1333
static apr_hash_t *wsgi_daemon_index = NULL;
 
1334
static apr_hash_t *wsgi_daemon_listeners = NULL;
 
1335
 
 
1336
static WSGIDaemonProcess *wsgi_daemon_process = NULL;
 
1337
 
 
1338
static int volatile wsgi_request_count = 0;
 
1339
 
 
1340
static WSGIDaemonThread *wsgi_worker_threads = NULL;
 
1341
 
 
1342
static WSGIThreadStack *wsgi_worker_stack = NULL;
 
1343
 
 
1344
#endif
 
1345
 
1004
1346
/* Class objects used by response handler. */
1005
1347
 
1006
1348
static PyTypeObject Dispatch_Type;
1007
1349
 
1008
1350
typedef struct {
1009
1351
        PyObject_HEAD
 
1352
        const char *target;
1010
1353
        request_rec *r;
1011
1354
        int level;
1012
1355
        char *s;
 
1356
        int l;
1013
1357
        int expired;
1014
1358
#if PY_MAJOR_VERSION < 3
1015
1359
        int softspace;
1018
1362
 
1019
1363
static PyTypeObject Log_Type;
1020
1364
 
1021
 
static LogObject *newLogObject(request_rec *r, int level)
 
1365
static PyObject *newLogObject(request_rec *r, int level, const char *target)
1022
1366
{
1023
1367
    LogObject *self;
1024
1368
 
 
1369
#if PY_MAJOR_VERSION >= 3
 
1370
    PyObject *module = NULL;
 
1371
    PyObject *dict = NULL;
 
1372
    PyObject *object = NULL;
 
1373
    PyObject *args = NULL;
 
1374
    PyObject *result = NULL;
 
1375
 
 
1376
    module = PyImport_ImportModule("io");
 
1377
 
 
1378
    if (!module)
 
1379
        return NULL;
 
1380
 
 
1381
    dict = PyModule_GetDict(module);
 
1382
    object = PyDict_GetItemString(dict, "TextIOWrapper");
 
1383
 
 
1384
    if (!object) {
 
1385
        PyErr_SetString(PyExc_NameError,
 
1386
                        "name 'TextIOWrapper' is not defined");
 
1387
        return NULL;
 
1388
    }
 
1389
#endif
 
1390
 
1025
1391
    self = PyObject_New(LogObject, &Log_Type);
1026
1392
    if (self == NULL)
1027
1393
        return NULL;
1028
1394
 
 
1395
    self->target = target;
1029
1396
    self->r = r;
1030
1397
    self->level = APLOG_NOERRNO|level;
1031
1398
    self->s = NULL;
 
1399
    self->l = 0;
1032
1400
    self->expired = 0;
1033
1401
#if PY_MAJOR_VERSION < 3
1034
1402
    self->softspace = 0;
1035
1403
#endif
1036
1404
 
1037
 
    return self;
 
1405
#if PY_MAJOR_VERSION >= 3
 
1406
    Py_INCREF(object);
 
1407
    args = Py_BuildValue("(OssOO)", self, "utf-8", "replace",
 
1408
                         Py_None, Py_True);
 
1409
    Py_DECREF(self);
 
1410
    result = PyEval_CallObject(object, args);
 
1411
    Py_DECREF(args);
 
1412
    Py_DECREF(object);
 
1413
 
 
1414
    return result;
 
1415
#else
 
1416
    return (PyObject *)self;
 
1417
#endif
 
1418
}
 
1419
 
 
1420
#if 0
 
1421
static void Log_file(LogObject *self, const char *s, int l)
 
1422
{
 
1423
    /*
 
1424
     * XXX This function is not currently being used.
 
1425
     * The intention was that it be called instead of
 
1426
     * Log_call() when 'target' is non zero. This would
 
1427
     * be the case for 'stdout' and 'stderr'. Doing
 
1428
     * this bypasses normally Apache logging mechanisms
 
1429
     * though. May reawaken this code in mod_wsgi 4.0
 
1430
     * by way of a mechanism to divert logging from a
 
1431
     * daemon process to specfic log file or pipe using
 
1432
     * an option to WSGIDaemonProcess.
 
1433
     */
 
1434
 
 
1435
    char errstr[MAX_STRING_LEN];
 
1436
 
 
1437
    int plen = 0;
 
1438
    int slen = 0;
 
1439
 
 
1440
#if AP_SERVER_MAJORVERSION_NUMBER < 2
 
1441
    FILE *logf;
 
1442
#else
 
1443
    apr_file_t *logf = NULL;
 
1444
#endif
 
1445
 
 
1446
    if (self->r)
 
1447
        logf = self->r->server->error_log;
 
1448
    else
 
1449
        logf = wsgi_server->error_log;
 
1450
 
 
1451
#if AP_SERVER_MAJORVERSION_NUMBER < 2
 
1452
    plen = ap_snprintf(errstr, sizeof(errstr), "[%s] ", ap_get_time());
 
1453
#else
 
1454
    errstr[0] = '[';
 
1455
    ap_recent_ctime(errstr + 1, apr_time_now());
 
1456
    errstr[1 + APR_CTIME_LEN - 1] = ']';
 
1457
    errstr[1 + APR_CTIME_LEN    ] = ' ';
 
1458
    plen = 1 + APR_CTIME_LEN + 1;
 
1459
#endif
 
1460
 
 
1461
    if (self->target) {
 
1462
        int len;
 
1463
 
 
1464
        errstr[plen++] = '[';
 
1465
 
 
1466
        len = strlen(self->target);
 
1467
        memcpy(errstr+plen, self->target, len);
 
1468
 
 
1469
        plen += len;
 
1470
 
 
1471
        errstr[plen++] = ']';
 
1472
        errstr[plen++] = ' ';
 
1473
    }
 
1474
 
 
1475
    slen = MAX_STRING_LEN - plen - 1;
 
1476
 
 
1477
    Py_BEGIN_ALLOW_THREADS
 
1478
 
 
1479
    /*
 
1480
     * We actually break long lines up into segments
 
1481
     * of around 8192 characters, with the date/time
 
1482
     * and target information prefixing each line.
 
1483
     * This is just to avoid having to allocate more
 
1484
     * memory just to format the line with prefix.
 
1485
     * We want to avoid writing the prefix separately
 
1486
     * so at least try and write line in one atomic
 
1487
     * operation.
 
1488
     */
 
1489
 
 
1490
    while (1) {
 
1491
        if (l > slen) {
 
1492
            memcpy(errstr+plen, s, slen);
 
1493
            errstr[plen+slen] = '\n';
 
1494
#if AP_SERVER_MAJORVERSION_NUMBER < 2
 
1495
            fwrite(errstr, plen+slen+1, 1, logf);
 
1496
            fflush(logf);
 
1497
#else
 
1498
            apr_file_write_full(logf, errstr, plen+slen+1, NULL);
 
1499
            apr_file_flush(logf);
 
1500
#endif
 
1501
            s += slen;
 
1502
            l -= slen;
 
1503
        }
 
1504
        else {
 
1505
            memcpy(errstr+plen, s, l);
 
1506
            errstr[plen+l] = '\n';
 
1507
#if AP_SERVER_MAJORVERSION_NUMBER < 2
 
1508
            fwrite(errstr, plen+l+1, 1, logf);
 
1509
            fflush(logf);
 
1510
#else
 
1511
            apr_file_write_full(logf, errstr, plen+l+1, NULL);
 
1512
            apr_file_flush(logf);
 
1513
#endif
 
1514
            break;
 
1515
        }
 
1516
    }
 
1517
 
 
1518
    Py_END_ALLOW_THREADS
 
1519
}
 
1520
#endif
 
1521
 
 
1522
static void Log_call(LogObject *self, const char *s, int l)
 
1523
{
 
1524
    /*
 
1525
     * The length of the string to be logged is ignored
 
1526
     * for now. We just pass the whole string to the
 
1527
     * Apache error log functions. It will actually
 
1528
     * truncate it at some value less than 8192
 
1529
     * characters depending on the length of the prefix
 
1530
     * to go at the front. If there are embedded NULLs
 
1531
     * then truncation will occur at that point. That
 
1532
     * truncation occurs like this is also what happens
 
1533
     * if using FASTCGI solutions for Apache, so not
 
1534
     * doing anything different here.
 
1535
     */
 
1536
 
 
1537
    if (self->r) {
 
1538
        Py_BEGIN_ALLOW_THREADS
 
1539
        ap_log_rerror(APLOG_MARK, WSGI_LOG_LEVEL(self->level),
 
1540
                      self->r, "%s", s);
 
1541
        Py_END_ALLOW_THREADS
 
1542
    }
 
1543
    else {
 
1544
        Py_BEGIN_ALLOW_THREADS
 
1545
        ap_log_error(APLOG_MARK, WSGI_LOG_LEVEL(self->level),
 
1546
                     wsgi_server, "%s", s);
 
1547
        Py_END_ALLOW_THREADS
 
1548
    }
1038
1549
}
1039
1550
 
1040
1551
static void Log_dealloc(LogObject *self)
1041
1552
{
1042
1553
    if (self->s) {
1043
 
        if (!self->expired) {
1044
 
            if (self->r) {
1045
 
                Py_BEGIN_ALLOW_THREADS
1046
 
                ap_log_rerror(APLOG_MARK, WSGI_LOG_LEVEL(self->level),
1047
 
                              self->r, "%s", self->s);
1048
 
                Py_END_ALLOW_THREADS
1049
 
            }
1050
 
            else {
1051
 
                Py_BEGIN_ALLOW_THREADS
1052
 
                ap_log_error(APLOG_MARK, WSGI_LOG_LEVEL(self->level),
1053
 
                             wsgi_server, "%s", self->s);
1054
 
                Py_END_ALLOW_THREADS
1055
 
            }
1056
 
        }
 
1554
        if (!self->expired)
 
1555
            Log_call(self, self->s, self->l);
1057
1556
 
1058
1557
        free(self->s);
1059
1558
    }
1061
1560
    PyObject_Del(self);
1062
1561
}
1063
1562
 
1064
 
static PyObject *Log_close(LogObject *self, PyObject *args)
1065
 
{
1066
 
    if (self->expired) {
1067
 
        PyErr_SetString(PyExc_RuntimeError, "log object has expired");
1068
 
        return NULL;
1069
 
    }
1070
 
 
1071
 
    if (!PyArg_ParseTuple(args, ":close"))
1072
 
        return NULL;
1073
 
 
1074
 
    PyErr_SetString(PyExc_RuntimeError, "log object cannot be closed");
1075
 
    return NULL;
1076
 
}
1077
 
 
1078
1563
static PyObject *Log_flush(LogObject *self, PyObject *args)
1079
1564
{
1080
1565
    if (self->expired) {
1086
1571
        return NULL;
1087
1572
 
1088
1573
    if (self->s) {
1089
 
        if (self->r) {
1090
 
            Py_BEGIN_ALLOW_THREADS
1091
 
            ap_log_rerror(APLOG_MARK, WSGI_LOG_LEVEL(self->level),
1092
 
                          self->r, "%s", self->s);
1093
 
            Py_END_ALLOW_THREADS
1094
 
        }
1095
 
        else {
1096
 
            Py_BEGIN_ALLOW_THREADS
1097
 
            ap_log_error(APLOG_MARK, WSGI_LOG_LEVEL(self->level),
1098
 
                         wsgi_server, "%s", self->s);
1099
 
            Py_END_ALLOW_THREADS
1100
 
        }
 
1574
        Log_call(self, self->s, self->l);
1101
1575
 
1102
1576
        free(self->s);
1103
1577
        self->s = NULL;
 
1578
        self->l = 0;
1104
1579
    }
1105
1580
 
1106
1581
    Py_INCREF(Py_None);
1107
1582
    return Py_None;
1108
1583
}
1109
1584
 
1110
 
static void Log_output(LogObject *self, const char *msg)
 
1585
static PyObject *Log_close(LogObject *self, PyObject *args)
 
1586
{
 
1587
    PyObject *result = NULL;
 
1588
 
 
1589
    if (!PyArg_ParseTuple(args, ":close"))
 
1590
        return NULL;
 
1591
 
 
1592
    if (!self->expired)
 
1593
        result = Log_flush(self, args);
 
1594
 
 
1595
    Py_XDECREF(result);
 
1596
 
 
1597
    self->r = NULL;
 
1598
    self->expired = 1;
 
1599
 
 
1600
    Py_INCREF(Py_None);
 
1601
    return Py_None;
 
1602
}
 
1603
 
 
1604
static void Log_queue(LogObject *self, const char *msg, int len)
1111
1605
{
1112
1606
    const char *p = NULL;
1113
1607
    const char *q = NULL;
 
1608
    const char *e = NULL;
1114
1609
 
1115
1610
    p = msg;
1116
 
 
1117
 
    q = strchr(p, '\n');
1118
 
 
1119
 
    while (q) {
 
1611
    e = p + len;
 
1612
 
 
1613
    /*
 
1614
     * Break string on newline. This is on assumption
 
1615
     * that primarily textual information being logged.
 
1616
     */
 
1617
 
 
1618
    q = p;
 
1619
    while (q != e) {
 
1620
        if (*q == '\n')
 
1621
            break;
 
1622
        q++;
 
1623
    }
 
1624
 
 
1625
    while (q != e) {
1120
1626
        /* Output each complete line. */
1121
1627
 
1122
1628
        if (self->s) {
1126
1632
            int n = 0;
1127
1633
            char *s = NULL;
1128
1634
 
1129
 
            m = strlen(self->s);
 
1635
            m = self->l;
1130
1636
            n = m+q-p+1;
1131
1637
 
1132
1638
            s = (char *)malloc(n);
1133
 
            strncpy(s, self->s, m);
1134
 
            strncpy(s+m, p, q-p);
 
1639
            memcpy(s, self->s, m);
 
1640
            memcpy(s+m, p, q-p);
1135
1641
            s[n-1] = '\0';
1136
1642
 
1137
1643
            free(self->s);
1138
1644
            self->s = NULL;
 
1645
            self->l = 0;
1139
1646
 
1140
 
            if (self->r) {
1141
 
                Py_BEGIN_ALLOW_THREADS
1142
 
                ap_log_rerror(APLOG_MARK, WSGI_LOG_LEVEL(self->level),
1143
 
                              self->r, "%s", s);
1144
 
                Py_END_ALLOW_THREADS
1145
 
            }
1146
 
            else {
1147
 
                Py_BEGIN_ALLOW_THREADS
1148
 
                ap_log_error(APLOG_MARK, WSGI_LOG_LEVEL(self->level),
1149
 
                             wsgi_server, "%s", s);
1150
 
                Py_END_ALLOW_THREADS
1151
 
            }
 
1647
            Log_call(self, s, n-1);
1152
1648
 
1153
1649
            free(s);
1154
1650
        }
1159
1655
            n = q-p+1;
1160
1656
 
1161
1657
            s = (char *)malloc(n);
1162
 
            strncpy(s, p, q-p);
 
1658
            memcpy(s, p, q-p);
1163
1659
            s[n-1] = '\0';
1164
1660
 
1165
 
            if (self->r) {
1166
 
                Py_BEGIN_ALLOW_THREADS
1167
 
                ap_log_rerror(APLOG_MARK, WSGI_LOG_LEVEL(self->level),
1168
 
                              self->r, "%s", s);
1169
 
                Py_END_ALLOW_THREADS
1170
 
            }
1171
 
            else {
1172
 
                Py_BEGIN_ALLOW_THREADS
1173
 
                ap_log_error(APLOG_MARK, WSGI_LOG_LEVEL(self->level),
1174
 
                             wsgi_server, "%s", s);
1175
 
                Py_END_ALLOW_THREADS
1176
 
            }
 
1661
            Log_call(self, s, n-1);
1177
1662
 
1178
1663
            free(s);
1179
1664
        }
1180
1665
 
1181
1666
        p = q+1;
1182
 
        q = strchr(p, '\n');
 
1667
 
 
1668
        /* Break string on newline. */
 
1669
 
 
1670
        q = p;
 
1671
        while (q != e) {
 
1672
            if (*q == '\n')
 
1673
                break;
 
1674
            q++;
 
1675
        }
1183
1676
    }
1184
1677
 
1185
 
    if (*p) {
 
1678
    if (p != e) {
1186
1679
        /* Save away incomplete line. */
1187
1680
 
1188
1681
        if (self->s) {
1191
1684
            int m = 0;
1192
1685
            int n = 0;
1193
1686
 
1194
 
            m = strlen(self->s);
1195
 
            n = strlen(p);
 
1687
            m = self->l;
 
1688
            n = m+e-p+1;
1196
1689
 
1197
 
            self->s = (char *)realloc(self->s, m+n+1);
1198
 
            strncpy(self->s+m, p, n);
1199
 
            self->s[m+n] = '\0';
 
1690
            self->s = (char *)realloc(self->s, n);
 
1691
            memcpy(self->s+m, p, e-p);
 
1692
            self->s[n-1] = '\0';
 
1693
            self->l = n-1;
1200
1694
        }
1201
1695
        else {
1202
 
            self->s = (char *)malloc(strlen(p)+1);
1203
 
            strcpy(self->s, p);
 
1696
            int n = 0;
 
1697
 
 
1698
            n = e-p+1;
 
1699
 
 
1700
            self->s = (char *)malloc(n);
 
1701
            memcpy(self->s, p, n-1);
 
1702
            self->s[n-1] = '\0';
 
1703
            self->l = n-1;
1204
1704
        }
1205
1705
    }
1206
1706
}
1208
1708
static PyObject *Log_write(LogObject *self, PyObject *args)
1209
1709
{
1210
1710
    const char *msg = NULL;
 
1711
    int len = -1;
1211
1712
 
1212
1713
    if (self->expired) {
1213
1714
        PyErr_SetString(PyExc_RuntimeError, "log object has expired");
1214
1715
        return NULL;
1215
1716
    }
1216
1717
 
1217
 
    if (!PyArg_ParseTuple(args, "s:write", &msg))
 
1718
    if (!PyArg_ParseTuple(args, "s#:write", &msg, &len))
1218
1719
        return NULL;
1219
1720
 
1220
 
    Log_output(self, msg);
 
1721
    Log_queue(self, msg, len);
1221
1722
 
1222
1723
    Py_INCREF(Py_None);
1223
1724
    return Py_None;
1240
1741
 
1241
1742
    iterator = PyObject_GetIter(sequence);
1242
1743
 
1243
 
    if (iterator == NULL)
 
1744
    if (iterator == NULL) {
 
1745
        PyErr_SetString(PyExc_TypeError,
 
1746
                        "argument must be sequence of strings");
 
1747
 
1244
1748
        return NULL;
 
1749
    }
1245
1750
 
1246
1751
    while ((item = PyIter_Next(iterator))) {
1247
 
        msg = PyString_AsString(item);
1248
 
 
1249
 
        if (msg) {
1250
 
            Log_output(self, msg);
1251
 
 
1252
 
            Py_DECREF(item);
1253
 
        }
1254
 
        else {
1255
 
            Py_DECREF(item);
1256
 
 
1257
 
            break;
 
1752
        PyObject *result = NULL;
 
1753
 
 
1754
        result = Log_write(self, item);
 
1755
 
 
1756
        if (!result) {
 
1757
            Py_DECREF(iterator);
 
1758
 
 
1759
            PyErr_SetString(PyExc_TypeError,
 
1760
                            "argument must be sequence of strings");
 
1761
 
 
1762
            return NULL;
1258
1763
        }
1259
1764
    }
1260
1765
 
1261
1766
    Py_DECREF(iterator);
1262
1767
 
1263
 
    if (item && !msg)
1264
 
        return NULL;
1265
 
 
1266
1768
    Py_INCREF(Py_None);
1267
1769
    return Py_None;
1268
1770
}
1269
1771
 
 
1772
#if PY_MAJOR_VERSION >= 3
 
1773
static PyObject *Log_readable(LogObject *self, PyObject *args)
 
1774
{
 
1775
    if (!PyArg_ParseTuple(args, ":readable"))
 
1776
        return NULL;
 
1777
 
 
1778
    Py_INCREF(Py_False);
 
1779
    return Py_False;
 
1780
}
 
1781
 
 
1782
static PyObject *Log_seekable(LogObject *self, PyObject *args)
 
1783
{
 
1784
    if (!PyArg_ParseTuple(args, ":seekable"))
 
1785
        return NULL;
 
1786
 
 
1787
    Py_INCREF(Py_False);
 
1788
    return Py_False;
 
1789
}
 
1790
 
 
1791
static PyObject *Log_writable(LogObject *self, PyObject *args)
 
1792
{
 
1793
    if (!PyArg_ParseTuple(args, ":writable"))
 
1794
        return NULL;
 
1795
 
 
1796
    Py_INCREF(Py_True);
 
1797
    return Py_True;
 
1798
}
 
1799
#endif
 
1800
 
1270
1801
static PyObject *Log_closed(LogObject *self, void *closure)
1271
1802
{
1272
1803
    Py_INCREF(Py_False);
1284
1815
    int new;
1285
1816
 
1286
1817
    if (value == NULL) {
1287
 
        PyErr_SetString(PyExc_TypeError,
1288
 
                        "can't delete softspace attribute");
 
1818
        PyErr_SetString(PyExc_TypeError, "can't delete softspace attribute");
1289
1819
        return -1;
1290
1820
    }
1291
1821
 
1297
1827
 
1298
1828
    return 0;
1299
1829
}
 
1830
 
 
1831
#else
 
1832
 
 
1833
static PyObject *Log_get_encoding(LogObject *self, void *closure)
 
1834
{
 
1835
    return PyUnicode_FromString("utf-8");
 
1836
}
 
1837
 
 
1838
static PyObject *Log_get_errors(LogObject *self, void *closure)
 
1839
{
 
1840
    return PyUnicode_FromString("replace");
 
1841
}
1300
1842
#endif
1301
1843
 
1302
1844
static PyMethodDef Log_methods[] = {
 
1845
    { "flush",      (PyCFunction)Log_flush,      METH_VARARGS, 0 },
1303
1846
    { "close",      (PyCFunction)Log_close,      METH_VARARGS, 0 },
1304
 
    { "flush",      (PyCFunction)Log_flush,      METH_VARARGS, 0 },
1305
1847
    { "write",      (PyCFunction)Log_write,      METH_VARARGS, 0 },
1306
1848
    { "writelines", (PyCFunction)Log_writelines, METH_VARARGS, 0 },
 
1849
#if PY_MAJOR_VERSION >= 3
 
1850
    { "readable",   (PyCFunction)Log_readable,   METH_VARARGS, 0 },
 
1851
    { "seekable",   (PyCFunction)Log_seekable,   METH_VARARGS, 0 },
 
1852
    { "writable",   (PyCFunction)Log_writable,   METH_VARARGS, 0 },
 
1853
#endif
1307
1854
    { NULL, NULL}
1308
1855
};
1309
1856
 
1311
1858
    { "closed", (getter)Log_closed, NULL, 0 },
1312
1859
#if PY_MAJOR_VERSION < 3
1313
1860
    { "softspace", (getter)Log_get_softspace, (setter)Log_set_softspace, 0 },
 
1861
#else
 
1862
    { "encoding", (getter)Log_get_encoding, NULL, 0 },
 
1863
    { "errors", (getter)Log_get_errors, NULL, 0 },
1314
1864
#endif
1315
1865
    { NULL },
1316
1866
};
1317
1867
 
1318
1868
static PyTypeObject Log_Type = {
1319
 
    /* The ob_type field must be initialized in the module init function
1320
 
     * to be portable to Windows without using C++. */
1321
 
    PyObject_HEAD_INIT(NULL)
1322
 
    0,                      /*ob_size*/
 
1869
    PyVarObject_HEAD_INIT(NULL, 0)
1323
1870
    "mod_wsgi.Log",         /*tp_name*/
1324
1871
    sizeof(LogObject),      /*tp_basicsize*/
1325
1872
    0,                      /*tp_itemsize*/
1362
1909
    0,                      /*tp_is_gc*/
1363
1910
};
1364
1911
 
1365
 
static void wsgi_log_python_error(request_rec *r, LogObject *log,
 
1912
static void wsgi_log_python_error(request_rec *r, PyObject *log,
1366
1913
                                  const char *filename)
1367
1914
{
1368
1915
    PyObject *m = NULL;
1372
1919
    PyObject *value = NULL;
1373
1920
    PyObject *traceback = NULL;
1374
1921
 
 
1922
    PyObject *xlog = NULL;
 
1923
 
1375
1924
    if (!PyErr_Occurred())
1376
1925
        return;
1377
1926
 
 
1927
    if (!log) {
 
1928
        PyErr_Fetch(&type, &value, &traceback);
 
1929
 
 
1930
        xlog = newLogObject(r, APLOG_ERR, NULL);
 
1931
 
 
1932
        log = xlog;
 
1933
 
 
1934
        PyErr_Restore(type, value, traceback);
 
1935
 
 
1936
        type = NULL;
 
1937
        value = NULL;
 
1938
        traceback = NULL;
 
1939
    }
 
1940
 
1378
1941
    if (PyErr_ExceptionMatches(PyExc_SystemExit)) {
1379
1942
        Py_BEGIN_ALLOW_THREADS
1380
1943
        if (r) {
1464
2027
    Py_XDECREF(result);
1465
2028
 
1466
2029
    Py_XDECREF(m);
 
2030
 
 
2031
    Py_XDECREF(xlog);
1467
2032
}
1468
2033
 
1469
2034
typedef struct {
1528
2093
    PyObject *result = NULL;
1529
2094
    char *buffer = NULL;
1530
2095
    apr_size_t length = 0;
 
2096
    int init = 0;
1531
2097
 
1532
2098
    apr_size_t n;
1533
2099
 
1548
2114
    }
1549
2115
#endif
1550
2116
 
 
2117
    init = self->init;
 
2118
 
1551
2119
    if (!self->init) {
1552
2120
        if (!ap_should_client_block(self->r))
1553
2121
            self->done = 1;
1561
2129
        return PyString_FromString("");
1562
2130
 
1563
2131
    /*
1564
 
     * If requested size if zero bytes, then still need to pass
 
2132
     * If requested size is zero bytes, then still need to pass
1565
2133
     * this through to Apache input filters so that any
1566
 
     * 100-continue response is triggered.
 
2134
     * 100-continue response is triggered. Only do this if very
 
2135
     * first attempt to read data. Note that this will cause an
 
2136
     * assertion failure in HTTP_IN input filter when Apache
 
2137
     * maintainer mode is enabled. It is arguable that the
 
2138
     * assertion check, which prohibits a zero length read,
 
2139
     * shouldn't exist, as why should a zero length read be not
 
2140
     * allowed if input filter processing still works when it
 
2141
     * does occur.
1567
2142
     */
1568
2143
 
1569
2144
    if (size == 0) {
1570
 
        char dummy[1];
1571
 
 
1572
 
        Py_BEGIN_ALLOW_THREADS
1573
 
        n = ap_get_client_block(self->r, dummy, 0);
1574
 
        Py_END_ALLOW_THREADS
1575
 
 
1576
 
        if (n == -1) {
1577
 
            PyErr_SetString(PyExc_IOError, "request data read error");
1578
 
            return NULL;
 
2145
        if (!init) {
 
2146
            char dummy[1];
 
2147
 
 
2148
            Py_BEGIN_ALLOW_THREADS
 
2149
            n = ap_get_client_block(self->r, dummy, 0);
 
2150
            Py_END_ALLOW_THREADS
 
2151
 
 
2152
            if (n == -1) {
 
2153
                PyErr_SetString(PyExc_IOError, "request data read error");
 
2154
                return NULL;
 
2155
            }
1579
2156
        }
1580
2157
 
1581
2158
        return PyString_FromString("");
1684
2261
 
1685
2262
        size = self->length;
1686
2263
 
1687
 
        if (self->r->remaining > 0)
 
2264
        if (!self->r->read_chunked && self->r->remaining > 0)
1688
2265
            size += self->r->remaining;
1689
2266
 
1690
2267
        size = size + (size >> 2);
1691
2268
 
1692
2269
        if (size < 256)
1693
 
            size = 256;
 
2270
            size = self->r->read_chunked ? 8192 : 256;
1694
2271
 
1695
2272
        /* Allocate string of the estimated size. */
1696
2273
 
2194
2771
}
2195
2772
 
2196
2773
static PyTypeObject Input_Type = {
2197
 
    /* The ob_type field must be initialized in the module init function
2198
 
     * to be portable to Windows without using C++. */
2199
 
    PyObject_HEAD_INIT(NULL)
2200
 
    0,                      /*ob_size*/
 
2774
    PyVarObject_HEAD_INIT(NULL, 0)
2201
2775
    "mod_wsgi.Input",       /*tp_name*/
2202
2776
    sizeof(InputObject),    /*tp_basicsize*/
2203
2777
    0,                      /*tp_itemsize*/
2217
2791
    0,                      /*tp_getattro*/
2218
2792
    0,                      /*tp_setattro*/
2219
2793
    0,                      /*tp_as_buffer*/
 
2794
#if defined(Py_TPFLAGS_HAVE_ITER)
2220
2795
    Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_ITER, /*tp_flags*/
 
2796
#else
 
2797
    Py_TPFLAGS_DEFAULT,     /*tp_flags*/
 
2798
#endif
2221
2799
    0,                      /*tp_doc*/
2222
2800
    0,                      /*tp_traverse*/
2223
2801
    0,                      /*tp_clear*/
2249
2827
#endif
2250
2828
        WSGIRequestConfig *config;
2251
2829
        InputObject *input;
2252
 
        LogObject *log;
 
2830
        PyObject *log;
2253
2831
        int status;
2254
2832
        const char *status_line;
2255
2833
        PyObject *headers;
2299
2877
    self->output_length = 0;
2300
2878
 
2301
2879
    self->input = newInputObject(r);
2302
 
    self->log = newLogObject(r, APLOG_ERR);
 
2880
    self->log = newLogObject(r, APLOG_ERR, NULL);
2303
2881
 
2304
2882
    return self;
2305
2883
}
2321
2899
    PyObject *headers = NULL;
2322
2900
    PyObject *exc_info = NULL;
2323
2901
 
 
2902
    PyObject *item = NULL;
 
2903
    PyObject *latin_item = NULL;
 
2904
 
2324
2905
    char* value = NULL;
2325
2906
 
2326
2907
    if (!self->r) {
2328
2909
        return NULL;
2329
2910
    }
2330
2911
 
2331
 
    if (!PyArg_ParseTuple(args, "sO|O:start_response",
2332
 
        &status, &headers, &exc_info)) {
2333
 
        return NULL;
2334
 
    }
 
2912
    if (!PyArg_ParseTuple(args, "OO|O:start_response",
 
2913
        &item, &headers, &exc_info)) {
 
2914
        return NULL;
 
2915
    }
 
2916
 
 
2917
#if PY_MAJOR_VERSION >= 3
 
2918
    if (PyUnicode_Check(item)) {
 
2919
        latin_item = PyUnicode_AsLatin1String(item);
 
2920
        if (!latin_item) {
 
2921
            PyErr_Format(PyExc_TypeError, "expected byte string object for "
 
2922
                         "status, value containing non 'latin-1' characters "
 
2923
                         "found");
 
2924
            return NULL;
 
2925
        }
 
2926
 
 
2927
        item = latin_item;
 
2928
    }
 
2929
#endif
 
2930
 
 
2931
    if (!PyString_Check(item)) {
 
2932
        PyErr_Format(PyExc_TypeError, "expected byte string object for "
 
2933
                     "status, value of type %.200s found",
 
2934
                     item->ob_type->tp_name);
 
2935
        Py_XDECREF(latin_item);
 
2936
        return NULL;
 
2937
    }
 
2938
 
 
2939
    status = PyString_AsString(item);
2335
2940
 
2336
2941
    if (!PyList_Check(headers)) {
2337
2942
        PyErr_SetString(PyExc_TypeError, "response headers must be a list");
 
2943
        Py_XDECREF(latin_item);
2338
2944
        return NULL;
2339
2945
    }
2340
2946
 
2344
2950
            PyObject *value = NULL;
2345
2951
            PyObject *traceback = NULL;
2346
2952
 
2347
 
            if (!PyArg_ParseTuple(exc_info, "OOO", &type, &value, &traceback))
 
2953
            if (!PyArg_ParseTuple(exc_info, "OOO", &type,
 
2954
                                  &value, &traceback)) {
 
2955
                Py_XDECREF(latin_item);
2348
2956
                return NULL;
 
2957
            }
2349
2958
 
2350
2959
            Py_INCREF(type);
2351
2960
            Py_INCREF(value);
2353
2962
 
2354
2963
            PyErr_Restore(type, value, traceback);
2355
2964
 
 
2965
            Py_XDECREF(latin_item);
 
2966
 
2356
2967
            return NULL;
2357
2968
        }
2358
2969
    }
2359
2970
    else if (self->status_line && !self->headers) {
2360
2971
        PyErr_SetString(PyExc_RuntimeError, "headers have already been sent");
 
2972
        Py_XDECREF(latin_item);
2361
2973
        return NULL;
2362
2974
    }
2363
2975
 
2370
2982
 
2371
2983
    if (*value || errno == ERANGE) {
2372
2984
        PyErr_SetString(PyExc_TypeError, "status value is not an integer");
 
2985
        Py_XDECREF(latin_item);
2373
2986
        return NULL;
2374
2987
    }
2375
2988
 
2376
2989
    if (!*status) {
2377
2990
        PyErr_SetString(PyExc_ValueError, "status message was not supplied");
 
2991
        Py_XDECREF(latin_item);
2378
2992
        return NULL;
2379
2993
    }
2380
2994
 
2384
2998
 
2385
2999
    Py_INCREF(self->headers);
2386
3000
 
 
3001
    Py_XDECREF(latin_item);
 
3002
 
2387
3003
    return PyObject_GetAttrString((PyObject *)self, "write");
2388
3004
}
2389
3005
 
2390
 
static int Adapter_output(AdapterObject *self, const char *data, int length)
 
3006
static int Adapter_output(AdapterObject *self, const char *data, int length,
 
3007
                          int exception_when_aborted)
2391
3008
{
2392
3009
    int i = 0;
2393
3010
    int n = 0;
2414
3031
 
2415
3032
    if (self->headers) {
2416
3033
        /*
2417
 
         * Force a zero length read before sending the
2418
 
         * headers. This will ensure that if no request
2419
 
         * content has been read that any '100 Continue'
2420
 
         * response will be flushed and sent back to the
2421
 
         * client if client was expecting one. Only
2422
 
         * want to do this for 2xx and 3xx status values.
 
3034
         * Apache prior to Apache 2.2.8 has a bug in it
 
3035
         * whereby it doesn't force '100 Continue'
 
3036
         * response before responding with headers if no
 
3037
         * read. So, force a zero length read before
 
3038
         * sending the headers if haven't yet attempted
 
3039
         * to read anything. This will ensure that if no
 
3040
         * request content has been read that any '100
 
3041
         * Continue' response will be flushed and sent
 
3042
         * back to the client if client was expecting
 
3043
         * one. Only want to do this for 2xx and 3xx
 
3044
         * status values. Note that even though Apple
 
3045
         * supplied version of Apache on MacOS X Leopard
 
3046
         * is newer than version 2.2.8, the header file
 
3047
         * has never been patched when they make updates
 
3048
         * and so anything compiled against it thinks it
 
3049
         * is older.
2423
3050
         */
2424
3051
 
2425
 
        if (self->status >= 200 && self->status < 400) {
2426
 
            PyObject *args = NULL;
2427
 
            PyObject *result = NULL;
2428
 
            args = Py_BuildValue("(i)", 0);
2429
 
            result = Input_read(self->input, args);
2430
 
            if (PyErr_Occurred())
2431
 
                PyErr_Clear();
2432
 
            Py_DECREF(args);
2433
 
            Py_XDECREF(result);
 
3052
#if (AP_SERVER_MAJORVERSION_NUMBER == 1) || \
 
3053
    (AP_SERVER_MAJORVERSION_NUMBER == 2 && \
 
3054
     AP_SERVER_MINORVERSION_NUMBER < 2) || \
 
3055
    (AP_SERVER_MAJORVERSION_NUMBER == 2 && \
 
3056
     AP_SERVER_MINORVERSION_NUMBER == 2 && \
 
3057
     AP_SERVER_PATCHLEVEL_NUMBER < 8)
 
3058
 
 
3059
        if (!self->input->init) {
 
3060
            if (self->status >= 200 && self->status < 400) {
 
3061
                PyObject *args = NULL;
 
3062
                PyObject *result = NULL;
 
3063
                args = Py_BuildValue("(i)", 0);
 
3064
                result = Input_read(self->input, args);
 
3065
                if (PyErr_Occurred())
 
3066
                    PyErr_Clear();
 
3067
                Py_DECREF(args);
 
3068
                Py_XDECREF(result);
 
3069
            }
2434
3070
        }
2435
3071
 
 
3072
#endif
 
3073
 
2436
3074
        /* Now setup response headers in request object. */
2437
3075
 
2438
3076
        r->status = self->status;
2466
3104
            object1 = PyTuple_GetItem(tuple, 0);
2467
3105
            object2 = PyTuple_GetItem(tuple, 1);
2468
3106
 
2469
 
            if (!PyString_Check(object1)) {
2470
 
                PyErr_SetString(PyExc_TypeError, "expected string object "
2471
 
                                "for header name");
2472
 
                return 0;
2473
 
            }
2474
 
 
2475
 
            if (!PyString_Check(object2)) {
2476
 
                PyErr_SetString(PyExc_TypeError, "expected string object "
2477
 
                                "for header value");
2478
 
                return 0;
2479
 
            }
2480
 
 
2481
 
            if (!PyArg_ParseTuple(tuple, "ss", &name, &value)) {
2482
 
                PyErr_SetString(PyExc_TypeError, "header name and value "
2483
 
                                "must be string objects without null bytes");
 
3107
            if (PyString_Check(object1)) {
 
3108
                name = PyString_AsString(object1);
 
3109
            }
 
3110
#if PY_MAJOR_VERSION >= 3
 
3111
            else if (PyUnicode_Check(object1)) {
 
3112
                PyObject *latin_object;
 
3113
                latin_object = PyUnicode_AsLatin1String(object1);
 
3114
                if (!latin_object) {
 
3115
                    PyErr_Format(PyExc_TypeError, "header name "
 
3116
                                 "contained non 'latin-1' characters ");
 
3117
                    return 0;
 
3118
                }
 
3119
 
 
3120
                name = apr_pstrdup(r->pool, PyString_AsString(latin_object));
 
3121
                Py_DECREF(latin_object);
 
3122
            }
 
3123
#endif
 
3124
            else {
 
3125
                PyErr_Format(PyExc_TypeError, "expected byte string object "
 
3126
                             "for header name, value of type %.200s "
 
3127
                             "found", object1->ob_type->tp_name);
 
3128
                return 0;
 
3129
            }
 
3130
 
 
3131
            if (PyString_Check(object2)) {
 
3132
                value = PyString_AsString(object2);
 
3133
            }
 
3134
#if PY_MAJOR_VERSION >= 3
 
3135
            else if (PyUnicode_Check(object2)) {
 
3136
                PyObject *latin_object;
 
3137
                latin_object = PyUnicode_AsLatin1String(object2);
 
3138
                if (!latin_object) {
 
3139
                    PyErr_Format(PyExc_TypeError, "header value "
 
3140
                                 "contained non 'latin-1' characters ");
 
3141
                    return 0;
 
3142
                }
 
3143
 
 
3144
                value = apr_pstrdup(r->pool, PyString_AsString(latin_object));
 
3145
                Py_DECREF(latin_object);
 
3146
            }
 
3147
#endif
 
3148
            else {
 
3149
                PyErr_Format(PyExc_TypeError, "expected byte string object "
 
3150
                             "for header value, value of type %.200s "
 
3151
                             "found", object2->ob_type->tp_name);
2484
3152
                return 0;
2485
3153
            }
2486
3154
 
2535
3203
            }
2536
3204
        }
2537
3205
 
2538
 
        /*
2539
 
         * If content length not set and dealing with iterable
2540
 
         * response from application, see if response is a
2541
 
         * sequence consisting of only one item and if so use
2542
 
         * the current length of data being output as the
2543
 
         * content length to use, given that there cannot be
2544
 
         * any further data.
2545
 
         */
2546
 
 
2547
 
        if (self->sequence && PySequence_Check(self->sequence)) {
2548
 
            if (PySequence_Size(self->sequence) == 1) {
2549
 
                if (!self->content_length_set) {
2550
 
                    ap_set_content_length(r, length);
2551
 
 
2552
 
                    self->content_length_set = 1;
2553
 
                    self->content_length = length;
2554
 
                }
2555
 
            }
2556
 
 
2557
 
            if (PyErr_Occurred())
2558
 
                PyErr_Clear();
2559
 
        }
2560
 
 
2561
3206
        /* Need to force output of headers when using Apache 1.3. */
2562
3207
 
2563
3208
        Py_BEGIN_ALLOW_THREADS
2626
3271
         */
2627
3272
 
2628
3273
        if (r->connection->aborted) {
2629
 
            PyErr_SetString(PyExc_IOError, "client connection closed");
 
3274
            if (!exception_when_aborted) {
 
3275
                ap_log_rerror(APLOG_MARK, WSGI_LOG_DEBUG(0), self->r,
 
3276
                              "mod_wsgi (pid=%d): Client closed connection.",
 
3277
                              getpid());
 
3278
            }
 
3279
            else
 
3280
                PyErr_SetString(PyExc_IOError, "client connection closed");
 
3281
 
2630
3282
            return 0;
2631
3283
        }
2632
3284
 
2694
3346
     */
2695
3347
 
2696
3348
    if (r->connection->aborted) {
2697
 
        PyErr_SetString(PyExc_IOError, "client connection closed");
 
3349
        if (!exception_when_aborted) {
 
3350
            ap_log_rerror(APLOG_MARK, WSGI_LOG_DEBUG(0), self->r,
 
3351
                          "mod_wsgi (pid=%d): Client closed connection.",
 
3352
                          getpid());
 
3353
        }
 
3354
        else
 
3355
            PyErr_SetString(PyExc_IOError, "client connection closed");
 
3356
 
2698
3357
        return 0;
2699
3358
    }
2700
3359
 
2816
3475
    for (i = 0; i < head->nelts; ++i) {
2817
3476
        if (elts[i].key) {
2818
3477
            if (elts[i].val) {
 
3478
#if PY_MAJOR_VERSION >= 3
 
3479
                if (!strcmp(elts[i].val, "DOCUMENT_ROOT")) {
 
3480
                    object = PyUnicode_Decode(elts[i].val, strlen(elts[i].val),
 
3481
                                             Py_FileSystemDefaultEncoding,
 
3482
                                             "surrogateescape");
 
3483
                }
 
3484
                else if (!strcmp(elts[i].val, "SCRIPT_FILENAME")) {
 
3485
                    object = PyUnicode_Decode(elts[i].val, strlen(elts[i].val),
 
3486
                                             Py_FileSystemDefaultEncoding,
 
3487
                                             "surrogateescape");
 
3488
                }
 
3489
                else {
 
3490
                    object = PyUnicode_DecodeLatin1(elts[i].val,
 
3491
                                                    strlen(elts[i].val), NULL);
 
3492
                }
 
3493
#else
2819
3494
                object = PyString_FromString(elts[i].val);
 
3495
#endif
2820
3496
                PyDict_SetItemString(vars, elts[i].key, object);
2821
3497
                Py_DECREF(object);
2822
3498
            }
2825
3501
        }
2826
3502
    }
2827
3503
 
 
3504
    PyDict_DelItemString(vars, "PATH");
 
3505
 
2828
3506
    /* Now setup all the WSGI specific environment values. */
2829
3507
 
2830
 
    object = Py_BuildValue("(ii)", 1, 0);
 
3508
    object = Py_BuildValue("(ii)", 1, 1);
2831
3509
    PyDict_SetItemString(vars, "wsgi.version", object);
2832
3510
    Py_DECREF(object);
2833
3511
 
2839
3517
    PyDict_SetItemString(vars, "wsgi.multiprocess", object);
2840
3518
    Py_DECREF(object);
2841
3519
 
 
3520
#if defined(MOD_WSGI_WITH_DAEMONS)
 
3521
    if (wsgi_daemon_process) {
 
3522
        if (wsgi_daemon_process->group->threads == 1 &&
 
3523
            wsgi_daemon_process->group->maximum_requests == 1) {
 
3524
            PyDict_SetItemString(vars, "wsgi.run_once", Py_True);
 
3525
        }
 
3526
        else
 
3527
            PyDict_SetItemString(vars, "wsgi.run_once", Py_False);
 
3528
    }
 
3529
    else
 
3530
        PyDict_SetItemString(vars, "wsgi.run_once", Py_False);
 
3531
#else
2842
3532
    PyDict_SetItemString(vars, "wsgi.run_once", Py_False);
 
3533
#endif
2843
3534
 
2844
3535
    scheme = apr_table_get(r->subprocess_env, "HTTPS");
2845
3536
 
2846
3537
    if (scheme && (!strcasecmp(scheme, "On") || !strcmp(scheme, "1"))) {
 
3538
#if PY_MAJOR_VERSION >= 3
 
3539
        object = PyUnicode_FromString("https");
 
3540
#else
2847
3541
        object = PyString_FromString("https");
 
3542
#endif
2848
3543
        PyDict_SetItemString(vars, "wsgi.url_scheme", object);
2849
3544
        Py_DECREF(object);
2850
3545
    }
2851
3546
    else {
 
3547
#if PY_MAJOR_VERSION >= 3
 
3548
        object = PyUnicode_FromString("http");
 
3549
#else
2852
3550
        object = PyString_FromString("http");
 
3551
#endif
2853
3552
        PyDict_SetItemString(vars, "wsgi.url_scheme", object);
2854
3553
        Py_DECREF(object);
2855
3554
    }
2886
3585
     * structure instance.
2887
3586
     */
2888
3587
 
2889
 
    if (!wsgi_daemon_pool && self->config->apache_extensions) {
 
3588
    if (!wsgi_daemon_pool && self->config->pass_apache_request) {
2890
3589
        object = PyCObject_FromVoidPtr(self->r, 0);
2891
3590
        PyDict_SetItemString(vars, "apache.request_rec", object);
2892
3591
        Py_DECREF(object);
3005
3704
        return 0;
3006
3705
    }
3007
3706
 
3008
 
   if (PyInt_Check(object)) {
3009
 
       fo_offset = PyInt_AsLong(object);
3010
 
   }
3011
 
   else if (PyLong_Check(object)) {
 
3707
   if (PyLong_Check(object)) {
3012
3708
#if defined(HAVE_LONG_LONG)
3013
3709
       fo_offset = PyLong_AsLongLong(object);
3014
3710
#else
3015
3711
       fo_offset = PyLong_AsLong(object);
3016
3712
#endif
3017
3713
   }
 
3714
#if PY_MAJOR_VERSION < 3
 
3715
   else if (PyInt_Check(object)) {
 
3716
       fo_offset = PyInt_AsLong(object);
 
3717
   }
 
3718
#endif
 
3719
   else {
 
3720
       Py_DECREF(object);
 
3721
       return 0;
 
3722
   }
3018
3723
 
3019
3724
   if (PyErr_Occurred()){
3020
3725
       Py_DECREF(object);
3042
3747
     * logged later.
3043
3748
     */
3044
3749
 
3045
 
    if (!Adapter_output(self, "", 0))
 
3750
    if (!Adapter_output(self, "", 0, 0))
3046
3751
        return 1;
3047
3752
 
3048
3753
    /*
3125
3830
 
3126
3831
    if (self->sequence != NULL) {
3127
3832
        if (!Adapter_process_file_wrapper(self)) {
 
3833
            int aborted = 0;
 
3834
 
3128
3835
            iterator = PyObject_GetIter(self->sequence);
3129
3836
 
3130
3837
            if (iterator != NULL) {
3131
3838
                PyObject *item = NULL;
3132
3839
 
3133
3840
                while ((item = PyIter_Next(iterator))) {
 
3841
#if PY_MAJOR_VERSION >= 3
 
3842
                    if (PyUnicode_Check(item)) {
 
3843
                        PyObject *latin_item;
 
3844
                        latin_item = PyUnicode_AsLatin1String(item);
 
3845
                        if (!latin_item) {
 
3846
                            PyErr_Format(PyExc_TypeError, "sequence of "
 
3847
                                         "byte string values expected, value "
 
3848
                                         "containing non 'latin-1' characters "
 
3849
                                         "found");
 
3850
                            Py_DECREF(item);
 
3851
                            break;
 
3852
                        }
 
3853
 
 
3854
                        Py_DECREF(item);
 
3855
                        item = latin_item;
 
3856
                    }
 
3857
#endif
 
3858
 
3134
3859
                    if (!PyString_Check(item)) {
3135
 
                        PyErr_Format(PyExc_TypeError, "sequence of string "
3136
 
                                     "values expected, value of type %.200s "
3137
 
                                     "found", item->ob_type->tp_name);
 
3860
                        PyErr_Format(PyExc_TypeError, "sequence of byte "
 
3861
                                     "string values expected, value of "
 
3862
                                     "type %.200s found",
 
3863
                                     item->ob_type->tp_name);
3138
3864
                        Py_DECREF(item);
3139
3865
                        break;
3140
3866
                    }
3147
3873
                        break;
3148
3874
                    }
3149
3875
 
3150
 
                    if (length && !Adapter_output(self, msg, length)) {
 
3876
                    if (length && !Adapter_output(self, msg, length, 0)) {
 
3877
                        if (!PyErr_Occurred())
 
3878
                            aborted = 1;
3151
3879
                        Py_DECREF(item);
3152
3880
                        break;
3153
3881
                    }
3156
3884
                }
3157
3885
            }
3158
3886
 
3159
 
            if (!PyErr_Occurred()) {
3160
 
                if (Adapter_output(self, "", 0))
 
3887
            if (!PyErr_Occurred() && !aborted) {
 
3888
                if (Adapter_output(self, "", 0, 0))
3161
3889
                    self->result = OK;
3162
3890
            }
3163
3891
 
3250
3978
        return NULL;
3251
3979
    }
3252
3980
 
3253
 
    if (!PyArg_ParseTuple(args, "S:write", &item))
3254
 
        return NULL;
 
3981
    if (!PyArg_ParseTuple(args, "O:write", &item))
 
3982
        return NULL;
 
3983
 
 
3984
#if PY_MAJOR_VERSION >= 3
 
3985
    if (PyUnicode_Check(item)) {
 
3986
        PyObject *latin_item;
 
3987
        latin_item = PyUnicode_AsLatin1String(item);
 
3988
        if (!latin_item) {
 
3989
            PyErr_Format(PyExc_TypeError, "byte string value expected, "
 
3990
                         "value containing non 'latin-1' characters found");
 
3991
            Py_DECREF(item);
 
3992
            return NULL;
 
3993
        }
 
3994
 
 
3995
        Py_DECREF(item);
 
3996
        item = latin_item;
 
3997
    }
 
3998
#endif
 
3999
 
 
4000
    if (!PyString_Check(item)) {
 
4001
        PyErr_Format(PyExc_TypeError, "byte string value expected, value "
 
4002
                     "of type %.200s found", item->ob_type->tp_name);
 
4003
        Py_DECREF(item);
 
4004
        return NULL;
 
4005
    }
3255
4006
 
3256
4007
    data = PyString_AsString(item);
3257
4008
    length = PyString_Size(item);
3258
4009
 
3259
 
    if (!Adapter_output(self, data, length))
 
4010
    if (!Adapter_output(self, data, length, 1))
3260
4011
        return NULL;
3261
4012
 
3262
4013
    Py_INCREF(Py_None);
3291
4042
};
3292
4043
 
3293
4044
static PyTypeObject Adapter_Type = {
3294
 
    /* The ob_type field must be initialized in the module init function
3295
 
     * to be portable to Windows without using C++. */
3296
 
    PyObject_HEAD_INIT(NULL)
3297
 
    0,                      /*ob_size*/
 
4045
    PyVarObject_HEAD_INIT(NULL, 0)
3298
4046
    "mod_wsgi.Adapter",     /*tp_name*/
3299
4047
    sizeof(AdapterObject),  /*tp_basicsize*/
3300
4048
    0,                      /*tp_itemsize*/
3398
4146
    result = PyEval_CallObject(method, args);
3399
4147
 
3400
4148
    Py_DECREF(method);
3401
 
 
3402
 
    if (!result) {
3403
 
        Py_DECREF(args);
3404
 
        return 0;
3405
 
    }
3406
 
 
3407
 
    if (!PyString_Check(result)) {
3408
 
        PyErr_SetString(PyExc_TypeError,
3409
 
                        "file like object yielded non string type");
3410
 
        Py_DECREF(args);
3411
 
        Py_DECREF(result);
3412
 
        return 0;
3413
 
    }
3414
 
 
3415
 
    if (PyString_Size(result) == 0) {
3416
 
        PyErr_SetObject(PyExc_StopIteration, Py_None);
3417
 
        Py_DECREF(args);
3418
 
        Py_DECREF(result);
3419
 
        return 0;
3420
 
    }
3421
 
 
3422
4149
    Py_DECREF(args);
3423
4150
 
3424
 
    return result;
 
4151
    if (!result)
 
4152
        return 0;
 
4153
 
 
4154
    if (PyString_Check(result)) {
 
4155
        if (PyString_Size(result) == 0) {
 
4156
            PyErr_SetObject(PyExc_StopIteration, Py_None);
 
4157
            Py_DECREF(result);
 
4158
            return 0;
 
4159
        }
 
4160
 
 
4161
        return result;
 
4162
    }
 
4163
 
 
4164
#if PY_MAJOR_VERSION >= 3
 
4165
    if (PyUnicode_Check(result)) {
 
4166
        if (PyUnicode_GetSize(result) == 0) {
 
4167
            PyErr_SetObject(PyExc_StopIteration, Py_None);
 
4168
            Py_DECREF(result);
 
4169
            return 0;
 
4170
        }
 
4171
 
 
4172
        return result;
 
4173
    }
 
4174
#endif
 
4175
 
 
4176
    Py_DECREF(result);
 
4177
 
 
4178
    PyErr_SetString(PyExc_TypeError,
 
4179
                    "file like object yielded non string type");
 
4180
 
 
4181
    return 0;
3425
4182
}
3426
4183
 
3427
4184
static PyObject *Stream_close(StreamObject *self, PyObject *args)
3450
4207
};
3451
4208
 
3452
4209
static PyTypeObject Stream_Type = {
3453
 
    /* The ob_type field must be initialized in the module init function
3454
 
     * to be portable to Windows without using C++. */
3455
 
    PyObject_HEAD_INIT(NULL)
3456
 
    0,                      /*ob_size*/
 
4210
    PyVarObject_HEAD_INIT(NULL, 0)
3457
4211
    "mod_wsgi.Stream",      /*tp_name*/
3458
4212
    sizeof(StreamObject),   /*tp_basicsize*/
3459
4213
    0,                      /*tp_itemsize*/
3473
4227
    0,                      /*tp_getattro*/
3474
4228
    0,                      /*tp_setattro*/
3475
4229
    0,                      /*tp_as_buffer*/
 
4230
#if defined(Py_TPFLAGS_HAVE_ITER)
3476
4231
    Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_ITER, /*tp_flags*/
 
4232
#else
 
4233
    Py_TPFLAGS_DEFAULT,     /*tp_flags*/
 
4234
#endif
3477
4235
    0,                      /*tp_doc*/
3478
4236
    0,                      /*tp_traverse*/
3479
4237
    0,                      /*tp_clear*/
3531
4289
}
3532
4290
 
3533
4291
static PyTypeObject Restricted_Type = {
3534
 
    /* The ob_type field must be initialized in the module init function
3535
 
     * to be portable to Windows without using C++. */
3536
 
    PyObject_HEAD_INIT(NULL)
3537
 
    0,                      /*ob_size*/
 
4292
    PyVarObject_HEAD_INIT(NULL, 0)
3538
4293
    "mod_wsgi.Restricted",  /*tp_name*/
3539
4294
    sizeof(RestrictedObject), /*tp_basicsize*/
3540
4295
    0,                      /*tp_itemsize*/
3607
4362
            PyObject *args = NULL;
3608
4363
            PyObject *result = NULL;
3609
4364
            Py_INCREF(o);
3610
 
            log = (PyObject *)newLogObject(NULL, APLOG_WARNING);
 
4365
            log = newLogObject(NULL, APLOG_WARNING, NULL);
3611
4366
            args = Py_BuildValue("(OOO)", Py_None, Py_None, log);
3612
4367
            result = PyEval_CallObject(o, args);
3613
4368
            Py_XDECREF(result);
3634
4389
static const char *wsgi_python_path = NULL;
3635
4390
static const char *wsgi_python_eggs = NULL;
3636
4391
 
 
4392
#if APR_HAS_THREADS
 
4393
static int wsgi_thread_count = 0;
 
4394
static apr_threadkey_t *wsgi_thread_key;
 
4395
#endif
 
4396
 
3637
4397
typedef struct {
3638
4398
    PyObject_HEAD
3639
4399
    char *name;
3640
4400
    PyInterpreterState *interp;
3641
4401
    int owner;
 
4402
#if APR_HAS_THREADS
 
4403
    apr_hash_t *tstate_table;
 
4404
#else
 
4405
    PyThreadState *tstate;
 
4406
#endif
3642
4407
} InterpreterObject;
3643
4408
 
3644
4409
static PyTypeObject Interpreter_Type;
3645
4410
 
3646
 
static InterpreterObject *newInterpreterObject(const char *name,
3647
 
                                               PyInterpreterState *interp)
 
4411
static InterpreterObject *newInterpreterObject(const char *name)
3648
4412
{
3649
 
    InterpreterObject *self;
 
4413
    PyInterpreterState *interp = NULL;
 
4414
    InterpreterObject *self = NULL;
3650
4415
    PyThreadState *tstate = NULL;
3651
4416
    PyThreadState *save_tstate = NULL;
3652
4417
    PyObject *module = NULL;
3653
4418
    PyObject *object = NULL;
3654
4419
    PyObject *item = NULL;
3655
4420
 
 
4421
    /* Create handle for interpreter and local data. */
 
4422
 
3656
4423
    self = PyObject_New(InterpreterObject, &Interpreter_Type);
3657
4424
    if (self == NULL)
3658
4425
        return NULL;
3659
4426
 
3660
 
    /* Remember active thread state so can restore it. */
3661
 
 
3662
 
    save_tstate = PyThreadState_Swap(NULL);
 
4427
    /*
 
4428
     * If interpreter not named, then we want to bind
 
4429
     * to the first Python interpreter instance created.
 
4430
     * Give this interpreter an empty string as name.
 
4431
     */
 
4432
 
 
4433
    if (!name) {
 
4434
        interp = PyInterpreterState_Head();
 
4435
        while (interp->next)
 
4436
            interp = interp->next;
 
4437
 
 
4438
        name = "";
 
4439
    }
3663
4440
 
3664
4441
    /* Save away the interpreter name. */
3665
4442
 
3668
4445
    if (interp) {
3669
4446
        /*
3670
4447
         * Interpreter provided to us so will not be
3671
 
         * responsible for deleting it later.
 
4448
         * responsible for deleting it later. This will
 
4449
         * be the case for the main Python interpreter.
3672
4450
         */
3673
4451
 
3674
4452
        ap_log_error(APLOG_MARK, WSGI_LOG_INFO(0), wsgi_server,
3677
4455
 
3678
4456
        self->interp = interp;
3679
4457
        self->owner = 0;
3680
 
 
3681
 
        /*
3682
 
         * Need though now to create a thread state
3683
 
         * against the interpreter so we can preload
3684
 
         * it with our modules and fixups.
3685
 
         */
3686
 
 
3687
 
        tstate = PyThreadState_New(self->interp);
3688
 
        PyThreadState_Swap(tstate);
3689
4458
    }
3690
4459
    else {
3691
4460
        /*
 
4461
         * Remember active thread state so can restore
 
4462
         * it. This is actually the thread state
 
4463
         * associated with simplified GIL state API.
 
4464
         */
 
4465
 
 
4466
        save_tstate = PyThreadState_Swap(NULL);
 
4467
 
 
4468
        /*
3692
4469
         * Create the interpreter. If creation of the
3693
4470
         * interpreter fails it will restore the
3694
4471
         * existing active thread state for us so don't
3724
4501
     * the 'pdb' module.
3725
4502
     */
3726
4503
 
3727
 
    object = (PyObject *)newLogObject(NULL, APLOG_ERR);
 
4504
    object = newLogObject(NULL, APLOG_ERR, "stderr");
3728
4505
    PySys_SetObject("stderr", object);
3729
4506
    Py_DECREF(object);
3730
4507
 
3731
4508
#ifndef WIN32
3732
4509
    if (wsgi_parent_pid != getpid()) {
3733
4510
#endif
3734
 
        if (wsgi_server_config->restrict_stdout != 0) {
 
4511
        if (wsgi_server_config->restrict_stdout == 1) {
3735
4512
            object = (PyObject *)newRestrictedObject("sys.stdout");
3736
4513
            PySys_SetObject("stdout", object);
3737
4514
            Py_DECREF(object);
3738
4515
        }
3739
4516
        else {
3740
 
            object = (PyObject *)newLogObject(NULL, APLOG_ERR);
 
4517
            object = newLogObject(NULL, APLOG_ERR, "stdout");
3741
4518
            PySys_SetObject("stdout", object);
3742
4519
            Py_DECREF(object);
3743
4520
        }
3744
4521
 
3745
 
        if (wsgi_server_config->restrict_stdin != 0) {
 
4522
        if (wsgi_server_config->restrict_stdin == 1) {
3746
4523
            object = (PyObject *)newRestrictedObject("sys.stdin");
3747
4524
            PySys_SetObject("stdin", object);
3748
4525
            Py_DECREF(object);
3758
4535
     */
3759
4536
 
3760
4537
    object = PyList_New(0);
 
4538
#if PY_MAJOR_VERSION >= 3
 
4539
    item = PyUnicode_FromString("mod_wsgi");
 
4540
#else
3761
4541
    item = PyString_FromString("mod_wsgi");
 
4542
#endif
3762
4543
    PyList_Append(object, item);
3763
4544
    PySys_SetObject("argv", object);
3764
4545
    Py_DECREF(item);
3806
4587
                pwent = getpwuid(geteuid());
3807
4588
 
3808
4589
                if (getenv("USER")) {
 
4590
#if PY_MAJOR_VERSION >= 3
 
4591
                    key = PyUnicode_FromString("USER");
 
4592
                    value = PyUnicode_Decode(pwent->pw_name,
 
4593
                                             strlen(pwent->pw_name),
 
4594
                                             Py_FileSystemDefaultEncoding,
 
4595
                                             "surrogateescape");
 
4596
#else
3809
4597
                    key = PyString_FromString("USER");
3810
4598
                    value = PyString_FromString(pwent->pw_name);
 
4599
#endif
3811
4600
 
3812
4601
                    PyObject_SetItem(object, key, value);
3813
4602
 
3816
4605
                }
3817
4606
 
3818
4607
                if (getenv("USERNAME")) {
 
4608
#if PY_MAJOR_VERSION >= 3
 
4609
                    key = PyUnicode_FromString("USERNAME");
 
4610
                    value = PyUnicode_Decode(pwent->pw_name,
 
4611
                                             strlen(pwent->pw_name),
 
4612
                                             Py_FileSystemDefaultEncoding,
 
4613
                                             "surrogateescape");
 
4614
#else
3819
4615
                    key = PyString_FromString("USERNAME");
3820
4616
                    value = PyString_FromString(pwent->pw_name);
 
4617
#endif
3821
4618
 
3822
4619
                    PyObject_SetItem(object, key, value);
3823
4620
 
3826
4623
                }
3827
4624
 
3828
4625
                if (getenv("LOGNAME")) {
 
4626
#if PY_MAJOR_VERSION >= 3
 
4627
                    key = PyUnicode_FromString("LOGNAME");
 
4628
                    value = PyUnicode_Decode(pwent->pw_name,
 
4629
                                             strlen(pwent->pw_name),
 
4630
                                             Py_FileSystemDefaultEncoding,
 
4631
                                             "surrogateescape");
 
4632
#else
3829
4633
                    key = PyString_FromString("LOGNAME");
3830
4634
                    value = PyString_FromString(pwent->pw_name);
 
4635
#endif
3831
4636
 
3832
4637
                    PyObject_SetItem(object, key, value);
3833
4638
 
3868
4673
                struct passwd *pwent;
3869
4674
 
3870
4675
                pwent = getpwuid(geteuid());
 
4676
#if PY_MAJOR_VERSION >= 3
 
4677
                key = PyUnicode_FromString("HOME");
 
4678
                value = PyUnicode_Decode(pwent->pw_dir, strlen(pwent->pw_dir),
 
4679
                                         Py_FileSystemDefaultEncoding,
 
4680
                                         "surrogateescape");
 
4681
#else
3871
4682
                key = PyString_FromString("HOME");
3872
4683
                value = PyString_FromString(pwent->pw_dir);
 
4684
#endif
3873
4685
 
3874
4686
                PyObject_SetItem(object, key, value);
3875
4687
 
3905
4717
            object = PyDict_GetItemString(dict, "environ");
3906
4718
 
3907
4719
            if (object) {
 
4720
#if PY_MAJOR_VERSION >= 3
 
4721
                key = PyUnicode_FromString("PYTHON_EGG_CACHE");
 
4722
                value = PyUnicode_Decode(wsgi_python_eggs,
 
4723
                                         strlen(wsgi_python_eggs),
 
4724
                                         Py_FileSystemDefaultEncoding,
 
4725
                                         "surrogateescape");
 
4726
#else
3908
4727
                key = PyString_FromString("PYTHON_EGG_CACHE");
3909
4728
                value = PyString_FromString(wsgi_python_eggs);
 
4729
#endif
3910
4730
 
3911
4731
                PyObject_SetItem(object, key, value);
3912
4732
 
3976
4796
                end = strchr(start, DELIM);
3977
4797
 
3978
4798
                if (end) {
 
4799
#if PY_MAJOR_VERSION >= 3
 
4800
                    item = PyUnicode_Decode(start, end-start,
 
4801
                                            Py_FileSystemDefaultEncoding,
 
4802
                                            "surrogateescape");
 
4803
#else
3979
4804
                    item = PyString_FromStringAndSize(start, end-start);
 
4805
#endif
3980
4806
                    start = end+1;
3981
4807
 
3982
4808
                    value = PyString_AsString(item);
4006
4832
                    end = strchr(start, DELIM);
4007
4833
 
4008
4834
                    while (result && end) {
 
4835
#if PY_MAJOR_VERSION >= 3
 
4836
                        item = PyUnicode_Decode(start, end-start,
 
4837
                                                Py_FileSystemDefaultEncoding,
 
4838
                                                "surrogateescape");
 
4839
#else
4009
4840
                        item = PyString_FromStringAndSize(start, end-start);
 
4841
#endif
4010
4842
                        start = end+1;
4011
4843
 
4012
4844
                        value = PyString_AsString(item);
4087
4919
            Py_DECREF(old);
4088
4920
            Py_DECREF(new);
4089
4921
            Py_DECREF(tmp);
4090
 
 
4091
 
            Py_DECREF(module);
4092
4922
        }
4093
4923
        else {
4094
4924
            if (!module) {
4107
4937
                Py_END_ALLOW_THREADS
4108
4938
            }
4109
4939
        }
 
4940
 
 
4941
        Py_XDECREF(module);
4110
4942
    }
4111
4943
 
4112
4944
    /*
4131
4963
 
4132
4964
        if (module) {
4133
4965
            PyErr_Print();
4134
 
            PyErr_Clear();
4135
4966
 
4136
4967
            PyDict_DelItemString(modules, "mod_wsgi");
4137
4968
        }
4138
4969
 
 
4970
        PyErr_Clear();
 
4971
 
4139
4972
        module = PyImport_AddModule("mod_wsgi");
4140
4973
 
4141
4974
        Py_INCREF(module);
4162
4995
     * group to the Python 'mod_wsgi' module.
4163
4996
     */
4164
4997
 
 
4998
#if PY_MAJOR_VERSION >= 3
 
4999
    PyModule_AddObject(module, "process_group",
 
5000
                       PyUnicode_DecodeLatin1(wsgi_daemon_group,
 
5001
                       strlen(wsgi_daemon_group), NULL));
 
5002
    PyModule_AddObject(module, "application_group",
 
5003
                       PyUnicode_DecodeLatin1(name, strlen(name), NULL));
 
5004
#else
4165
5005
    PyModule_AddObject(module, "process_group",
4166
5006
                       PyString_FromString(wsgi_daemon_group));
4167
5007
    PyModule_AddObject(module, "application_group",
4168
5008
                       PyString_FromString(name));
 
5009
#endif
4169
5010
 
4170
5011
    Py_DECREF(module);
4171
5012
 
4199
5040
                Py_END_ALLOW_THREADS
4200
5041
 
4201
5042
                PyErr_Print();
4202
 
                PyErr_Clear();
4203
5043
 
4204
5044
                PyDict_DelItemString(modules, "apache");
4205
5045
 
4206
5046
                module = NULL;
4207
5047
            }
 
5048
 
 
5049
            PyErr_Clear();
4208
5050
        }
4209
5051
        else {
4210
5052
            Py_BEGIN_ALLOW_THREADS
4232
5074
 
4233
5075
    Py_DECREF(module);
4234
5076
 
4235
 
    /* Restore previous thread state. */
4236
 
 
4237
 
    PyThreadState_Clear(tstate);
4238
 
    PyThreadState_Swap(save_tstate);
4239
 
    PyThreadState_Delete(tstate);
 
5077
    /*
 
5078
     * Restore previous thread state. Only need to do
 
5079
     * this where had to create a new interpreter. This
 
5080
     * is basically anything except the first Python
 
5081
     * interpreter instance. We need to restore it in
 
5082
     * these cases as came into the function holding the
 
5083
     * simplified GIL state for this thread but creating
 
5084
     * the interpreter has resulted in a new thread
 
5085
     * state object being created bound to the newly
 
5086
     * created interpreter. In doing this though we want
 
5087
     * to cache the thread state object which has been
 
5088
     * created when interpreter is created. This is so
 
5089
     * it can be reused later ensuring that thread local
 
5090
     * data persists between requests.
 
5091
     */
 
5092
 
 
5093
    if (self->owner) {
 
5094
#if APR_HAS_THREADS
 
5095
        int thread_id = 0;
 
5096
        int *thread_handle = NULL;
 
5097
 
 
5098
        self->tstate_table = apr_hash_make(wsgi_server->process->pool);
 
5099
 
 
5100
        apr_threadkey_private_get((void**)&thread_handle, wsgi_thread_key);
 
5101
 
 
5102
        if (!thread_handle) {
 
5103
            thread_id = wsgi_thread_count++;
 
5104
            thread_handle = (int*)apr_pmemdup(wsgi_server->process->pool,
 
5105
                                              &thread_id, sizeof(thread_id));
 
5106
            apr_threadkey_private_set(thread_handle, wsgi_thread_key);
 
5107
        }
 
5108
        else {
 
5109
            thread_id = *thread_handle;
 
5110
        }
 
5111
 
 
5112
        if (wsgi_server_config->verbose_debugging) {
 
5113
            ap_log_error(APLOG_MARK, WSGI_LOG_DEBUG(0), wsgi_server,
 
5114
                         "mod_wsgi (pid=%d): Bind thread state for "
 
5115
                         "thread %d against interpreter '%s'.", getpid(),
 
5116
                         thread_id, self->name);
 
5117
        }
 
5118
 
 
5119
        apr_hash_set(self->tstate_table, thread_handle,
 
5120
                     sizeof(*thread_handle), tstate);
 
5121
 
 
5122
        PyThreadState_Swap(save_tstate);
 
5123
#else
 
5124
        self->tstate = tstate;
 
5125
        PyThreadState_Swap(save_tstate);
 
5126
#endif
 
5127
    }
4240
5128
 
4241
5129
    return self;
4242
5130
}
4258
5146
    PyEval_ReleaseLock();
4259
5147
 
4260
5148
    if (*self->name) {
4261
 
        tstate = PyThreadState_New(self->interp);
 
5149
#if APR_HAS_THREADS
 
5150
        int thread_id = 0;
 
5151
        int *thread_handle = NULL;
 
5152
 
 
5153
        apr_threadkey_private_get((void**)&thread_handle, wsgi_thread_key);
 
5154
 
 
5155
        if (!thread_handle) {
 
5156
            thread_id = wsgi_thread_count++;
 
5157
            thread_handle = (int*)apr_pmemdup(wsgi_server->process->pool,
 
5158
                                              &thread_id, sizeof(thread_id));
 
5159
            apr_threadkey_private_set(thread_handle, wsgi_thread_key);
 
5160
        }
 
5161
        else {
 
5162
            thread_id = *thread_handle;
 
5163
        }
 
5164
 
 
5165
        tstate = apr_hash_get(self->tstate_table, &thread_id,
 
5166
                              sizeof(thread_id));
 
5167
 
 
5168
        if (!tstate) {
 
5169
            tstate = PyThreadState_New(self->interp);
 
5170
 
 
5171
            if (wsgi_server_config->verbose_debugging) {
 
5172
                ap_log_error(APLOG_MARK, WSGI_LOG_DEBUG(0), wsgi_server,
 
5173
                             "mod_wsgi (pid=%d): Create thread state for "
 
5174
                             "thread %d against interpreter '%s'.", getpid(),
 
5175
                             thread_id, self->name);
 
5176
            }
 
5177
 
 
5178
            apr_hash_set(self->tstate_table, thread_handle,
 
5179
                         sizeof(*thread_handle), tstate);
 
5180
        }
 
5181
#else
 
5182
        tstate = self->tstate;
 
5183
#endif
 
5184
 
4262
5185
        PyEval_AcquireThread(tstate);
4263
5186
    }
4264
5187
    else
4283
5206
     * Because the thread state we are using was created outside
4284
5207
     * of any Python code and is not the same as the Python main
4285
5208
     * thread, there is no record of it within the 'threading'
4286
 
     * module. We thus need to call the 'currentThread()'
4287
 
     * function of the 'threading' module to force it to create
4288
 
     * a thread handle for the thread. If we do not do this,
4289
 
     * then the 'threading' modules exit function will always
4290
 
     * fail because it will not be able to find a handle for
4291
 
     * this thread.
 
5209
     * module. We thus need to access current thread function of
 
5210
     * the 'threading' module to force it to create a thread
 
5211
     * handle for the thread. If we do not do this, then the
 
5212
     * 'threading' modules exit function will always fail
 
5213
     * because it will not be able to find a handle for this
 
5214
     * thread.
4292
5215
     */
4293
5216
 
4294
5217
    module = PyImport_ImportModule("threading");
4301
5224
        PyObject *func = NULL;
4302
5225
 
4303
5226
        dict = PyModule_GetDict(module);
 
5227
#if PY_MAJOR_VERSION >= 3
 
5228
        func = PyDict_GetItemString(dict, "current_thread");
 
5229
#else
4304
5230
        func = PyDict_GetItemString(dict, "currentThread");
 
5231
#endif
4305
5232
        if (func) {
4306
5233
            PyObject *res = NULL;
4307
5234
            Py_INCREF(func);
4371
5298
                        PyObject *log = NULL;
4372
5299
                        PyObject *args = NULL;
4373
5300
                        Py_INCREF(o);
4374
 
                        log = (PyObject *)newLogObject(NULL, APLOG_ERR);
 
5301
                        log = newLogObject(NULL, APLOG_ERR, NULL);
4375
5302
                        args = Py_BuildValue("(OOOOO)", type, value,
4376
5303
                                             traceback, Py_None, log);
4377
5304
                        result = PyEval_CallObject(o, args);
4419
5346
 
4420
5347
    /* Finally done with 'threading' module. */
4421
5348
 
4422
 
    if (module) {
4423
 
        Py_DECREF(module);
 
5349
    Py_XDECREF(module);
 
5350
 
 
5351
    /*
 
5352
     * Invoke exit functions by calling sys.exitfunc() for
 
5353
     * Python 2.X and atexit._run_exitfuncs() for Python 3.X.
 
5354
     * Note that in Python 3.X we can't call this on main Python
 
5355
     * interpreter as for Python 3.X it doesn't deregister
 
5356
     * functions as called, so have no choice but to rely on
 
5357
     * Py_Finalize() to do it for the main interpreter. Now
 
5358
     * that simplified GIL state API usage sorted out, this
 
5359
     * should be okay.
 
5360
     */
 
5361
 
 
5362
    module = NULL;
 
5363
 
 
5364
#if PY_MAJOR_VERSION >= 3
 
5365
    if (self->owner) {
 
5366
        module = PyImport_ImportModule("atexit");
 
5367
 
 
5368
        if (module) {
 
5369
            PyObject *dict = NULL;
 
5370
 
 
5371
            dict = PyModule_GetDict(module);
 
5372
            exitfunc = PyDict_GetItemString(dict, "_run_exitfuncs");
 
5373
        }
 
5374
        else
 
5375
            PyErr_Clear();
4424
5376
    }
4425
 
 
4426
 
    /* Invoke exit functions by calling sys.exitfunc(). */
4427
 
 
 
5377
#else
4428
5378
    exitfunc = PySys_GetObject("exitfunc");
 
5379
#endif
4429
5380
 
4430
5381
    if (exitfunc) {
4431
5382
        PyObject *res = NULL;
4445
5396
                Py_BEGIN_ALLOW_THREADS
4446
5397
                ap_log_error(APLOG_MARK, WSGI_LOG_ERR(0), wsgi_server,
4447
5398
                             "mod_wsgi (pid=%d): SystemExit exception "
4448
 
                             "raised by sys.exitfunc() ignored.", getpid());
 
5399
                             "raised by exit functions ignored.", getpid());
4449
5400
                Py_END_ALLOW_THREADS
4450
5401
            }
4451
5402
            else {
4452
5403
                Py_BEGIN_ALLOW_THREADS
4453
5404
                ap_log_error(APLOG_MARK, WSGI_LOG_ERR(0), wsgi_server,
4454
5405
                             "mod_wsgi (pid=%d): Exception occurred within "
4455
 
                             "sys.exitfunc().", getpid());
 
5406
                             "exit functions.", getpid());
4456
5407
                Py_END_ALLOW_THREADS
4457
5408
            }
4458
5409
 
4480
5431
                    PyObject *log = NULL;
4481
5432
                    PyObject *args = NULL;
4482
5433
                    Py_INCREF(o);
4483
 
                    log = (PyObject *)newLogObject(NULL, APLOG_ERR);
 
5434
                    log = newLogObject(NULL, APLOG_ERR, NULL);
4484
5435
                    args = Py_BuildValue("(OOOOO)", type, value,
4485
5436
                                         traceback, Py_None, log);
4486
5437
                    result = PyEval_CallObject(o, args);
4525
5476
        Py_DECREF(exitfunc);
4526
5477
    }
4527
5478
 
 
5479
    Py_XDECREF(module);
 
5480
 
4528
5481
    /* If we own it, we destroy it. */
4529
5482
 
4530
5483
    if (!self->owner) {
4540
5493
 
4541
5494
        PyEval_AcquireLock();
4542
5495
    }
4543
 
    else
 
5496
    else {
 
5497
        /*
 
5498
         * We need to destroy all the thread state objects
 
5499
         * associated with the interpreter. If there are
 
5500
         * background threads that were created then this
 
5501
         * may well cause them to crash the next time they
 
5502
         * try to run. Only saving grace is that we are
 
5503
         * trying to shutdown the process.
 
5504
         */
 
5505
 
 
5506
        PyThreadState *tstate_save = tstate;
 
5507
        PyThreadState *tstate_next = NULL;
 
5508
 
 
5509
        PyThreadState_Swap(NULL);
 
5510
 
 
5511
        tstate = tstate->interp->tstate_head;
 
5512
        while (tstate) {
 
5513
            tstate_next = tstate->next;
 
5514
            if (tstate != tstate_save) {
 
5515
                PyThreadState_Swap(tstate);
 
5516
                PyThreadState_Clear(tstate);
 
5517
                PyThreadState_Swap(NULL);
 
5518
                PyThreadState_Delete(tstate);
 
5519
            }
 
5520
            tstate = tstate_next;
 
5521
        }
 
5522
 
 
5523
        tstate = tstate_save;
 
5524
 
 
5525
        PyThreadState_Swap(tstate);
 
5526
 
 
5527
        /* Can now destroy the interpreter. */
 
5528
 
4544
5529
        Py_EndInterpreter(tstate);
 
5530
    }
4545
5531
 
4546
5532
    free(self->name);
4547
5533
 
4549
5535
}
4550
5536
 
4551
5537
static PyTypeObject Interpreter_Type = {
4552
 
    /* The ob_type field must be initialized in the module init function
4553
 
     * to be portable to Windows without using C++. */
4554
 
    PyObject_HEAD_INIT(NULL)
4555
 
    0,                      /*ob_size*/
 
5538
    PyVarObject_HEAD_INIT(NULL, 0)
4556
5539
    "mod_wsgi.Interpreter",  /*tp_name*/
4557
5540
    sizeof(InterpreterObject), /*tp_basicsize*/
4558
5541
    0,                      /*tp_itemsize*/
4599
5582
 * Startup and shutdown of Python interpreter. In mod_wsgi if
4600
5583
 * the Python interpreter hasn't been initialised by another
4601
5584
 * Apache module such as mod_python, we will take control and
4602
 
 * initialise it. Need to remember that we initialised Python as
4603
 
 * in doing that we also take responsibility for performing
4604
 
 * special Python fixups after Apache is forked and child
4605
 
 * process has run.
 
5585
 * initialise it. Need to remember that we initialised Python
 
5586
 * and whether done in parent or child process as when done in
 
5587
 * the parent we also take responsibility for performing special
 
5588
 * Python fixups after Apache is forked and child process has
 
5589
 * run.
 
5590
 *
 
5591
 * Note that by default we now defer initialisation of Python
 
5592
 * until after the fork of processes as Python 3.X by design
 
5593
 * doesn't clean up properly when it is destroyed causing
 
5594
 * significant memory leaks into Apache parent process on an
 
5595
 * Apache restart. Some Python 2.X versions also have real
 
5596
 * memory leaks but not near as much. The result of deferring
 
5597
 * initialisation is that can't benefit from copy on write
 
5598
 * semantics for loaded data across a fork. Each process will
 
5599
 * therefore have higher memory requirement where Python needs
 
5600
 * to be used.
4606
5601
 */
4607
5602
 
4608
5603
static int wsgi_python_initialized = 0;
4609
5604
 
 
5605
#if defined(MOD_WSGI_DISABLE_EMBEDDED)
 
5606
static int wsgi_python_required = 0;
 
5607
#else
 
5608
static int wsgi_python_required = -1;
 
5609
#endif
 
5610
 
 
5611
static int wsgi_python_after_fork = 1;
 
5612
 
4610
5613
static void wsgi_python_version(void)
4611
5614
{
4612
5615
    const char *compile = PY_VERSION;
4619
5622
                     "mod_wsgi: Compiled for Python/%s.", compile);
4620
5623
        ap_log_error(APLOG_MARK, WSGI_LOG_WARNING(0), wsgi_server,
4621
5624
                     "mod_wsgi: Runtime using Python/%s.", dynamic);
4622
 
        ap_log_error(APLOG_MARK, WSGI_LOG_WARNING(0), wsgi_server,
4623
 
                     "mod_wsgi: Python module path '%s'.",
4624
 
                     Py_GetPath());
4625
5625
    }
4626
5626
}
4627
5627
 
4630
5630
    PyInterpreterState *interp = NULL;
4631
5631
    PyThreadState *tstate = NULL;
4632
5632
 
 
5633
    PyObject *module = NULL;
 
5634
 
4633
5635
    ap_log_error(APLOG_MARK, WSGI_LOG_INFO(0), wsgi_server,
4634
5636
                 "mod_wsgi (pid=%d): Terminating Python.", getpid());
4635
5637
 
4636
 
    PyEval_AcquireLock();
4637
 
 
4638
 
    interp = PyInterpreterState_Head();
4639
 
    while (interp->next)
4640
 
        interp = interp->next;
4641
 
 
4642
 
    tstate = PyThreadState_New(interp);
4643
 
    PyThreadState_Swap(tstate);
 
5638
    PyGILState_Ensure();
 
5639
 
 
5640
    /*
 
5641
     * Work around bug in Python 3.X whereby it will crash if
 
5642
     * atexit imported into sub interpreter, but never imported
 
5643
     * into main interpreter before calling Py_Finalize(). We
 
5644
     * perform an import of atexit module and it as side effect
 
5645
     * must be performing required initialisation.
 
5646
     */
 
5647
 
 
5648
    module = PyImport_ImportModule("atexit");
 
5649
    Py_XDECREF(module);
4644
5650
 
4645
5651
    Py_Finalize();
4646
5652
 
4647
 
    PyThreadState_Swap(NULL);
4648
 
 
4649
 
    PyEval_ReleaseLock();
4650
 
 
4651
5653
    wsgi_python_initialized = 0;
4652
5654
 
 
5655
    ap_log_error(APLOG_MARK, WSGI_LOG_INFO(0), wsgi_server,
 
5656
                 "mod_wsgi (pid=%d): Python has shutdown.", getpid());
 
5657
 
4653
5658
    return APR_SUCCESS;
4654
5659
}
4655
5660
 
4661
5666
{
4662
5667
    if (wsgi_parent_pid == getpid()) {
4663
5668
        /*
4664
 
         * Destroy Python itself including the main
4665
 
         * interpreter. If mod_python is being loaded it
4666
 
         * is left to mod_python to destroy Python,
4667
 
         * although it currently doesn't do so.
 
5669
         * Destroy Python itself including the main
 
5670
         * interpreter. If mod_python is being loaded it
 
5671
         * is left to mod_python to destroy Python,
 
5672
         * although it currently doesn't do so.
4668
5673
         */
4669
5674
 
4670
5675
        if (wsgi_python_initialized)
4685
5690
    static int initialized = 1;
4686
5691
#endif
4687
5692
 
4688
 
    /*
4689
 
     * Check that the version of Python found at
4690
 
     * runtime is what was used at compilation.
4691
 
     */
4692
 
 
4693
 
    wsgi_python_version();
4694
 
 
4695
5693
    /* Perform initialisation if required. */
4696
5694
 
4697
5695
    if (!Py_IsInitialized() || !initialized) {
4698
 
        char buffer[256];
4699
 
        const char *token = NULL;
4700
 
        const char *version = NULL;
 
5696
 
 
5697
        /* Enable Python 3.0 migration warnings. */
 
5698
 
 
5699
#if PY_MAJOR_VERSION == 2 && PY_MINOR_VERSION >= 6
 
5700
        if (wsgi_server_config->py3k_warning_flag == 1)
 
5701
            Py_Py3kWarningFlag++;
 
5702
#endif
4701
5703
 
4702
5704
        /* Check for Python paths and optimisation flag. */
4703
5705
 
4706
5708
        else
4707
5709
            Py_OptimizeFlag = 0;
4708
5710
 
4709
 
        if (wsgi_server_config->python_home)
 
5711
        /* Check for control options for Python warnings. */
 
5712
 
 
5713
        if (wsgi_server_config->python_warnings) {
 
5714
            apr_array_header_t *options = NULL;
 
5715
            char **entries;
 
5716
 
 
5717
            int i;
 
5718
 
 
5719
            options = wsgi_server_config->python_warnings;
 
5720
            entries = (char **)options->elts;
 
5721
 
 
5722
            for (i = 0; i < options->nelts; ++i) {
 
5723
#if PY_MAJOR_VERSION >= 3
 
5724
                wchar_t *s = NULL;
 
5725
                int len = strlen(entries[i])+1;
 
5726
 
 
5727
                s = (wchar_t *)apr_palloc(p, len*sizeof(wchar_t));
 
5728
 
 
5729
#if defined(WIN32) && defined(APR_HAS_UNICODE_FS)
 
5730
                wsgi_utf8_to_unicode_path(s, len, entries[i]);
 
5731
#else
 
5732
                mbstowcs(s, entries[i], len);
 
5733
#endif
 
5734
                PySys_AddWarnOption(s);
 
5735
#else
 
5736
                PySys_AddWarnOption(entries[i]);
 
5737
#endif
 
5738
            }
 
5739
        }
 
5740
 
 
5741
        /* Check for Python HOME being overridden. */
 
5742
 
 
5743
#if PY_MAJOR_VERSION >= 3
 
5744
        if (wsgi_server_config->python_home) {
 
5745
            wchar_t *s = NULL;
 
5746
            int len = strlen(wsgi_server_config->python_home)+1;
 
5747
 
 
5748
            ap_log_error(APLOG_MARK, WSGI_LOG_INFO(0), wsgi_server,
 
5749
                         "mod_wsgi (pid=%d): Python home %s.", getpid(),
 
5750
                         wsgi_server_config->python_home);
 
5751
 
 
5752
            s = (wchar_t *)apr_palloc(p, len*sizeof(wchar_t));
 
5753
 
 
5754
#if defined(WIN32) && defined(APR_HAS_UNICODE_FS)
 
5755
            wsgi_utf8_to_unicode_path(s, len, wsgi_server_config->python_home);
 
5756
#else
 
5757
            mbstowcs(s, wsgi_server_config->python_home, len);
 
5758
#endif
 
5759
            Py_SetPythonHome(s);
 
5760
        }
 
5761
#else
 
5762
        if (wsgi_server_config->python_home) {
 
5763
            ap_log_error(APLOG_MARK, WSGI_LOG_INFO(0), wsgi_server,
 
5764
                         "mod_wsgi (pid=%d): Python home %s.", getpid(),
 
5765
                         wsgi_server_config->python_home);
 
5766
 
4710
5767
            Py_SetPythonHome((char *)wsgi_server_config->python_home);
 
5768
        }
 
5769
#endif
 
5770
 
 
5771
        /*
 
5772
         * Work around bug in Python 3.1 where it will crash
 
5773
         * when used in non console application on Windows if
 
5774
         * stdin/stdout have been initialised and aren't null.
 
5775
         */
 
5776
 
 
5777
#if defined(WIN32) && PY_MAJOR_VERSION >= 3
 
5778
        _wputenv(L"PYTHONIOENCODING=cp1252:backslashreplace");
 
5779
#endif
4711
5780
 
4712
5781
        /* Initialise Python. */
4713
5782
 
4718
5787
 
4719
5788
        Py_Initialize();
4720
5789
 
4721
 
        /* Record version string with Apache. */
4722
 
 
4723
 
        version = Py_GetVersion();
4724
 
 
4725
 
        token = version;
4726
 
        while (*token && *token != ' ')
4727
 
            token++;
4728
 
 
4729
 
        strcpy(buffer, "Python/");
4730
 
        strncat(buffer, version, token - version);
4731
 
 
4732
 
#if AP_SERVER_MAJORVERSION_NUMBER < 2
4733
 
        ap_add_version_component(buffer);
4734
 
#else
4735
 
        ap_add_version_component(p, buffer);
4736
 
#endif
4737
 
 
4738
5790
        /* Initialise threading. */
4739
5791
 
4740
5792
        PyEval_InitThreads();
4779
5831
    PyInterpreterState *interp = NULL;
4780
5832
    InterpreterObject *handle = NULL;
4781
5833
 
 
5834
    PyGILState_STATE state;
 
5835
 
4782
5836
    /*
4783
5837
     * In a multithreaded MPM must protect the
4784
5838
     * interpreters table. This lock is only needed to
4785
5839
     * avoid a secondary thread coming in and creating
4786
5840
     * the same interpreter if Python releases the GIL
4787
 
     * when an interpreter is being created. When
4788
 
     * are removing an interpreter from the table in
4789
 
     * preparation for reloading, don't need to have
4790
 
     * it.
 
5841
     * when an interpreter is being created.
4791
5842
     */
4792
5843
 
4793
5844
#if APR_HAS_THREADS
4799
5850
     * Python GIL is held, so need to acquire it.
4800
5851
     */
4801
5852
 
4802
 
    PyEval_AcquireLock();
 
5853
    state = PyGILState_Ensure();
4803
5854
 
4804
5855
    /*
4805
5856
     * Check if already have interpreter instance and
4810
5861
                                                       name);
4811
5862
 
4812
5863
    if (!handle) {
4813
 
        handle = newInterpreterObject(name, NULL);
 
5864
        handle = newInterpreterObject(name);
4814
5865
 
4815
5866
        if (!handle) {
4816
5867
            ap_log_error(APLOG_MARK, WSGI_LOG_CRIT(0), wsgi_server,
4820
5871
            PyErr_Print();
4821
5872
            PyErr_Clear();
4822
5873
 
4823
 
            PyEval_ReleaseLock();
 
5874
            PyGILState_Release(state);
4824
5875
 
4825
5876
#if APR_HAS_THREADS
4826
5877
            apr_thread_mutex_unlock(wsgi_interp_lock);
4844
5895
     * extension modules which use that will still work.
4845
5896
     */
4846
5897
 
4847
 
    PyEval_ReleaseLock();
 
5898
    PyGILState_Release(state);
4848
5899
 
4849
5900
#if APR_HAS_THREADS
4850
5901
    apr_thread_mutex_unlock(wsgi_interp_lock);
4851
5902
#endif
4852
5903
 
4853
5904
    if (*name) {
4854
 
        tstate = PyThreadState_New(interp);
 
5905
#if APR_HAS_THREADS
 
5906
        int thread_id = 0;
 
5907
        int *thread_handle = NULL;
 
5908
 
 
5909
        apr_threadkey_private_get((void**)&thread_handle, wsgi_thread_key);
 
5910
 
 
5911
        if (!thread_handle) {
 
5912
            thread_id = wsgi_thread_count++;
 
5913
            thread_handle = (int*)apr_pmemdup(wsgi_server->process->pool,
 
5914
                                              &thread_id, sizeof(thread_id));
 
5915
            apr_threadkey_private_set(thread_handle, wsgi_thread_key);
 
5916
        }
 
5917
        else {
 
5918
            thread_id = *thread_handle;
 
5919
        }
 
5920
 
 
5921
        tstate = apr_hash_get(handle->tstate_table, &thread_id,
 
5922
                              sizeof(thread_id));
 
5923
 
 
5924
        if (!tstate) {
 
5925
            tstate = PyThreadState_New(interp);
 
5926
 
 
5927
            if (wsgi_server_config->verbose_debugging) {
 
5928
                ap_log_error(APLOG_MARK, WSGI_LOG_DEBUG(0), wsgi_server,
 
5929
                             "mod_wsgi (pid=%d): Create thread state for "
 
5930
                             "thread %d against interpreter '%s'.", getpid(),
 
5931
                             thread_id, handle->name);
 
5932
            }
 
5933
 
 
5934
            apr_hash_set(handle->tstate_table, thread_handle,
 
5935
                         sizeof(*thread_handle), tstate);
 
5936
        }
 
5937
#else
 
5938
        tstate = handle->tstate;
 
5939
#endif
 
5940
 
4855
5941
        PyEval_AcquireThread(tstate);
4856
5942
    }
4857
 
    else
 
5943
    else {
4858
5944
        PyGILState_Ensure();
4859
5945
 
 
5946
        /*
 
5947
         * When simplified GIL state API is used, the thread
 
5948
         * local data only persists for the extent of the top
 
5949
         * level matching ensure/release calls. We want to
 
5950
         * extend lifetime of the thread local data beyond
 
5951
         * that, retaining it for all requests within the one
 
5952
         * thread for the life of the process. To do that we
 
5953
         * need to artificially increment the reference count
 
5954
         * for the associated thread state object.
 
5955
         */
 
5956
 
 
5957
        tstate = PyThreadState_Get();
 
5958
        if (tstate && tstate->gilstate_counter == 1)
 
5959
            tstate->gilstate_counter++;
 
5960
    }
 
5961
 
4860
5962
    return handle;
4861
5963
}
4862
5964
 
4876
5978
 
4877
5979
    if (*handle->name) {
4878
5980
        tstate = PyThreadState_Get();
4879
 
 
4880
 
        PyThreadState_Clear(tstate);
4881
5981
        PyEval_ReleaseThread(tstate);
4882
 
        PyThreadState_Delete(tstate);
4883
5982
    }
4884
5983
    else
4885
5984
        PyGILState_Release(PyGILState_UNLOCKED);
4914
6013
    PyObject *co = NULL;
4915
6014
    struct _node *n = NULL;
4916
6015
 
 
6016
#if defined(WIN32) && defined(APR_HAS_UNICODE_FS)
 
6017
    apr_wchar_t wfilename[APR_PATH_MAX];
 
6018
#endif
 
6019
 
4917
6020
    if (exists) {
4918
6021
        Py_BEGIN_ALLOW_THREADS
4919
6022
        if (r) {
4947
6050
        Py_END_ALLOW_THREADS
4948
6051
    }
4949
6052
 
4950
 
    if (!(fp = fopen(filename, "r"))) {
 
6053
#if defined(WIN32) && defined(APR_HAS_UNICODE_FS)
 
6054
    if (wsgi_utf8_to_unicode_path(wfilename, sizeof(wfilename) /
 
6055
                                  sizeof(apr_wchar_t), filename)) {
 
6056
 
 
6057
        Py_BEGIN_ALLOW_THREADS
 
6058
        if (r) {
 
6059
            ap_log_rerror(APLOG_MARK, WSGI_LOG_ERR(0), r,
 
6060
                          "mod_wsgi (pid=%d, process='%s', "
 
6061
                          "application='%s'): Failed to convert '%s' "
 
6062
                          "to UCS2 filename.", getpid(),
 
6063
                          process_group, application_group, filename);
 
6064
        }
 
6065
        else {
 
6066
            ap_log_error(APLOG_MARK, WSGI_LOG_ERR(0), wsgi_server,
 
6067
                         "mod_wsgi (pid=%d, process='%s', "
 
6068
                         "application='%s'): Failed to convert '%s' "
 
6069
                         "to UCS2 filename.", getpid(),
 
6070
                         process_group, application_group, filename);
 
6071
        }
 
6072
        Py_END_ALLOW_THREADS
 
6073
        return NULL;
 
6074
    }
 
6075
 
 
6076
    fp = _wfopen(wfilename, "r");
 
6077
#else
 
6078
    fp = fopen(filename, "r");
 
6079
#endif
 
6080
 
 
6081
    if (!fp) {
4951
6082
        Py_BEGIN_ALLOW_THREADS
4952
6083
        if (r) {
4953
6084
            ap_log_rerror(APLOG_MARK, WSGI_LOG_ERR(errno), r,
4962
6093
                         process_group, application_group, filename);
4963
6094
        }
4964
6095
        Py_END_ALLOW_THREADS
4965
 
        PyErr_SetFromErrno(PyExc_IOError);
4966
6096
        return NULL;
4967
6097
    }
4968
6098
 
4970
6100
 
4971
6101
    fclose(fp);
4972
6102
 
4973
 
    if (!n)
 
6103
    if (!n) {
 
6104
        Py_BEGIN_ALLOW_THREADS
 
6105
        if (r) {
 
6106
            ap_log_rerror(APLOG_MARK, WSGI_LOG_ERR(0), r,
 
6107
                          "mod_wsgi (pid=%d, process='%s', application='%s'): "
 
6108
                          "Failed to parse WSGI script file '%s'.", getpid(),
 
6109
                          process_group, application_group, filename);
 
6110
        }
 
6111
        else {
 
6112
            ap_log_error(APLOG_MARK, WSGI_LOG_ERR(0), wsgi_server,
 
6113
                         "mod_wsgi (pid=%d, process='%s', application='%s'): "
 
6114
                         "Failed to parse WSGI script file '%s'.", getpid(),
 
6115
                         process_group, application_group, filename);
 
6116
        }
 
6117
        Py_END_ALLOW_THREADS
4974
6118
        return NULL;
 
6119
    }
4975
6120
 
4976
6121
    co = (PyObject *)PyNode_Compile(n, filename);
4977
6122
    PyNode_Free(n);
5014
6159
        PyModule_AddObject(m, "__mtime__", object);
5015
6160
    }
5016
6161
    else {
5017
 
        LogObject *log;
5018
 
 
5019
6162
        Py_BEGIN_ALLOW_THREADS
5020
6163
        if (r) {
5021
6164
            ap_log_rerror(APLOG_MARK, WSGI_LOG_ERR(0), r,
5029
6172
        }
5030
6173
        Py_END_ALLOW_THREADS
5031
6174
 
5032
 
        log = newLogObject(r, APLOG_ERR);
5033
 
        wsgi_log_python_error(r, log, filename);
5034
 
        Py_DECREF(log);
 
6175
        wsgi_log_python_error(r, NULL, filename);
5035
6176
    }
5036
6177
 
5037
6178
    return m;
5038
6179
}
5039
6180
 
5040
6181
static int wsgi_reload_required(apr_pool_t *pool, request_rec *r,
5041
 
                                const char *filename, PyObject *module)
 
6182
                                const char *filename, PyObject *module,
 
6183
                                const char *resource)
5042
6184
{
5043
6185
    PyObject *dict = NULL;
5044
6186
    PyObject *object = NULL;
5083
6225
    else
5084
6226
        return 1;
5085
6227
 
 
6228
    if (resource) {
 
6229
        PyObject *dict = NULL;
 
6230
        PyObject *object = NULL;
 
6231
 
 
6232
        dict = PyModule_GetDict(module);
 
6233
        object = PyDict_GetItemString(dict, "reload_required");
 
6234
 
 
6235
        if (object) {
 
6236
            PyObject *args = NULL;
 
6237
            PyObject *result = NULL;
 
6238
 
 
6239
            Py_INCREF(object);
 
6240
            args = Py_BuildValue("(s)", resource);
 
6241
            result = PyEval_CallObject(object, args);
 
6242
            Py_DECREF(args);
 
6243
            Py_DECREF(object);
 
6244
 
 
6245
            if (result && PyObject_IsTrue(result)) {
 
6246
                Py_DECREF(result);
 
6247
 
 
6248
                return 1;
 
6249
            }
 
6250
 
 
6251
            if (PyErr_Occurred())
 
6252
                wsgi_log_python_error(r, NULL, filename);
 
6253
 
 
6254
            Py_XDECREF(result);
 
6255
        }
 
6256
    }
 
6257
 
5086
6258
    return 0;
5087
6259
}
5088
6260
 
5147
6319
 
5148
6320
    /* Calculate the Python module name to be used for script. */
5149
6321
 
5150
 
    script = r->filename;
 
6322
    if (config->handler_script && *config->handler_script)
 
6323
        script = config->handler_script;
 
6324
    else
 
6325
        script = r->filename;
5151
6326
 
5152
6327
    name = wsgi_module_name(r->pool, script);
5153
6328
 
5175
6350
    /*
5176
6351
     * If script reloading is enabled and the module for it has
5177
6352
     * previously been loaded, see if it has been modified since
5178
 
     * the last time it was accessed.
 
6353
     * the last time it was accessed. For a handler script will
 
6354
     * also see if it contains a custom function for determining
 
6355
     * if a reload should be performed.
5179
6356
     */
5180
6357
 
5181
6358
    if (module && config->script_reloading) {
5182
 
        if (wsgi_reload_required(r->pool, r, script, module)) {
 
6359
        if (wsgi_reload_required(r->pool, r, script, module, r->filename)) {
5183
6360
            /*
5184
6361
             * Script file has changed. Discard reference to
5185
6362
             * loaded module and work out what action we are
5192
6369
            module = NULL;
5193
6370
 
5194
6371
#if defined(MOD_WSGI_WITH_DAEMONS)
5195
 
            if (*config->process_group &&
5196
 
                config->reload_mechanism == WSGI_RELOAD_PROCESS) {
5197
 
 
 
6372
            if (*config->process_group) {
5198
6373
                /*
5199
6374
                 * Need to restart the daemon process. We bail
5200
6375
                 * out on the request process here, sending back
5267
6442
     */
5268
6443
 
5269
6444
#if defined(MOD_WSGI_WITH_DAEMONS)
5270
 
    if (*config->process_group &&
5271
 
        config->reload_mechanism == WSGI_RELOAD_PROCESS) {
5272
 
 
 
6445
    if (*config->process_group) {
5273
6446
        ap_filter_t *filters;
5274
6447
        apr_bucket_brigade *bb;
5275
6448
        apr_bucket *b;
5335
6508
            adapter = newAdapterObject(r);
5336
6509
 
5337
6510
            if (adapter) {
 
6511
                PyObject *method = NULL;
5338
6512
                PyObject *args = NULL;
5339
6513
 
5340
6514
                Py_INCREF(object);
5352
6526
                adapter->r = NULL;
5353
6527
                adapter->input->r = NULL;
5354
6528
 
5355
 
                /*
5356
 
                 * Flush any data held within error log object
5357
 
                 * and mark it as expired so that it can't be
5358
 
                 * used beyond life of the request. We hope that
5359
 
                 * this doesn't error, as it will overwrite any
5360
 
                 * error from application if it does.
5361
 
                 */
5362
 
 
5363
 
                args = PyTuple_New(0);
5364
 
                object = Log_flush(adapter->log, args);
 
6529
                /* Close the log object so data is flushed. */
 
6530
 
 
6531
                method = PyObject_GetAttrString(adapter->log, "close");
 
6532
 
 
6533
                if (!method) {
 
6534
                    PyErr_Format(PyExc_AttributeError,
 
6535
                                 "'%s' object has no attribute 'close'",
 
6536
                                 adapter->log->ob_type->tp_name);
 
6537
                }
 
6538
                else {
 
6539
                    args = PyTuple_New(0);
 
6540
                    object = PyEval_CallObject(method, args);
 
6541
                    Py_DECREF(args);
 
6542
                }
 
6543
 
5365
6544
                Py_XDECREF(object);
5366
 
                Py_DECREF(args);
5367
 
 
5368
 
                adapter->log->r = NULL;
5369
 
                adapter->log->expired = 1;
 
6545
                Py_XDECREF(method);
5370
6546
 
5371
6547
#if defined(MOD_WSGI_WITH_BUCKETS)
5372
6548
                adapter->bb = NULL;
5380
6556
            ap_log_rerror(APLOG_MARK, WSGI_LOG_ERR(0), r,
5381
6557
                          "mod_wsgi (pid=%d): Target WSGI script '%s' does "
5382
6558
                          "not contain WSGI application '%s'.",
5383
 
                          getpid(), r->filename, config->callable_object);
 
6559
                          getpid(), script, config->callable_object);
5384
6560
            Py_END_ALLOW_THREADS
5385
6561
 
5386
6562
            status = HTTP_NOT_FOUND;
5389
6565
 
5390
6566
    /* Log any details of exceptions if execution failed. */
5391
6567
 
5392
 
    if (PyErr_Occurred()) {
5393
 
        LogObject *log;
5394
 
        log = newLogObject(r, APLOG_ERR);
5395
 
        wsgi_log_python_error(r, log, r->filename);
5396
 
        Py_DECREF(log);
5397
 
    }
 
6568
    if (PyErr_Occurred())
 
6569
        wsgi_log_python_error(r, NULL, r->filename);
5398
6570
 
5399
6571
    /* Cleanup and release interpreter, */
5400
6572
 
5442
6614
     * destroying interpreters we own.
5443
6615
     */
5444
6616
 
 
6617
    ap_log_error(APLOG_MARK, WSGI_LOG_INFO(0), wsgi_server,
 
6618
                 "mod_wsgi (pid=%d): Destroying interpreters.", getpid());
 
6619
 
5445
6620
    PyDict_Clear(wsgi_interpreters);
5446
6621
 
5447
6622
#if APR_HAS_THREADS
5479
6654
 
5480
6655
static void wsgi_python_child_init(apr_pool_t *p)
5481
6656
{
 
6657
    PyGILState_STATE state;
5482
6658
    PyInterpreterState *interp = NULL;
5483
 
    PyThreadState *tstate = NULL;
5484
 
    PyThreadState *save_tstate = NULL;
5485
 
 
5486
6659
    PyObject *object = NULL;
5487
6660
 
 
6661
    int thread_id = 0;
 
6662
    int *thread_handle = NULL;
 
6663
 
5488
6664
    /* Working with Python, so must acquire GIL. */
5489
6665
 
5490
 
    PyEval_AcquireLock();
5491
 
 
5492
 
    /*
5493
 
     * Get a reference to the main Python interpreter created
5494
 
     * and associate our own thread state against it.
5495
 
     */
5496
 
 
5497
 
    interp = PyInterpreterState_Head();
5498
 
    while (interp->next)
5499
 
        interp = interp->next;
5500
 
 
5501
 
    tstate = PyThreadState_New(interp);
5502
 
    save_tstate = PyThreadState_Swap(tstate);
 
6666
    state = PyGILState_Ensure();
5503
6667
 
5504
6668
    /*
5505
6669
     * Trigger any special Python stuff required after a fork.
5506
6670
     * Only do this though if we were responsible for the
5507
6671
     * initialisation of the Python interpreter in the first
5508
 
     * place to avoid it being done multiple times.
 
6672
     * place to avoid it being done multiple times. Also only
 
6673
     * do it if Python was initialised in parent process.
5509
6674
     */
5510
6675
 
5511
 
    if (wsgi_python_initialized)
 
6676
    if (wsgi_python_initialized && !wsgi_python_after_fork)
5512
6677
        PyOS_AfterFork();
5513
6678
 
5514
6679
    /* Finalise any Python objects required by child process. */
5535
6700
#endif
5536
6701
 
5537
6702
    /*
 
6703
     * Initialise the key for data related to a thread. At
 
6704
     * the moment we only record an integer thread ID to be
 
6705
     * used in lookup table to thread states associated with
 
6706
     * an interprter.
 
6707
     */
 
6708
 
 
6709
#if APR_HAS_THREADS
 
6710
    apr_threadkey_private_create(&wsgi_thread_key, NULL, p);
 
6711
 
 
6712
    thread_id = wsgi_thread_count++;
 
6713
    thread_handle = (int*)apr_pmemdup(wsgi_server->process->pool,
 
6714
                                      &thread_id, sizeof(thread_id));
 
6715
    apr_threadkey_private_set(thread_handle, wsgi_thread_key);
 
6716
#endif
 
6717
 
 
6718
    /*
5538
6719
     * Cache a reference to the first Python interpreter
5539
6720
     * instance. This interpreter is special as some third party
5540
6721
     * Python modules will only work when used from within this
5541
6722
     * interpreter. This is generally when they use the Python
5542
6723
     * simplified GIL API or otherwise don't use threading API
5543
 
     * properly.
 
6724
     * properly. An empty string for name is used to identify
 
6725
     * the first Python interpreter instance.
5544
6726
     */
5545
6727
 
5546
 
    object = (PyObject *)newInterpreterObject("", interp);
 
6728
    object = (PyObject *)newInterpreterObject(NULL);
5547
6729
    PyDict_SetItemString(wsgi_interpreters, "", object);
5548
6730
    Py_DECREF(object);
5549
6731
 
5550
6732
    /* Restore the prior thread state and release the GIL. */
5551
6733
 
5552
 
    PyThreadState_Clear(tstate);
5553
 
    PyThreadState_Swap(save_tstate);
5554
 
    PyThreadState_Delete(tstate);
5555
 
 
5556
 
    PyEval_ReleaseLock();
 
6734
    PyGILState_Release(state);
5557
6735
 
5558
6736
    /* Register cleanups to performed on process shutdown. */
5559
6737
 
5567
6745
 
5568
6746
    /* Loop through import scripts for this process and load them. */
5569
6747
 
5570
 
    if (wsgi_server_config->import_list) {
 
6748
    if (wsgi_import_list) {
5571
6749
        apr_array_header_t *scripts = NULL;
5572
6750
 
5573
6751
        WSGIScriptFile *entries;
5575
6753
 
5576
6754
        int i;
5577
6755
 
5578
 
        scripts = wsgi_server_config->import_list;
 
6756
        scripts = wsgi_import_list;
5579
6757
        entries = (WSGIScriptFile *)scripts->elts;
5580
6758
 
5581
6759
        for (i = 0; i < scripts->nelts; ++i) {
5631
6809
 
5632
6810
                if (module && wsgi_server_config->script_reloading) {
5633
6811
                    if (wsgi_reload_required(p, NULL, entry->handler_script,
5634
 
                                             module)) {
 
6812
                                             module, NULL)) {
5635
6813
                        /*
5636
6814
                         * Script file has changed. Only support module
5637
6815
                         * reloading for dispatch scripts. Remove the
5677
6855
 
5678
6856
/* The processors for directives. */
5679
6857
 
 
6858
static int wsgi_parse_option(apr_pool_t *p, const char **line,
 
6859
                             const char **name, const char **value)
 
6860
{
 
6861
    const char *str = *line, *strend;
 
6862
 
 
6863
    while (*str && apr_isspace(*str))
 
6864
        ++str;
 
6865
 
 
6866
    if (!*str || *str == '=') {
 
6867
        *line = str;
 
6868
        return !APR_SUCCESS;
 
6869
    }
 
6870
 
 
6871
    /* Option must be of form name=value. Extract the name. */
 
6872
 
 
6873
    strend = str;
 
6874
    while (*strend && *strend != '=' && !apr_isspace(*strend))
 
6875
        ++strend;
 
6876
 
 
6877
    if (*strend != '=') {
 
6878
        *line = str;
 
6879
        return !APR_SUCCESS;
 
6880
    }
 
6881
 
 
6882
    *name = apr_pstrndup(p, str, strend-str);
 
6883
 
 
6884
    *line = strend+1;
 
6885
 
 
6886
    /* Now extract the value. Note that value can be quoted. */
 
6887
 
 
6888
    *value = ap_getword_conf(p, line);
 
6889
 
 
6890
    return APR_SUCCESS;
 
6891
}
 
6892
 
5680
6893
static const char *wsgi_add_script_alias(cmd_parms *cmd, void *mconfig,
5681
 
                                         const char *l, const char *a)
 
6894
                                         const char *args)
5682
6895
{
5683
 
    WSGIServerConfig *config = NULL;
 
6896
    const char *l = NULL;
 
6897
    const char *a = NULL;
 
6898
 
 
6899
    WSGIServerConfig *sconfig = NULL;
5684
6900
    WSGIAliasEntry *entry = NULL;
5685
6901
 
5686
 
    config = ap_get_module_config(cmd->server->module_config, &wsgi_module);
5687
 
 
5688
 
    if (!config->alias_list) {
5689
 
        config->alias_list = apr_array_make(config->pool, 20,
 
6902
    const char *option = NULL;
 
6903
    const char *value = NULL;
 
6904
 
 
6905
#if defined(MOD_WSGI_WITH_DAEMONS)
 
6906
    const char *process_group = NULL;
 
6907
#else
 
6908
    const char *process_group = "";
 
6909
#endif
 
6910
 
 
6911
    const char *application_group = NULL;
 
6912
    const char *callable_object = NULL;
 
6913
 
 
6914
    int pass_authorization = -1;
 
6915
 
 
6916
    sconfig = ap_get_module_config(cmd->server->module_config, &wsgi_module);
 
6917
 
 
6918
    if (!sconfig->alias_list) {
 
6919
        sconfig->alias_list = apr_array_make(sconfig->pool, 20,
5690
6920
                                            sizeof(WSGIAliasEntry));
5691
6921
    }
5692
6922
 
5693
 
    entry = (WSGIAliasEntry *)apr_array_push(config->alias_list);
 
6923
    l = ap_getword_conf(cmd->pool, &args);
 
6924
 
 
6925
    if (*l == '\0' || *args == 0) {
 
6926
        return apr_pstrcat(cmd->pool, cmd->cmd->name,
 
6927
                           " requires at least two arguments",
 
6928
                           cmd->cmd->errmsg ? ", " : NULL,
 
6929
                           cmd->cmd->errmsg, NULL);
 
6930
    }
 
6931
 
 
6932
    a = ap_getword_conf(cmd->pool, &args);
 
6933
 
 
6934
    if (*a == '\0') {
 
6935
        return apr_pstrcat(cmd->pool, cmd->cmd->name,
 
6936
                           " requires at least two arguments",
 
6937
                           cmd->cmd->errmsg ? ", " : NULL,
 
6938
                           cmd->cmd->errmsg, NULL);
 
6939
    }
 
6940
 
 
6941
    while (*args) {
 
6942
        if (wsgi_parse_option(cmd->pool, &args, &option,
 
6943
                              &value) != APR_SUCCESS) {
 
6944
            return "Invalid option to WSGI script alias definition.";
 
6945
        }
 
6946
 
 
6947
        if (!cmd->info && !strcmp(option, "application-group")) {
 
6948
            if (!*value)
 
6949
                return "Invalid name for WSGI application group.";
 
6950
 
 
6951
            if (!strcmp(value, "%{GLOBAL}"))
 
6952
                value = "";
 
6953
 
 
6954
            application_group = value;
 
6955
        }
 
6956
#if defined(MOD_WSGI_WITH_DAEMONS)
 
6957
        else if (!cmd->info && !strcmp(option, "process-group")) {
 
6958
            if (!*value)
 
6959
                return "Invalid name for WSGI process group.";
 
6960
 
 
6961
            if (!strcmp(value, "%{GLOBAL}"))
 
6962
                value = "";
 
6963
 
 
6964
            process_group = value;
 
6965
        }
 
6966
#endif
 
6967
        else if (!strcmp(option, "callable-object")) {
 
6968
            if (!*value)
 
6969
                return "Invalid name for WSGI callable object.";
 
6970
 
 
6971
            callable_object = value;
 
6972
        }
 
6973
        else if (!strcmp(option, "pass-authorization")) {
 
6974
            if (!*value)
 
6975
                return "Invalid value for authorization flag.";
 
6976
 
 
6977
            if (strcasecmp(value, "Off") == 0)
 
6978
                pass_authorization = 0;
 
6979
            else if (strcasecmp(value, "On") == 0)
 
6980
                pass_authorization = 1;
 
6981
            else
 
6982
                return "Invalid value for authorization flag.";
 
6983
        }
 
6984
        else
 
6985
            return "Invalid option to WSGI script alias definition.";
 
6986
    }
 
6987
 
 
6988
    entry = (WSGIAliasEntry *)apr_array_push(sconfig->alias_list);
5694
6989
 
5695
6990
    if (cmd->info) {
5696
6991
        entry->regexp = ap_pregcomp(cmd->pool, l, AP_REG_EXTENDED);
5701
6996
    entry->location = l;
5702
6997
    entry->application = a;
5703
6998
 
 
6999
    entry->process_group = process_group;
 
7000
    entry->application_group = application_group;
 
7001
    entry->callable_object = callable_object;
 
7002
    entry->pass_authorization = pass_authorization;
 
7003
 
 
7004
    if (process_group && application_group &&
 
7005
        !strstr(process_group, "%{") &&
 
7006
        !strstr(application_group, "%{")) {
 
7007
 
 
7008
        WSGIScriptFile *object = NULL;
 
7009
 
 
7010
        if (!wsgi_import_list) {
 
7011
            wsgi_import_list = apr_array_make(sconfig->pool, 20,
 
7012
                                              sizeof(WSGIScriptFile));
 
7013
        }
 
7014
 
 
7015
        object = (WSGIScriptFile *)apr_array_push(wsgi_import_list);
 
7016
 
 
7017
        object->handler_script = a;
 
7018
        object->process_group = process_group;
 
7019
        object->application_group = application_group;
 
7020
 
 
7021
#if defined(MOD_WSGI_WITH_DAEMONS)
 
7022
        if (*object->process_group) {
 
7023
            WSGIProcessGroup *group = NULL;
 
7024
            WSGIProcessGroup *entries = NULL;
 
7025
            WSGIProcessGroup *entry = NULL;
 
7026
            int i;
 
7027
 
 
7028
            if (!wsgi_daemon_list)
 
7029
                return "WSGI process group not yet configured.";
 
7030
 
 
7031
            entries = (WSGIProcessGroup *)wsgi_daemon_list->elts;
 
7032
 
 
7033
            for (i = 0; i < wsgi_daemon_list->nelts; ++i) {
 
7034
                entry = &entries[i];
 
7035
 
 
7036
                if (!strcmp(entry->name, object->process_group)) {
 
7037
                    group = entry;
 
7038
                    break;
 
7039
                }
 
7040
            }
 
7041
 
 
7042
            if (!group)
 
7043
                return "WSGI process group not yet configured.";
 
7044
 
 
7045
            if (group->server != cmd->server && group->server->is_virtual)
 
7046
                return "WSGI process group not accessible.";
 
7047
        }
 
7048
#endif
 
7049
    }
 
7050
 
 
7051
    return NULL;
 
7052
}
 
7053
 
 
7054
static const char *wsgi_set_verbose_debugging(cmd_parms *cmd, void *mconfig,
 
7055
                                              const char *f)
 
7056
{
 
7057
    const char *error = NULL;
 
7058
    WSGIServerConfig *sconfig = NULL;
 
7059
 
 
7060
    error = ap_check_cmd_context(cmd, GLOBAL_ONLY);
 
7061
    if (error != NULL)
 
7062
        return error;
 
7063
 
 
7064
    sconfig = ap_get_module_config(cmd->server->module_config, &wsgi_module);
 
7065
 
 
7066
    if (strcasecmp(f, "Off") == 0)
 
7067
        sconfig->verbose_debugging = 0;
 
7068
    else if (strcasecmp(f, "On") == 0)
 
7069
        sconfig->verbose_debugging = 1;
 
7070
    else
 
7071
        return "WSGIVerboseDebugging must be one of: Off | On";
 
7072
 
 
7073
    return NULL;
 
7074
}
 
7075
 
 
7076
static const char *wsgi_set_lazy_initialization(cmd_parms *cmd, void *mconfig,
 
7077
                                                const char *f)
 
7078
{
 
7079
    const char *error = NULL;
 
7080
 
 
7081
    error = ap_check_cmd_context(cmd, GLOBAL_ONLY);
 
7082
    if (error != NULL)
 
7083
        return error;
 
7084
 
 
7085
    if (strcasecmp(f, "Off") == 0)
 
7086
        wsgi_python_after_fork = 0;
 
7087
    else if (strcasecmp(f, "On") == 0)
 
7088
        wsgi_python_after_fork = 1;
 
7089
    else
 
7090
        return "WSGILazyInitialization must be one of: Off | On";
 
7091
 
 
7092
    return NULL;
 
7093
}
 
7094
 
 
7095
static const char *wsgi_add_python_warnings(cmd_parms *cmd, void *mconfig,
 
7096
                                            const char *f)
 
7097
{
 
7098
    const char *error = NULL;
 
7099
    WSGIServerConfig *sconfig = NULL;
 
7100
 
 
7101
    char **entry = NULL;
 
7102
 
 
7103
    error = ap_check_cmd_context(cmd, GLOBAL_ONLY);
 
7104
    if (error != NULL)
 
7105
        return error;
 
7106
 
 
7107
    sconfig = ap_get_module_config(cmd->server->module_config, &wsgi_module);
 
7108
 
 
7109
    if (!sconfig->python_warnings) {
 
7110
        sconfig->python_warnings = apr_array_make(sconfig->pool, 5,
 
7111
                                                  sizeof(char*));
 
7112
    }
 
7113
 
 
7114
    entry = (char **)apr_array_push(sconfig->python_warnings);
 
7115
    *entry = apr_pstrdup(sconfig->pool, f);
 
7116
 
 
7117
    return NULL;
 
7118
}
 
7119
 
 
7120
static const char *wsgi_set_py3k_warning_flag(cmd_parms *cmd, void *mconfig,
 
7121
                                              const char *f)
 
7122
{
 
7123
    const char *error = NULL;
 
7124
    WSGIServerConfig *sconfig = NULL;
 
7125
 
 
7126
    error = ap_check_cmd_context(cmd, GLOBAL_ONLY);
 
7127
    if (error != NULL)
 
7128
        return error;
 
7129
 
 
7130
    sconfig = ap_get_module_config(cmd->server->module_config, &wsgi_module);
 
7131
 
 
7132
    if (strcasecmp(f, "Off") == 0)
 
7133
        sconfig->py3k_warning_flag = 0;
 
7134
    else if (strcasecmp(f, "On") == 0)
 
7135
        sconfig->py3k_warning_flag = 1;
 
7136
    else
 
7137
        return "WSGIPy3kWarningFlag must be one of: Off | On";
 
7138
 
5704
7139
    return NULL;
5705
7140
}
5706
7141
 
5787
7222
    else
5788
7223
        return "WSGIRestrictEmbedded must be one of: Off | On";
5789
7224
 
 
7225
    if (sconfig->restrict_embedded) {
 
7226
        if (wsgi_python_required == -1)
 
7227
            wsgi_python_required = 0;
 
7228
    }
 
7229
 
5790
7230
    return NULL;
5791
7231
}
5792
7232
 
5898
7338
    }
5899
7339
 
5900
7340
    while (*args) {
5901
 
        char const *option;
 
7341
        const char *option;
5902
7342
 
5903
7343
        option = ap_getword_conf(cmd->pool, &args);
5904
7344
 
5970
7410
{
5971
7411
    const char *error = NULL;
5972
7412
    WSGIScriptFile *object = NULL;
5973
 
    WSGIServerConfig *sconfig = NULL;
5974
7413
 
5975
7414
    const char *option = NULL;
5976
7415
    const char *value = NULL;
5977
7416
 
5978
 
    error = ap_check_cmd_context(cmd, GLOBAL_ONLY);
5979
 
    if (error != NULL)
5980
 
        return error;
5981
 
 
5982
 
    sconfig = ap_get_module_config(cmd->server->module_config,
5983
 
                                   &wsgi_module);
5984
 
 
5985
 
    if (!sconfig->import_list) {
5986
 
        sconfig->import_list = apr_array_make(sconfig->pool, 20,
5987
 
                                              sizeof(WSGIScriptFile));
 
7417
    if (!wsgi_import_list) {
 
7418
        wsgi_import_list = apr_array_make(cmd->pool, 20,
 
7419
                                          sizeof(WSGIScriptFile));
5988
7420
    }
5989
7421
 
5990
 
    object = (WSGIScriptFile *)apr_array_push(sconfig->import_list);
 
7422
    object = (WSGIScriptFile *)apr_array_push(wsgi_import_list);
5991
7423
 
5992
7424
    object->handler_script = ap_getword_conf(cmd->pool, &args);
5993
7425
    object->process_group = NULL;
5997
7429
        return "Location of import script not supplied.";
5998
7430
 
5999
7431
    while (*args) {
6000
 
        option = ap_getword_conf(cmd->pool, &args);
 
7432
        if (wsgi_parse_option(cmd->pool, &args, &option,
 
7433
                              &value) != APR_SUCCESS) {
 
7434
            return "Invalid option to WSGI import script definition.";
 
7435
        }
6001
7436
 
6002
 
        if (strstr(option, "application-group=") == option) {
6003
 
            value = option + 18;
 
7437
        if (!strcmp(option, "application-group")) {
6004
7438
            if (!*value)
6005
7439
                return "Invalid name for WSGI application group.";
6006
7440
 
6007
7441
            object->application_group = value;
6008
7442
        }
6009
7443
#if defined(MOD_WSGI_WITH_DAEMONS)
6010
 
        else if (strstr(option, "process-group=") == option) {
6011
 
            value = option + 14;
 
7444
        else if (!strcmp(option, "process-group")) {
6012
7445
            if (!*value)
6013
7446
                return "Invalid name for WSGI process group.";
6014
7447
 
6031
7464
 
6032
7465
    if (!strcmp(object->process_group, "%{GLOBAL}"))
6033
7466
        object->process_group = "";
 
7467
 
 
7468
    if (*object->process_group) {
 
7469
        WSGIProcessGroup *group = NULL;
 
7470
        WSGIProcessGroup *entries = NULL;
 
7471
        WSGIProcessGroup *entry = NULL;
 
7472
        int i;
 
7473
 
 
7474
        if (!wsgi_daemon_list)
 
7475
            return "WSGI process group not yet configured.";
 
7476
 
 
7477
        entries = (WSGIProcessGroup *)wsgi_daemon_list->elts;
 
7478
 
 
7479
        for (i = 0; i < wsgi_daemon_list->nelts; ++i) {
 
7480
            entry = &entries[i];
 
7481
 
 
7482
            if (!strcmp(entry->name, object->process_group)) {
 
7483
                group = entry;
 
7484
                break;
 
7485
            }
 
7486
        }
 
7487
 
 
7488
        if (!group)
 
7489
            return "WSGI process group not yet configured.";
 
7490
 
 
7491
        if (group->server != cmd->server && group->server->is_virtual)
 
7492
            return "WSGI process group not accessible.";
 
7493
    }
6034
7494
#else
6035
7495
    object->process_group = "";
6036
7496
#endif
6037
7497
 
 
7498
    if (!*object->process_group)
 
7499
        wsgi_python_required = 1;
 
7500
 
6038
7501
    return NULL;
6039
7502
}
6040
7503
 
6054
7517
        return "Location of dispatch script not supplied.";
6055
7518
 
6056
7519
    while (*args) {
6057
 
        option = ap_getword_conf(cmd->pool, &args);
 
7520
        if (wsgi_parse_option(cmd->pool, &args, &option,
 
7521
                              &value) != APR_SUCCESS) {
 
7522
            return "Invalid option to WSGI dispatch script definition.";
 
7523
        }
6058
7524
 
6059
 
        if (strstr(option, "application-group=") == option) {
6060
 
            value = option + 18;
 
7525
        if (!strcmp(option, "application-group")) {
6061
7526
            if (!*value)
6062
7527
                return "Invalid name for WSGI application group.";
6063
7528
 
6079
7544
        sconfig->dispatch_script = object;
6080
7545
    }
6081
7546
 
 
7547
    wsgi_python_required = 1;
 
7548
 
6082
7549
    return NULL;
6083
7550
}
6084
7551
 
6085
 
static const char *wsgi_set_apache_extensions(cmd_parms *cmd, void *mconfig,
6086
 
                                              const char *f)
 
7552
static const char *wsgi_set_pass_apache_request(cmd_parms *cmd, void *mconfig,
 
7553
                                                const char *f)
6087
7554
{
6088
7555
    if (cmd->path) {
6089
7556
        WSGIDirectoryConfig *dconfig = NULL;
6090
7557
        dconfig = (WSGIDirectoryConfig *)mconfig;
6091
7558
 
6092
7559
        if (strcasecmp(f, "Off") == 0)
6093
 
            dconfig->apache_extensions = 0;
 
7560
            dconfig->pass_apache_request = 0;
6094
7561
        else if (strcasecmp(f, "On") == 0)
6095
 
            dconfig->apache_extensions = 1;
 
7562
            dconfig->pass_apache_request = 1;
6096
7563
        else
6097
 
            return "WSGIApacheExtensions must be one of: Off | On";
 
7564
            return "WSGIPassApacheRequest must be one of: Off | On";
6098
7565
    }
6099
7566
    else {
6100
7567
        WSGIServerConfig *sconfig = NULL;
6102
7569
                                       &wsgi_module);
6103
7570
 
6104
7571
        if (strcasecmp(f, "Off") == 0)
6105
 
            sconfig->apache_extensions = 0;
 
7572
            sconfig->pass_apache_request = 0;
6106
7573
        else if (strcasecmp(f, "On") == 0)
6107
 
            sconfig->apache_extensions = 1;
 
7574
            sconfig->pass_apache_request = 1;
6108
7575
        else
6109
 
            return "WSGIApacheExtensions must be one of: Off | On";
 
7576
            return "WSGIPassApacheRequest must be one of: Off | On";
6110
7577
    }
6111
7578
 
6112
7579
    return NULL;
6172
7639
    return NULL;
6173
7640
}
6174
7641
 
6175
 
static const char *wsgi_set_reload_mechanism(cmd_parms *cmd, void *mconfig,
6176
 
                                             const char *f)
6177
 
{
6178
 
    if (cmd->path) {
6179
 
        WSGIDirectoryConfig *dconfig = NULL;
6180
 
        dconfig = (WSGIDirectoryConfig *)mconfig;
6181
 
 
6182
 
        if (strcasecmp(f, "Module") == 0)
6183
 
            dconfig->reload_mechanism = WSGI_RELOAD_MODULE;
6184
 
        else if (strcasecmp(f, "Process") == 0)
6185
 
            dconfig->reload_mechanism = WSGI_RELOAD_PROCESS;
6186
 
        else {
6187
 
            return "WSGIReloadMechanism must be one of: "
6188
 
                   "Module | Process";
6189
 
        }
6190
 
    }
6191
 
    else {
6192
 
        WSGIServerConfig *sconfig = NULL;
6193
 
        sconfig = ap_get_module_config(cmd->server->module_config,
6194
 
                                       &wsgi_module);
6195
 
 
6196
 
        if (strcasecmp(f, "Module") == 0)
6197
 
            sconfig->reload_mechanism = WSGI_RELOAD_MODULE;
6198
 
        else if (strcasecmp(f, "Process") == 0)
6199
 
            sconfig->reload_mechanism = WSGI_RELOAD_PROCESS;
6200
 
        else {
6201
 
            return "WSGIReloadMechanism must be one of: "
6202
 
                   "Module | Process";
6203
 
        }
 
7642
static const char *wsgi_set_error_override(cmd_parms *cmd, void *mconfig,
 
7643
                                           const char *f)
 
7644
{
 
7645
    if (cmd->path) {
 
7646
        WSGIDirectoryConfig *dconfig = NULL;
 
7647
        dconfig = (WSGIDirectoryConfig *)mconfig;
 
7648
 
 
7649
        if (strcasecmp(f, "Off") == 0)
 
7650
            dconfig->error_override = 0;
 
7651
        else if (strcasecmp(f, "On") == 0)
 
7652
            dconfig->error_override = 1;
 
7653
        else
 
7654
            return "WSGIErrorOverride must be one of: Off | On";
 
7655
    }
 
7656
    else {
 
7657
        WSGIServerConfig *sconfig = NULL;
 
7658
        sconfig = ap_get_module_config(cmd->server->module_config,
 
7659
                                       &wsgi_module);
 
7660
 
 
7661
        if (strcasecmp(f, "Off") == 0)
 
7662
            sconfig->error_override = 0;
 
7663
        else if (strcasecmp(f, "On") == 0)
 
7664
            sconfig->error_override = 1;
 
7665
        else
 
7666
            return "WSGIErrorOverride must be one of: Off | On";
 
7667
    }
 
7668
 
 
7669
    return NULL;
 
7670
}
 
7671
 
 
7672
static const char *wsgi_set_chunked_request(cmd_parms *cmd, void *mconfig,
 
7673
                                            const char *f)
 
7674
{
 
7675
    if (cmd->path) {
 
7676
        WSGIDirectoryConfig *dconfig = NULL;
 
7677
        dconfig = (WSGIDirectoryConfig *)mconfig;
 
7678
 
 
7679
        if (strcasecmp(f, "Off") == 0)
 
7680
            dconfig->chunked_request = 0;
 
7681
        else if (strcasecmp(f, "On") == 0)
 
7682
            dconfig->chunked_request = 1;
 
7683
        else
 
7684
            return "WSGIChunkedRequest must be one of: Off | On";
 
7685
    }
 
7686
    else {
 
7687
        WSGIServerConfig *sconfig = NULL;
 
7688
        sconfig = ap_get_module_config(cmd->server->module_config,
 
7689
                                       &wsgi_module);
 
7690
 
 
7691
        if (strcasecmp(f, "Off") == 0)
 
7692
            sconfig->chunked_request = 0;
 
7693
        else if (strcasecmp(f, "On") == 0)
 
7694
            sconfig->chunked_request = 1;
 
7695
        else
 
7696
            return "WSGIChunkedRequest must be one of: Off | On";
6204
7697
    }
6205
7698
 
6206
7699
    return NULL;
6223
7716
        return "Location of access script not supplied.";
6224
7717
 
6225
7718
    while (*args) {
6226
 
        option = ap_getword_conf(cmd->pool, &args);
 
7719
        if (wsgi_parse_option(cmd->pool, &args, &option,
 
7720
                              &value) != APR_SUCCESS) {
 
7721
            return "Invalid option to WSGI access script definition.";
 
7722
        }
6227
7723
 
6228
 
        if (strstr(option, "application-group=") == option) {
6229
 
            value = option + 18;
 
7724
        if (!strcmp(option, "application-group")) {
6230
7725
            if (!*value)
6231
7726
                return "Invalid name for WSGI application group.";
6232
7727
 
6239
7734
    dconfig = (WSGIDirectoryConfig *)mconfig;
6240
7735
    dconfig->access_script = object;
6241
7736
 
 
7737
    wsgi_python_required = 1;
 
7738
 
6242
7739
    return NULL;
6243
7740
}
6244
7741
 
6259
7756
        return "Location of auth user script not supplied.";
6260
7757
 
6261
7758
    while (*args) {
6262
 
        option = ap_getword_conf(cmd->pool, &args);
 
7759
        if (wsgi_parse_option(cmd->pool, &args, &option,
 
7760
                              &value) != APR_SUCCESS) {
 
7761
            return "Invalid option to WSGI auth user script definition.";
 
7762
        }
6263
7763
 
6264
 
        if (strstr(option, "application-group=") == option) {
6265
 
            value = option + 18;
 
7764
        if (!strcmp(option, "application-group")) {
6266
7765
            if (!*value)
6267
7766
                return "Invalid name for WSGI application group.";
6268
7767
 
6275
7774
    dconfig = (WSGIDirectoryConfig *)mconfig;
6276
7775
    dconfig->auth_user_script = object;
6277
7776
 
 
7777
    wsgi_python_required = 1;
 
7778
 
6278
7779
    return NULL;
6279
7780
}
6280
7781
 
6295
7796
        return "Location of auth group script not supplied.";
6296
7797
 
6297
7798
    while (*args) {
6298
 
        option = ap_getword_conf(cmd->pool, &args);
 
7799
        if (wsgi_parse_option(cmd->pool, &args, &option,
 
7800
                              &value) != APR_SUCCESS) {
 
7801
            return "Invalid option to WSGI auth group script definition.";
 
7802
        }
6299
7803
 
6300
 
        if (strstr(option, "application-group=") == option) {
6301
 
            value = option + 18;
 
7804
        if (!strcmp(option, "application-group")) {
6302
7805
            if (!*value)
6303
7806
                return "Invalid name for WSGI application group.";
6304
7807
 
6311
7814
    dconfig = (WSGIDirectoryConfig *)mconfig;
6312
7815
    dconfig->auth_group_script = object;
6313
7816
 
 
7817
    wsgi_python_required = 1;
 
7818
 
6314
7819
    return NULL;
6315
7820
}
6316
7821
 
6346
7851
    return NULL;
6347
7852
}
6348
7853
 
 
7854
#if AP_SERVER_MAJORVERSION_NUMBER >= 2
 
7855
static const char *wsgi_add_handler_script(cmd_parms *cmd, void *mconfig,
 
7856
                                           const char *args)
 
7857
{
 
7858
    WSGIServerConfig *sconfig = NULL;
 
7859
    WSGIDirectoryConfig *dconfig = NULL;
 
7860
    WSGIScriptFile *object = NULL;
 
7861
 
 
7862
    const char *name = NULL;
 
7863
    const char *option = NULL;
 
7864
    const char *value = NULL;
 
7865
 
 
7866
    name = ap_getword_conf(cmd->pool, &args);
 
7867
 
 
7868
    if (!name || !*name)
 
7869
        return "Name for handler script not supplied.";
 
7870
 
 
7871
    object = newWSGIScriptFile(cmd->pool);
 
7872
 
 
7873
    object->handler_script = ap_getword_conf(cmd->pool, &args);
 
7874
 
 
7875
    if (!object->handler_script || !*object->handler_script)
 
7876
        return "Location of handler script not supplied.";
 
7877
 
 
7878
    while (*args) {
 
7879
        if (wsgi_parse_option(cmd->pool, &args, &option,
 
7880
                              &value) != APR_SUCCESS) {
 
7881
            return "Invalid option to WSGI handler script definition.";
 
7882
        }
 
7883
 
 
7884
        if (!strcmp(option, "process-group")) {
 
7885
            if (!*value)
 
7886
                return "Invalid name for WSGI process group.";
 
7887
 
 
7888
            object->process_group = value;
 
7889
        }
 
7890
        else if (!strcmp(option, "application-group")) {
 
7891
            if (!*value)
 
7892
                return "Invalid name for WSGI application group.";
 
7893
 
 
7894
            object->application_group = value;
 
7895
        }
 
7896
        else if (!strcmp(option, "pass-authorization")) {
 
7897
            if (!*value)
 
7898
                return "Invalid value for authorization flag.";
 
7899
 
 
7900
            if (strcasecmp(value, "Off") == 0)
 
7901
                object->pass_authorization = "0";
 
7902
            else if (strcasecmp(value, "On") == 0)
 
7903
                object->pass_authorization = "1";
 
7904
            else
 
7905
                return "Invalid value for authorization flag.";
 
7906
        }
 
7907
        else
 
7908
            return "Invalid option to WSGI handler script definition.";
 
7909
    }
 
7910
 
 
7911
    if (cmd->path) {
 
7912
        WSGIDirectoryConfig *dconfig = NULL;
 
7913
        dconfig = (WSGIDirectoryConfig *)mconfig;
 
7914
 
 
7915
        if (!dconfig->handler_scripts)
 
7916
            dconfig->handler_scripts = apr_hash_make(cmd->pool);
 
7917
 
 
7918
        apr_hash_set(dconfig->handler_scripts, name, APR_HASH_KEY_STRING,
 
7919
                     object);
 
7920
    }
 
7921
    else {
 
7922
        WSGIServerConfig *sconfig = NULL;
 
7923
        sconfig = ap_get_module_config(cmd->server->module_config,
 
7924
                                       &wsgi_module);
 
7925
 
 
7926
        if (!sconfig->handler_scripts)
 
7927
            sconfig->handler_scripts = apr_hash_make(cmd->pool);
 
7928
 
 
7929
        apr_hash_set(sconfig->handler_scripts, name, APR_HASH_KEY_STRING,
 
7930
                     object);
 
7931
    }
 
7932
 
 
7933
    return NULL;
 
7934
}
 
7935
#endif
 
7936
 
6349
7937
/* Handler for the translate name phase. */
6350
7938
 
6351
7939
static int wsgi_alias_matches(const char *uri, const char *alias_fakename)
6454
8042
            r->handler = "wsgi-script";
6455
8043
            apr_table_setn(r->notes, "alias-forced-type", r->handler);
6456
8044
 
 
8045
            if (entry->process_group) {
 
8046
                apr_table_setn(r->notes, "mod_wsgi.process_group",
 
8047
                               entry->process_group);
 
8048
            }
 
8049
            if (entry->application_group) {
 
8050
                apr_table_setn(r->notes, "mod_wsgi.application_group",
 
8051
                               entry->application_group);
 
8052
            }
 
8053
            if (entry->callable_object) {
 
8054
                apr_table_setn(r->notes, "mod_wsgi.callable_object",
 
8055
                               entry->callable_object);
 
8056
            }
 
8057
 
 
8058
            if (entry->pass_authorization == 0)
 
8059
                apr_table_setn(r->notes, "mod_wsgi.pass_authorization", "0");
 
8060
            else if (entry->pass_authorization == 1)
 
8061
                apr_table_setn(r->notes, "mod_wsgi.pass_authorization", "1");
 
8062
 
6457
8063
            return OK;
6458
8064
        }
6459
8065
    }
6602
8208
    apr_table_setn(r->subprocess_env, "mod_wsgi.callable_object",
6603
8209
                   config->callable_object);
6604
8210
 
 
8211
    apr_table_setn(r->subprocess_env, "mod_wsgi.request_handler", r->handler);
 
8212
    apr_table_setn(r->subprocess_env, "mod_wsgi.handler_script",
 
8213
                   config->handler_script);
 
8214
 
6605
8215
    apr_table_setn(r->subprocess_env, "mod_wsgi.script_reloading",
6606
8216
                   apr_psprintf(r->pool, "%d", config->script_reloading));
6607
 
    apr_table_setn(r->subprocess_env, "mod_wsgi.reload_mechanism",
6608
 
                   apr_psprintf(r->pool, "%d", config->reload_mechanism));
6609
8217
 
6610
8218
#if defined(MOD_WSGI_WITH_DAEMONS)
6611
8219
    apr_table_setn(r->subprocess_env, "mod_wsgi.listener_host",
6613
8221
    apr_table_setn(r->subprocess_env, "mod_wsgi.listener_port",
6614
8222
                   apr_psprintf(r->pool, "%d", c->local_addr->port));
6615
8223
#endif
 
8224
 
 
8225
    apr_table_setn(r->subprocess_env, "mod_wsgi.input_chunked",
 
8226
                   apr_psprintf(r->pool, "%d", !!r->read_chunked));
6616
8227
}
6617
8228
 
6618
8229
typedef struct {
6619
8230
        PyObject_HEAD
6620
8231
        request_rec *r;
6621
8232
        WSGIRequestConfig *config;
6622
 
        LogObject *log;
 
8233
        PyObject *log;
6623
8234
} DispatchObject;
6624
8235
 
6625
8236
static DispatchObject *newDispatchObject(request_rec *r,
6635
8246
 
6636
8247
    self->r = r;
6637
8248
 
6638
 
    self->log = newLogObject(r, APLOG_ERR);
 
8249
    self->log = newLogObject(r, APLOG_ERR, NULL);
6639
8250
 
6640
8251
    return self;
6641
8252
}
6673
8284
    for (i = 0; i < head->nelts; ++i) {
6674
8285
        if (elts[i].key) {
6675
8286
            if (elts[i].val) {
 
8287
#if PY_MAJOR_VERSION >= 3
 
8288
                object = PyUnicode_DecodeLatin1(elts[i].val,
 
8289
                                                strlen(elts[i].val), NULL);
 
8290
#else
6676
8291
                object = PyString_FromString(elts[i].val);
 
8292
#endif
6677
8293
                PyDict_SetItemString(vars, elts[i].key, object);
6678
8294
                Py_DECREF(object);
6679
8295
            }
6689
8305
     * to remove callable object reference.
6690
8306
     */
6691
8307
 
 
8308
#if PY_MAJOR_VERSION >= 3
 
8309
    object = PyUnicode_FromString("");
 
8310
#else
6692
8311
    object = PyString_FromString("");
 
8312
#endif
6693
8313
    PyDict_SetItemString(vars, "mod_wsgi.process_group", object);
6694
8314
    Py_DECREF(object);
6695
8315
 
 
8316
#if PY_MAJOR_VERSION >= 3
 
8317
    object = PyUnicode_DecodeLatin1(group, strlen(group), NULL);
 
8318
#else
6696
8319
    object = PyString_FromString(group);
 
8320
#endif
6697
8321
    PyDict_SetItemString(vars, "mod_wsgi.application_group", object);
6698
8322
    Py_DECREF(object);
6699
8323
 
6712
8336
     * to the Apache request_rec structure instance.
6713
8337
     */
6714
8338
 
6715
 
    if (!wsgi_daemon_pool && self->config->apache_extensions) {
 
8339
    if (!wsgi_daemon_pool && self->config->pass_apache_request) {
6716
8340
        object = PyCObject_FromVoidPtr(self->r, 0);
6717
8341
        PyDict_SetItemString(vars, "apache.request_rec", object);
6718
8342
        Py_DECREF(object);
6722
8346
}
6723
8347
 
6724
8348
static PyTypeObject Dispatch_Type = {
6725
 
    /* The ob_type field must be initialized in the module init function
6726
 
     * to be portable to Windows without using C++. */
6727
 
    PyObject_HEAD_INIT(NULL)
6728
 
    0,                      /*ob_size*/
 
8349
    PyVarObject_HEAD_INIT(NULL, 0)
6729
8350
    "mod_wsgi.Dispatch",    /*tp_name*/
6730
8351
    sizeof(DispatchObject), /*tp_basicsize*/
6731
8352
    0,                      /*tp_itemsize*/
6846
8467
     */
6847
8468
 
6848
8469
    if (module && config->script_reloading) {
6849
 
        if (wsgi_reload_required(r->pool, r, script, module)) {
 
8470
        if (wsgi_reload_required(r->pool, r, script, module, NULL)) {
6850
8471
            /*
6851
8472
             * Script file has changed. Only support module
6852
8473
             * reloading for dispatch scripts. Remove the
6892
8513
        if (adapter) {
6893
8514
            PyObject *vars = NULL;
6894
8515
            PyObject *args = NULL;
 
8516
            PyObject *method = NULL;
6895
8517
 
6896
8518
            vars = Dispatch_environ(adapter, group);
6897
8519
 
6924
8546
                                               "mod_wsgi.process_group",
6925
8547
                                               config->process_group);
6926
8548
                            }
 
8549
#if PY_MAJOR_VERSION >= 3
 
8550
                            else if (PyUnicode_Check(result)) {
 
8551
                                PyObject *latin_item;
 
8552
                                latin_item = PyUnicode_AsLatin1String(result);
 
8553
                                if (!latin_item) {
 
8554
                                    PyErr_SetString(PyExc_TypeError,
 
8555
                                                    "Process group must be "
 
8556
                                                    "a byte string, value "
 
8557
                                                    "containing non 'latin-1' "
 
8558
                                                    "characters found");
 
8559
 
 
8560
                                    status = HTTP_INTERNAL_SERVER_ERROR;
 
8561
                                }
 
8562
                                else {
 
8563
                                    const char *s;
 
8564
 
 
8565
                                    Py_DECREF(result);
 
8566
                                    result = latin_item;
 
8567
 
 
8568
                                    s = PyString_AsString(result);
 
8569
                                    s = apr_pstrdup(r->pool, s);
 
8570
                                    s = wsgi_process_group(r, s);
 
8571
                                    config->process_group = s;
 
8572
 
 
8573
                                    apr_table_setn(r->subprocess_env,
 
8574
                                                   "mod_wsgi.process_group",
 
8575
                                                   config->process_group);
 
8576
                                }
 
8577
                            }
 
8578
#endif
6927
8579
                            else {
6928
8580
                                PyErr_SetString(PyExc_TypeError, "Process "
6929
 
                                                "group must be a string "
6930
 
                                                "object");
 
8581
                                                "group must be a byte string");
6931
8582
 
6932
8583
                                status = HTTP_INTERNAL_SERVER_ERROR;
6933
8584
                            }
6974
8625
                                               "mod_wsgi.application_group",
6975
8626
                                               config->application_group);
6976
8627
                            }
 
8628
#if PY_MAJOR_VERSION >= 3
 
8629
                            else if (PyUnicode_Check(result)) {
 
8630
                                PyObject *latin_item;
 
8631
                                latin_item = PyUnicode_AsLatin1String(result);
 
8632
                                if (!latin_item) {
 
8633
                                    PyErr_SetString(PyExc_TypeError,
 
8634
                                                    "Application group must "
 
8635
                                                    "be a byte string, value "
 
8636
                                                    "containing non 'latin-1' "
 
8637
                                                    "characters found");
 
8638
 
 
8639
                                    status = HTTP_INTERNAL_SERVER_ERROR;
 
8640
                                }
 
8641
                                else {
 
8642
                                    const char *s;
 
8643
 
 
8644
                                    Py_DECREF(result);
 
8645
                                    result = latin_item;
 
8646
 
 
8647
                                    s = PyString_AsString(result);
 
8648
                                    s = apr_pstrdup(r->pool, s);
 
8649
                                    s = wsgi_application_group(r, s);
 
8650
                                    config->application_group = s;
 
8651
 
 
8652
                                    apr_table_setn(r->subprocess_env,
 
8653
                                                   "mod_wsgi.application_group",
 
8654
                                                   config->application_group);
 
8655
                                }
 
8656
                            }
 
8657
#endif
6977
8658
                            else {
6978
8659
                                PyErr_SetString(PyExc_TypeError, "Application "
6979
8660
                                                "group must be a string "
7023
8704
                                               "mod_wsgi.callable_object",
7024
8705
                                               config->callable_object);
7025
8706
                            }
 
8707
#if PY_MAJOR_VERSION >= 3
 
8708
                            else if (PyUnicode_Check(result)) {
 
8709
                                PyObject *latin_item;
 
8710
                                latin_item = PyUnicode_AsLatin1String(result);
 
8711
                                if (!latin_item) {
 
8712
                                    PyErr_SetString(PyExc_TypeError,
 
8713
                                                    "Callable object must "
 
8714
                                                    "be a byte string, value "
 
8715
                                                    "containing non 'latin-1' "
 
8716
                                                    "characters found");
 
8717
 
 
8718
                                    status = HTTP_INTERNAL_SERVER_ERROR;
 
8719
                                }
 
8720
                                else {
 
8721
                                    const char *s;
 
8722
 
 
8723
                                    Py_DECREF(result);
 
8724
                                    result = latin_item;
 
8725
 
 
8726
                                    s = PyString_AsString(result);
 
8727
                                    s = apr_pstrdup(r->pool, s);
 
8728
                                    s = wsgi_callable_object(r, s);
 
8729
                                    config->callable_object = s;
 
8730
 
 
8731
                                    apr_table_setn(r->subprocess_env,
 
8732
                                                   "mod_wsgi.callable_object",
 
8733
                                                   config->callable_object);
 
8734
                                }
 
8735
                            }
 
8736
#endif
7026
8737
                            else {
7027
8738
                                PyErr_SetString(PyExc_TypeError, "Callable "
7028
8739
                                                "object must be a string "
7053
8764
 
7054
8765
            adapter->r = NULL;
7055
8766
 
7056
 
            /*
7057
 
             * Flush any data held within error log object
7058
 
             * and mark it as expired so that it can't be
7059
 
             * used beyond life of the request. We hope that
7060
 
             * this doesn't error, as it will overwrite any
7061
 
             * error from application if it does.
7062
 
             */
7063
 
 
7064
 
            args = PyTuple_New(0);
7065
 
            object = Log_flush(adapter->log, args);
 
8767
            /* Close the log object so data is flushed. */
 
8768
 
 
8769
            method = PyObject_GetAttrString(adapter->log, "close");
 
8770
 
 
8771
            if (!method) {
 
8772
                PyErr_Format(PyExc_AttributeError,
 
8773
                             "'%s' object has no attribute 'close'",
 
8774
                             adapter->log->ob_type->tp_name);
 
8775
            }
 
8776
            else {
 
8777
                args = PyTuple_New(0);
 
8778
                object = PyEval_CallObject(method, args);
 
8779
                Py_DECREF(args);
 
8780
            }
 
8781
 
7066
8782
            Py_XDECREF(object);
7067
 
            Py_DECREF(args);
 
8783
            Py_XDECREF(method);
7068
8784
 
7069
 
            adapter->log->r = NULL;
7070
 
            adapter->log->expired = 1;
 
8785
            /* No longer need adapter object. */
7071
8786
 
7072
8787
            Py_DECREF((PyObject *)adapter);
7073
8788
 
7074
8789
            /* Log any details of exceptions if execution failed. */
7075
8790
 
7076
 
            if (PyErr_Occurred()) {
7077
 
                LogObject *log;
7078
 
                log = newLogObject(r, APLOG_ERR);
7079
 
                wsgi_log_python_error(r, log, script);
7080
 
                Py_DECREF(log);
7081
 
            }
 
8791
            if (PyErr_Occurred())
 
8792
                wsgi_log_python_error(r, NULL, script);
7082
8793
 
7083
8794
            Py_DECREF(vars);
7084
8795
        }
7112
8823
 
7113
8824
    WSGIRequestConfig *config = NULL;
7114
8825
 
7115
 
    /*
7116
 
     * Only process requests for this module. Honour a content
7117
 
     * type here because mod_rewrite prior to Apache 2.2 only
7118
 
     * provides a means of setting content type and doesn't
7119
 
     * provide a means of setting the handler name explicitly.
7120
 
     */
7121
 
 
7122
 
    if (!r->handler || (strcmp(r->handler, "wsgi-script") &&
7123
 
        strcmp(r->handler, "application/x-httpd-wsgi"))) {
7124
 
        return DECLINED;
7125
 
    }
7126
 
 
7127
 
    /*
7128
 
     * Ensure that have adequate privileges to run the WSGI
7129
 
     * script. Require ExecCGI to be specified in Options for
7130
 
     * this. In doing this, using the wider interpretation that
7131
 
     * ExecCGI refers to any executable like script even though
7132
 
     * not a separate process execution.
7133
 
     */
7134
 
 
7135
 
    if (!(ap_allow_options(r) & OPT_EXECCGI) && !wsgi_is_script_aliased(r)) {
7136
 
        wsgi_log_script_error(r, "Options ExecCGI is off in this directory",
7137
 
                              r->filename);
7138
 
        return HTTP_FORBIDDEN;
7139
 
    }
7140
 
 
7141
 
    /* Ensure target script exists and is a file. */
7142
 
 
7143
 
#if AP_SERVER_MAJORVERSION_NUMBER < 2
7144
 
    if (r->finfo.st_mode == 0) {
7145
 
        wsgi_log_script_error(r, "Target WSGI script not found or unable "
7146
 
                              "to stat", r->filename);
7147
 
        return HTTP_NOT_FOUND;
7148
 
    }
7149
 
#else
7150
 
    if (r->finfo.filetype == 0) {
7151
 
        wsgi_log_script_error(r, "Target WSGI script not found or unable "
7152
 
                              "to stat", r->filename);
7153
 
        return HTTP_NOT_FOUND;
7154
 
    }
7155
 
#endif
7156
 
 
7157
 
#if AP_SERVER_MAJORVERSION_NUMBER < 2
7158
 
    if (S_ISDIR(r->finfo.st_mode)) {
7159
 
        wsgi_log_script_error(r, "Attempt to invoke directory as WSGI "
7160
 
                              "application", r->filename);
7161
 
        return HTTP_FORBIDDEN;
7162
 
    }
7163
 
#else
7164
 
    if (r->finfo.filetype == APR_DIR) {
7165
 
        wsgi_log_script_error(r, "Attempt to invoke directory as WSGI "
7166
 
                              "application", r->filename);
7167
 
        return HTTP_FORBIDDEN;
7168
 
    }
7169
 
#endif
 
8826
    const char *value = NULL;
 
8827
 
 
8828
    /* Filter out the obvious case of no handler defined. */
 
8829
 
 
8830
    if (!r->handler)
 
8831
        return DECLINED;
 
8832
 
 
8833
    /*
 
8834
     * Construct request configuration and cache it in the
 
8835
     * request object against this module so can access it later
 
8836
     * from handler code.
 
8837
     */
 
8838
 
 
8839
    config = wsgi_create_req_config(r->pool, r);
 
8840
 
 
8841
    ap_set_module_config(r->request_config, &wsgi_module, config);
 
8842
 
 
8843
    /*
 
8844
     * Only process requests for this module. First check for
 
8845
     * where target is the actual WSGI script. Then need to
 
8846
     * check for the case where handler name mapped to a handler
 
8847
     * script definition.
 
8848
     */
 
8849
 
 
8850
    if (!strcmp(r->handler, "wsgi-script") ||
 
8851
        !strcmp(r->handler, "application/x-httpd-wsgi")) {
 
8852
 
 
8853
        /*
 
8854
         * Ensure that have adequate privileges to run the WSGI
 
8855
         * script. Require ExecCGI to be specified in Options for
 
8856
         * this. In doing this, using the wider interpretation that
 
8857
         * ExecCGI refers to any executable like script even though
 
8858
         * not a separate process execution.
 
8859
         */
 
8860
 
 
8861
        if (!(ap_allow_options(r) & OPT_EXECCGI) &&
 
8862
            !wsgi_is_script_aliased(r)) {
 
8863
            wsgi_log_script_error(r, "Options ExecCGI is off in this "
 
8864
                                  "directory", r->filename);
 
8865
            return HTTP_FORBIDDEN;
 
8866
        }
 
8867
 
 
8868
        /* Ensure target script exists and is a file. */
 
8869
 
 
8870
#if AP_SERVER_MAJORVERSION_NUMBER < 2
 
8871
        if (r->finfo.st_mode == 0) {
 
8872
            wsgi_log_script_error(r, "Target WSGI script not found or unable "
 
8873
                                  "to stat", r->filename);
 
8874
            return HTTP_NOT_FOUND;
 
8875
        }
 
8876
#else
 
8877
        if (r->finfo.filetype == 0) {
 
8878
            wsgi_log_script_error(r, "Target WSGI script not found or unable "
 
8879
                                  "to stat", r->filename);
 
8880
            return HTTP_NOT_FOUND;
 
8881
        }
 
8882
#endif
 
8883
 
 
8884
#if AP_SERVER_MAJORVERSION_NUMBER < 2
 
8885
        if (S_ISDIR(r->finfo.st_mode)) {
 
8886
            wsgi_log_script_error(r, "Attempt to invoke directory as WSGI "
 
8887
                                  "application", r->filename);
 
8888
            return HTTP_FORBIDDEN;
 
8889
        }
 
8890
#else
 
8891
        if (r->finfo.filetype == APR_DIR) {
 
8892
            wsgi_log_script_error(r, "Attempt to invoke directory as WSGI "
 
8893
                                  "application", r->filename);
 
8894
            return HTTP_FORBIDDEN;
 
8895
        }
 
8896
#endif
 
8897
 
 
8898
        if (wsgi_is_script_aliased(r)) {
 
8899
            /*
 
8900
             * Allow any configuration supplied through request notes to
 
8901
             * override respective values. Request notes are used when
 
8902
             * configuration supplied with WSGIScriptAlias directives.
 
8903
             */
 
8904
 
 
8905
            if (value = apr_table_get(r->notes, "mod_wsgi.process_group"))
 
8906
                config->process_group = wsgi_process_group(r, value);
 
8907
            if (value = apr_table_get(r->notes, "mod_wsgi.application_group"))
 
8908
                config->application_group = wsgi_application_group(r, value);
 
8909
            if (value = apr_table_get(r->notes, "mod_wsgi.callable_object"))
 
8910
                config->callable_object = value;
 
8911
 
 
8912
            if (value = apr_table_get(r->notes,
 
8913
                                      "mod_wsgi.pass_authorization")) {
 
8914
                if (!strcmp(value, "1"))
 
8915
                    config->pass_authorization = 1;
 
8916
                else
 
8917
                    config->pass_authorization = 0;
 
8918
            }
 
8919
        }
 
8920
    }
 
8921
#if AP_SERVER_MAJORVERSION_NUMBER >= 2
 
8922
    else if (config->handler_scripts) {
 
8923
        WSGIScriptFile *entry;
 
8924
 
 
8925
        entry = (WSGIScriptFile *)apr_hash_get(config->handler_scripts,
 
8926
                                               r->handler,
 
8927
                                               APR_HASH_KEY_STRING);
 
8928
 
 
8929
        if (entry) {
 
8930
            config->handler_script = entry->handler_script;
 
8931
            config->callable_object = "handle_request";
 
8932
 
 
8933
            if (value = entry->process_group)
 
8934
                config->process_group = wsgi_process_group(r, value);
 
8935
            if (value = entry->application_group)
 
8936
                config->application_group = wsgi_application_group(r, value);
 
8937
 
 
8938
            if (value = entry->pass_authorization) {
 
8939
                if (!strcmp(value, "1"))
 
8940
                    config->pass_authorization = 1;
 
8941
                else
 
8942
                    config->pass_authorization = 0;
 
8943
            }
 
8944
        }
 
8945
        else
 
8946
            return DECLINED;
 
8947
    }
 
8948
#endif
 
8949
    else
 
8950
        return DECLINED;
7170
8951
 
7171
8952
    /*
7172
8953
     * For Apache 2.0+ honour AcceptPathInfo directive. Default
7185
8966
 
7186
8967
    /*
7187
8968
     * Setup policy to apply if request contains a body. Note
7188
 
     * that it is not possible to have chunked transfer encoding
7189
 
     * for the request content. This is actually a limitation in
7190
 
     * WSGI specification as it has no way of indicating that
7191
 
     * there is content of unknown length, nor a way to deal
7192
 
     * with trailers appearing after any chunked content.
 
8969
     * that WSGI specification doesn't strictly allow for chunked
 
8970
     * request content as CONTENT_LENGTH required when reading
 
8971
     * input and application isn't meant to read more than what
 
8972
     * is defined by CONTENT_LENGTH. To allow chunked request
 
8973
     * content tell Apache to dechunk it. For application to use
 
8974
     * the content, it has to ignore WSGI specification and use
 
8975
     * read() with no arguments to read all available input, or
 
8976
     * call read() with specific block size until read() returns
 
8977
     * an empty string.
7193
8978
     */
7194
8979
 
7195
 
    status = ap_setup_client_block(r, REQUEST_CHUNKED_ERROR);
 
8980
    if (config->chunked_request)
 
8981
        status = ap_setup_client_block(r, REQUEST_CHUNKED_DECHUNK);
 
8982
    else
 
8983
        status = ap_setup_client_block(r, REQUEST_CHUNKED_ERROR);
7196
8984
 
7197
8985
    if (status != OK)
7198
8986
        return status;
7215
9003
        return OK;
7216
9004
    }
7217
9005
 
7218
 
    /*
7219
 
     * Construct request configuration and cache it in the
7220
 
     * request object against this module so can access it
7221
 
     * later from handler code.
7222
 
     */
7223
 
 
7224
 
    config = wsgi_create_req_config(r->pool, r);
7225
 
 
7226
 
    ap_set_module_config(r->request_config, &wsgi_module, config);
7227
 
 
7228
9006
    /* Build the sub process environment. */
7229
9007
 
7230
9008
    wsgi_build_environment(r);
7286
9064
 
7287
9065
    ap_add_version_component(package);
7288
9066
 
 
9067
    /* Record Python version string with Apache. */
 
9068
 
 
9069
    if (!Py_IsInitialized()) {
 
9070
        char buffer[256];
 
9071
        const char *token = NULL;
 
9072
        const char *version = NULL;
 
9073
        
 
9074
        version = Py_GetVersion();
 
9075
 
 
9076
        token = version;
 
9077
        while (*token && *token != ' ')
 
9078
            token++;
 
9079
 
 
9080
        strcpy(buffer, "Python/");
 
9081
        strncat(buffer, version, token - version);
 
9082
 
 
9083
        ap_add_version_component(buffer);
 
9084
    }
 
9085
 
7289
9086
    /* Retain reference to base server. */
7290
9087
 
7291
9088
    wsgi_server = s;
7303
9100
 
7304
9101
    wsgi_server_config = ap_get_module_config(s->module_config, &wsgi_module);
7305
9102
 
7306
 
    /* Initialise Python if not already done. */
7307
 
 
7308
 
    wsgi_python_init(p);
 
9103
    /*
 
9104
     * Check that the version of Python found at
 
9105
     * runtime is what was used at compilation.
 
9106
     */
 
9107
 
 
9108
    wsgi_python_version();
 
9109
 
 
9110
    /*
 
9111
     * Initialise Python if required to be done in
 
9112
     * the parent process. Note that it will not be
 
9113
     * initialised if mod_python loaded and it has
 
9114
     * already been done.
 
9115
     */
 
9116
 
 
9117
    if (!wsgi_python_after_fork)
 
9118
        wsgi_python_init(p);
7309
9119
}
7310
9120
 
7311
9121
static void wsgi_hook_child_init(server_rec *s, apr_pool_t *p)
7312
9122
{
7313
 
    wsgi_python_child_init(p);
 
9123
    if (wsgi_python_required) {
 
9124
        /*
 
9125
         * Initialise Python if required to be done in
 
9126
         * the child process. Note that it will not be
 
9127
         * initialised if mod_python loaded and it has
 
9128
         * already been done.
 
9129
         */
 
9130
 
 
9131
        if (wsgi_python_after_fork)
 
9132
            wsgi_python_init(p);
 
9133
 
 
9134
        /*
 
9135
         * Now perform additional initialisation steps
 
9136
         * always done in child process.
 
9137
         */
 
9138
 
 
9139
        wsgi_python_child_init(p);
 
9140
    }
7314
9141
}
7315
9142
 
7316
9143
/* Dispatch list of content handlers */
7323
9150
static const command_rec wsgi_commands[] =
7324
9151
{
7325
9152
    { "WSGIScriptAlias", wsgi_add_script_alias, NULL,
7326
 
        RSRC_CONF, TAKE2, "Map location to target WSGI script file." },
 
9153
        RSRC_CONF, RAW_ARGS, "Map location to target WSGI script file." },
7327
9154
    { "WSGIScriptAliasMatch", wsgi_add_script_alias, "*",
7328
 
        RSRC_CONF, TAKE2, "Map location to target WSGI script file." },
7329
 
 
 
9155
        RSRC_CONF, RAW_ARGS, "Map location to target WSGI script file." },
 
9156
 
 
9157
    { "WSGIVerboseDebugging", wsgi_set_verbose_debugging, NULL,
 
9158
        RSRC_CONF, TAKE1, "Enable/Disable verbose debugging messages." },
 
9159
 
 
9160
#if PY_MAJOR_VERSION == 2 && PY_MINOR_VERSION >= 6
 
9161
    { "WSGIPy3kWarningFlag", wsgi_set_py3k_warning_flag, NULL,
 
9162
        RSRC_CONF, TAKE1, "Enable/Disable Python 3.0 warnings." },
 
9163
#endif
 
9164
 
 
9165
    { "WSGIPythonWarnings", wsgi_add_python_warnings, NULL,
 
9166
        RSRC_CONF, TAKE1, "Control Python warning messages." },
7330
9167
    { "WSGIPythonOptimize", wsgi_set_python_optimize, NULL,
7331
9168
        RSRC_CONF, TAKE1, "Set level of Python compiler optimisations." },
7332
9169
    { "WSGIPythonHome", wsgi_set_python_home, NULL,
7336
9173
    { "WSGIPythonEggs", wsgi_set_python_eggs, NULL,
7337
9174
        RSRC_CONF, TAKE1, "Python eggs cache directory." },
7338
9175
 
7339
 
    { "WSGIRestrictEmbedded", wsgi_set_restrict_embedded, NULL,
7340
 
        RSRC_CONF, TAKE1, "Enable/Disable use of embedded mode." },
7341
9176
    { "WSGIRestrictStdin", wsgi_set_restrict_stdin, NULL,
7342
9177
        RSRC_CONF, TAKE1, "Enable/Disable restrictions on use of STDIN." },
7343
9178
    { "WSGIRestrictStdout", wsgi_set_restrict_stdout, NULL,
7358
9193
    { "WSGIDispatchScript", wsgi_set_dispatch_script, NULL,
7359
9194
        ACCESS_CONF|RSRC_CONF, RAW_ARGS, "Location of WSGI dispatch script." },
7360
9195
 
7361
 
    { "WSGIApacheExtensions", wsgi_set_apache_extensions, NULL,
7362
 
        ACCESS_CONF|RSRC_CONF, TAKE1, "Enable/Disable Apache extensions." },
7363
9196
    { "WSGIPassAuthorization", wsgi_set_pass_authorization, NULL,
7364
9197
        OR_FILEINFO, TAKE1, "Enable/Disable WSGI authorization." },
7365
9198
    { "WSGIScriptReloading", wsgi_set_script_reloading, NULL,
7366
9199
        OR_FILEINFO, TAKE1, "Enable/Disable script reloading mechanism." },
7367
 
    { "WSGIReloadMechanism", wsgi_set_reload_mechanism, NULL,
7368
 
        OR_FILEINFO, TAKE1, "Defines what is reloaded when a reload occurs." },
 
9200
    { "WSGIChunkedRequest", wsgi_set_chunked_request, NULL,
 
9201
        OR_FILEINFO, TAKE1, "Enable/Disable support for chunked request." },
7369
9202
 
7370
9203
    { NULL }
7371
9204
};
7409
9242
 
7410
9243
#if defined(MOD_WSGI_WITH_DAEMONS)
7411
9244
 
7412
 
#include "unixd.h"
7413
 
#include "scoreboard.h"
7414
 
#include "mpm_common.h"
7415
 
#include "apr_proc_mutex.h"
7416
 
#include "http_connection.h"
7417
 
#include "apr_buckets.h"
7418
 
#include "apr_poll.h"
7419
 
#include "apr_signal.h"
7420
 
#include "http_vhost.h"
7421
 
 
7422
 
#if APR_HAVE_SYS_SOCKET_H
7423
 
#include <sys/socket.h>
7424
 
#endif
7425
 
#if APR_HAVE_UNISTD_H
7426
 
#include <unistd.h>
7427
 
#endif
7428
 
#if APR_HAVE_SYS_TYPES_H
7429
 
#include <sys/types.h>
7430
 
#endif
7431
 
#ifdef HAVE_SYS_SEM_H
7432
 
#include <sys/sem.h>
7433
 
#endif
7434
 
 
7435
 
#include <sys/un.h>
7436
 
 
7437
 
#ifndef WSGI_LISTEN_BACKLOG
7438
 
#define WSGI_LISTEN_BACKLOG 100
7439
 
#endif
7440
 
 
7441
 
#ifndef WSGI_CONNECT_ATTEMPTS
7442
 
#define WSGI_CONNECT_ATTEMPTS 15
7443
 
#endif
7444
 
 
7445
 
typedef struct {
7446
 
    server_rec *server;
7447
 
    long random;
7448
 
    int id;
7449
 
    const char *name;
7450
 
    const char *user;
7451
 
    uid_t uid;
7452
 
    const char *group;
7453
 
    gid_t gid;
7454
 
    int processes;
7455
 
    int multiprocess;
7456
 
    int threads;
7457
 
    int umask;
7458
 
    const char *home;
7459
 
    const char *python_path;
7460
 
    const char *python_eggs;
7461
 
    int stack_size;
7462
 
    int maximum_requests;
7463
 
    int shutdown_timeout;
7464
 
    apr_time_t deadlock_timeout;
7465
 
    apr_time_t inactivity_timeout;
7466
 
    const char *display_name;
7467
 
    int send_buffer_size;
7468
 
    int recv_buffer_size;
7469
 
    const char *socket;
7470
 
    int listener_fd;
7471
 
    const char* mutex_path;
7472
 
    apr_proc_mutex_t* mutex;
7473
 
} WSGIProcessGroup;
7474
 
 
7475
 
typedef struct {
7476
 
    WSGIProcessGroup *group;
7477
 
    int instance;
7478
 
    apr_proc_t process;
7479
 
    apr_socket_t *listener;
7480
 
} WSGIDaemonProcess;
7481
 
 
7482
 
typedef struct {
7483
 
    WSGIDaemonProcess *process;
7484
 
    apr_thread_t *thread;
7485
 
    int running;
7486
 
} WSGIDaemonThread;
7487
 
 
7488
 
typedef struct {
7489
 
    const char *name;
7490
 
    const char *socket;
7491
 
    int fd;
7492
 
} WSGIDaemonSocket;
7493
 
 
7494
 
static int wsgi_daemon_count = 0;
7495
 
static apr_hash_t *wsgi_daemon_index = NULL;
7496
 
static apr_hash_t *wsgi_daemon_listeners = NULL;
7497
 
 
7498
 
static WSGIDaemonProcess *wsgi_daemon_process = NULL;
7499
 
 
7500
 
static apr_thread_mutex_t* wsgi_daemon_lock = NULL;
7501
 
 
7502
 
static int volatile wsgi_request_count = 0;
7503
 
 
7504
9245
static const char *wsgi_add_daemon_process(cmd_parms *cmd, void *mconfig,
7505
9246
                                           const char *args)
7506
9247
{
7513
9254
    int threads = 15;
7514
9255
    int umask = -1;
7515
9256
 
 
9257
    const char *root = NULL;
7516
9258
    const char *home = NULL;
7517
9259
    const char *python_path = NULL;
7518
9260
    const char *python_eggs = NULL;
7528
9270
    int send_buffer_size = 0;
7529
9271
    int recv_buffer_size = 0;
7530
9272
 
 
9273
    const char *script_user = NULL;
 
9274
    const char *script_group = NULL;
 
9275
 
 
9276
    int cpu_time_limit = 0;
 
9277
    int cpu_priority = 0;
 
9278
 
7531
9279
    uid_t uid;
7532
9280
    uid_t gid;
7533
9281
 
7545
9293
     * Apache configuration.
7546
9294
     */
7547
9295
 
7548
 
    uid = unixd_config.user_id;
7549
 
    user = unixd_config.user_name;
 
9296
    uid = ap_unixd_config.user_id;
 
9297
    user = ap_unixd_config.user_name;
7550
9298
 
7551
 
    gid = unixd_config.group_id;
 
9299
    gid = ap_unixd_config.group_id;
7552
9300
 
7553
9301
    /* Now parse options for directive. */
7554
9302
 
7558
9306
        return "Name of WSGI daemon process not supplied.";
7559
9307
 
7560
9308
    while (*args) {
7561
 
        option = ap_getword_conf(cmd->pool, &args);
 
9309
        if (wsgi_parse_option(cmd->pool, &args, &option,
 
9310
                              &value) != APR_SUCCESS) {
 
9311
            return "Invalid option to WSGI daemon process definition.";
 
9312
        }
7562
9313
 
7563
 
        if (strstr(option, "user=") == option) {
7564
 
            value = option + 5;
 
9314
        if (!strcmp(option, "user")) {
7565
9315
            if (!*value)
7566
9316
                return "Invalid user for WSGI daemon process.";
7567
9317
 
7579
9329
                user = entry->pw_name;
7580
9330
            }
7581
9331
        }
7582
 
        else if (strstr(option, "group=") == option) {
7583
 
            value = option + 6;
 
9332
        else if (!strcmp(option, "group")) {
7584
9333
            if (!*value)
7585
9334
                return "Invalid group for WSGI daemon process.";
7586
9335
 
7587
9336
            group = value;
7588
9337
            gid = ap_gname2id(group);
7589
9338
        }
7590
 
        else if (strstr(option, "processes=") == option) {
7591
 
            value = option + 10;
 
9339
        else if (!strcmp(option, "processes")) {
7592
9340
            if (!*value)
7593
9341
                return "Invalid process count for WSGI daemon process.";
7594
9342
 
7598
9346
 
7599
9347
            multiprocess = 1;
7600
9348
        }
7601
 
        else if (strstr(option, "threads=") == option) {
7602
 
            value = option + 8;
 
9349
        else if (!strcmp(option, "threads")) {
7603
9350
            if (!*value)
7604
9351
                return "Invalid thread count for WSGI daemon process.";
7605
9352
 
7606
9353
            threads = atoi(value);
7607
 
            if (threads < 1)
 
9354
            if (threads < 1 || threads >= WSGI_STACK_LAST-1)
7608
9355
                return "Invalid thread count for WSGI daemon process.";
7609
9356
        }
7610
 
        else if (strstr(option, "umask=") == option) {
7611
 
            value = option + 6;
 
9357
        else if (!strcmp(option, "umask")) {
7612
9358
            if (!*value)
7613
9359
                return "Invalid umask for WSGI daemon process.";
7614
9360
 
7618
9364
            if (*value || errno == ERANGE || umask < 0)
7619
9365
                return "Invalid umask for WSGI daemon process.";
7620
9366
        }
7621
 
        else if (strstr(option, "home=") == option) {
7622
 
            value = option + 5;
 
9367
        else if (!strcmp(option, "chroot")) {
 
9368
            if (geteuid())
 
9369
                return "Cannot chroot WSGI daemon process when not root.";
 
9370
 
 
9371
            if (*value != '/')
 
9372
                return "Invalid chroot directory for WSGI daemon process.";
 
9373
 
 
9374
            root = value;
 
9375
        }
 
9376
        else if (!strcmp(option, "home")) {
7623
9377
            if (*value != '/')
7624
9378
                return "Invalid home directory for WSGI daemon process.";
7625
9379
 
7626
9380
            home = value;
7627
9381
        }
7628
 
        else if (strstr(option, "python-path=") == option) {
7629
 
            value = option + 12;
7630
 
 
 
9382
        else if (!strcmp(option, "python-path")) {
7631
9383
            python_path = value;
7632
9384
        }
7633
 
        else if (strstr(option, "python-eggs=") == option) {
7634
 
            value = option + 12;
7635
 
 
 
9385
        else if (!strcmp(option, "python-eggs")) {
7636
9386
            python_eggs = value;
7637
9387
        }
7638
9388
#if (APR_MAJOR_VERSION >= 1)
7639
 
        else if (strstr(option, "stack-size=") == option) {
7640
 
            value = option + 11;
 
9389
        else if (!strcmp(option, "stack-size")) {
7641
9390
            if (!*value)
7642
9391
                return "Invalid stack size for WSGI daemon process.";
7643
9392
 
7646
9395
                return "Invalid stack size for WSGI daemon process.";
7647
9396
        }
7648
9397
#endif
7649
 
        else if (strstr(option, "maximum-requests=") == option) {
7650
 
            value = option + 17;
 
9398
        else if (!strcmp(option, "maximum-requests")) {
7651
9399
            if (!*value)
7652
9400
                return "Invalid request count for WSGI daemon process.";
7653
9401
 
7655
9403
            if (maximum_requests < 0)
7656
9404
                return "Invalid request count for WSGI daemon process.";
7657
9405
        }
7658
 
        else if (strstr(option, "shutdown-timeout=") == option) {
7659
 
            value = option + 17;
 
9406
        else if (!strcmp(option, "shutdown-timeout")) {
7660
9407
            if (!*value)
7661
9408
                return "Invalid shutdown timeout for WSGI daemon process.";
7662
9409
 
7664
9411
            if (shutdown_timeout < 0)
7665
9412
                return "Invalid shutdown timeout for WSGI daemon process.";
7666
9413
        }
7667
 
        else if (strstr(option, "deadlock-timeout=") == option) {
7668
 
            value = option + 17;
 
9414
        else if (!strcmp(option, "deadlock-timeout")) {
7669
9415
            if (!*value)
7670
9416
                return "Invalid deadlock timeout for WSGI daemon process.";
7671
9417
 
7673
9419
            if (deadlock_timeout < 0)
7674
9420
                return "Invalid deadlock timeout for WSGI daemon process.";
7675
9421
        }
7676
 
        else if (strstr(option, "inactivity-timeout=") == option) {
7677
 
            value = option + 19;
 
9422
        else if (!strcmp(option, "inactivity-timeout")) {
7678
9423
            if (!*value)
7679
9424
                return "Invalid inactivity timeout for WSGI daemon process.";
7680
9425
 
7682
9427
            if (inactivity_timeout < 0)
7683
9428
                return "Invalid inactivity timeout for WSGI daemon process.";
7684
9429
        }
7685
 
        else if (strstr(option, "display-name=") == option) {
7686
 
            value = option + 13;
7687
 
 
 
9430
        else if (!strcmp(option, "display-name")) {
7688
9431
            display_name = value;
7689
9432
        }
7690
 
        else if (strstr(option, "send-buffer-size=") == option) {
7691
 
            value = option + 17;
 
9433
        else if (!strcmp(option, "send-buffer-size")) {
7692
9434
            if (!*value)
7693
9435
                return "Invalid send buffer size for WSGI daemon process.";
7694
9436
 
7698
9440
                       "or 0 for system default.";
7699
9441
            }
7700
9442
        }
7701
 
        else if (strstr(option, "receive-buffer-size=") == option) {
7702
 
            value = option + 20;
 
9443
        else if (!strcmp(option, "receive-buffer-size")) {
7703
9444
            if (!*value)
7704
9445
                return "Invalid receive buffer size for WSGI daemon process.";
7705
9446
 
7709
9450
                       "or 0 for system default.";
7710
9451
            }
7711
9452
        }
 
9453
        else if (!strcmp(option, "script-user")) {
 
9454
            uid_t script_uid;
 
9455
 
 
9456
            if (!*value)
 
9457
                return "Invalid script user for WSGI daemon process.";
 
9458
 
 
9459
            script_uid = ap_uname2id(value);
 
9460
 
 
9461
            if (*value == '#') {
 
9462
                struct passwd *entry = NULL;
 
9463
 
 
9464
                if ((entry = getpwuid(script_uid)) == NULL)
 
9465
                    return "Couldn't determine uid from script user.";
 
9466
 
 
9467
                value = entry->pw_name;
 
9468
            }
 
9469
 
 
9470
            script_user = value;
 
9471
        }
 
9472
        else if (!strcmp(option, "script-group")) {
 
9473
            gid_t script_gid;
 
9474
 
 
9475
            if (!*value)
 
9476
                return "Invalid script group for WSGI daemon process.";
 
9477
 
 
9478
            script_gid = ap_gname2id(value);
 
9479
 
 
9480
            if (*value == '#') {
 
9481
                struct group *entry = NULL;
 
9482
 
 
9483
                if ((entry = getgrgid(script_gid)) == NULL)
 
9484
                    return "Couldn't determine gid from script group.";
 
9485
 
 
9486
                value = entry->gr_name;
 
9487
            }
 
9488
 
 
9489
            script_group = value;
 
9490
        }
 
9491
        else if (!strcmp(option, "cpu-time-limit")) {
 
9492
            if (!*value)
 
9493
                return "Invalid CPU time limit for WSGI daemon process.";
 
9494
 
 
9495
            cpu_time_limit = atoi(value);
 
9496
            if (cpu_time_limit < 0)
 
9497
                return "Invalid CPU time limit for WSGI daemon process.";
 
9498
        }
 
9499
        else if (!strcmp(option, "cpu-priority")) {
 
9500
            if (!*value)
 
9501
                return "Invalid CPU priority for WSGI daemon process.";
 
9502
 
 
9503
            cpu_priority = atoi(value);
 
9504
        }
7712
9505
        else
7713
9506
            return "Invalid option to WSGI daemon process definition.";
7714
9507
    }
7715
9508
 
 
9509
    if (script_user && script_group)
 
9510
        return "Only one of script-user and script-group allowed.";
 
9511
 
7716
9512
    if (!wsgi_daemon_list) {
7717
9513
        wsgi_daemon_list = apr_array_make(cmd->pool, 20,
7718
9514
                                          sizeof(WSGIProcessGroup));
7748
9544
    entry->threads = threads;
7749
9545
 
7750
9546
    entry->umask = umask;
 
9547
    entry->root = root;
7751
9548
    entry->home = home;
7752
9549
 
7753
9550
    entry->python_path = python_path;
7764
9561
    entry->send_buffer_size = send_buffer_size;
7765
9562
    entry->recv_buffer_size = recv_buffer_size;
7766
9563
 
 
9564
    entry->script_user = script_user;
 
9565
    entry->script_group = script_group;
 
9566
 
 
9567
    entry->cpu_time_limit = cpu_time_limit;
 
9568
    entry->cpu_priority = cpu_priority;
 
9569
 
7767
9570
    entry->listener_fd = -1;
7768
9571
 
7769
9572
    return NULL;
7822
9625
 
7823
9626
    sconfig = ap_get_module_config(cmd->server->module_config, &wsgi_module);
7824
9627
 
 
9628
#if !defined(AP_ACCEPT_MUTEX_TYPE)
7825
9629
    sconfig->lock_mechanism = ap_accept_lock_mech;
 
9630
#else
 
9631
    sconfig->lock_mechanism = APR_LOCK_DEFAULT;
 
9632
#endif
7826
9633
 
7827
9634
    if (!strcasecmp(arg, "default")) {
7828
9635
        sconfig->lock_mechanism = APR_LOCK_DEFAULT;
7864
9671
static apr_file_t *wsgi_signal_pipe_in = NULL;
7865
9672
static apr_file_t *wsgi_signal_pipe_out = NULL;
7866
9673
 
 
9674
static int wsgi_cpu_time_limit_exceeded = 0;
 
9675
 
7867
9676
static void wsgi_signal_handler(int signum)
7868
9677
{
7869
9678
    apr_size_t nbytes = 1;
7870
9679
 
 
9680
    if (signum == SIGXCPU)
 
9681
        wsgi_cpu_time_limit_exceeded = 1;
 
9682
 
7871
9683
    apr_file_write(wsgi_signal_pipe_out, "X", &nbytes);
7872
9684
    apr_file_flush(wsgi_signal_pipe_out);
7873
9685
 
8014
9826
    if (daemon->group->umask != -1)
8015
9827
        umask(daemon->group->umask);
8016
9828
 
 
9829
    /* Change to chroot environment. */
 
9830
 
 
9831
    if (daemon->group->root) {
 
9832
        if (chroot(daemon->group->root) == -1) {
 
9833
            ap_log_error(APLOG_MARK, WSGI_LOG_ALERT(errno), wsgi_server,
 
9834
                         "mod_wsgi (pid=%d): Unable to change root "
 
9835
                         "directory to '%s'.", getpid(), daemon->group->root);
 
9836
        }
 
9837
    }
 
9838
 
8017
9839
    /* Setup the working directory.*/
8018
9840
 
8019
9841
    if (daemon->group->home) {
8144
9966
        ap_log_error(APLOG_MARK, WSGI_LOG_WARNING(errno), wsgi_server,
8145
9967
                     "mod_wsgi (pid=%d): Removing stale unix domain "
8146
9968
                     "socket '%s'.", getpid(), process->socket);
8147
 
        
 
9969
 
8148
9970
        unlink(process->socket);
8149
 
    
 
9971
 
8150
9972
        rc = bind(sockfd, (struct sockaddr *)&addr, sizeof(addr));
8151
 
    }                              
 
9973
    }
8152
9974
 
8153
9975
    umask(omask);
8154
9976
 
8167
9989
    }
8168
9990
 
8169
9991
    if (!geteuid()) {
8170
 
        if (chown(process->socket, unixd_config.user_id, -1) < 0) {
 
9992
        if (chown(process->socket, ap_unixd_config.user_id, -1) < 0) {
8171
9993
            ap_log_error(APLOG_MARK, WSGI_LOG_ALERT(errno), wsgi_server,
8172
9994
                         "mod_wsgi (pid=%d): Couldn't change owner of unix "
8173
9995
                         "domain socket '%s'.", getpid(),
8258
10080
    ap_lingering_close(c);
8259
10081
}
8260
10082
 
 
10083
static apr_status_t wsgi_worker_acquire(int id)
 
10084
{
 
10085
    WSGIThreadStack *stack = wsgi_worker_stack;
 
10086
    WSGIDaemonThread *thread = &wsgi_worker_threads[id];
 
10087
 
 
10088
    while (1) {
 
10089
        apr_uint32_t state = stack->state;
 
10090
        if (state & (WSGI_STACK_TERMINATED | WSGI_STACK_NO_LISTENER)) {
 
10091
            if (state & WSGI_STACK_TERMINATED) {
 
10092
                return APR_EINVAL;
 
10093
            }
 
10094
            if (apr_atomic_cas32(&(stack->state), WSGI_STACK_LAST, state) !=
 
10095
                state) {
 
10096
                continue;
 
10097
            }
 
10098
            else {
 
10099
                return APR_SUCCESS;
 
10100
            }
 
10101
        }
 
10102
        thread->next = state;
 
10103
        if (apr_atomic_cas32(&(stack->state), (unsigned)id, state) != state) {
 
10104
            continue;
 
10105
        }
 
10106
        else {
 
10107
            apr_status_t rv;
 
10108
 
 
10109
            if (thread->wakeup) {
 
10110
                thread->wakeup = 0;
 
10111
 
 
10112
                return APR_SUCCESS;
 
10113
            }
 
10114
 
 
10115
            rv = apr_thread_cond_wait(thread->condition, thread->mutex);
 
10116
 
 
10117
            while (rv == APR_SUCCESS && !thread->wakeup)
 
10118
                rv = apr_thread_cond_wait(thread->condition, thread->mutex);
 
10119
 
 
10120
            if (rv != APR_SUCCESS) {
 
10121
                ap_log_error(APLOG_MARK, WSGI_LOG_CRIT(rv),
 
10122
                             wsgi_server, "mod_wsgi (pid=%d): "
 
10123
                             "Wait on thread %d wakeup condition variable "
 
10124
                             "failed.", getpid(), id);
 
10125
            }
 
10126
 
 
10127
            thread->wakeup = 0;
 
10128
 
 
10129
            return rv;
 
10130
        }
 
10131
    }
 
10132
}
 
10133
 
 
10134
static apr_status_t wsgi_worker_release()
 
10135
{
 
10136
    WSGIThreadStack *stack = wsgi_worker_stack;
 
10137
 
 
10138
    while (1) {
 
10139
        apr_uint32_t state = stack->state;
 
10140
        unsigned int first = state & WSGI_STACK_HEAD;
 
10141
        if (first == WSGI_STACK_LAST) {
 
10142
            if (apr_atomic_cas32(&(stack->state),
 
10143
                                 state | WSGI_STACK_NO_LISTENER,
 
10144
                                 state) != state) {
 
10145
                continue;
 
10146
            }
 
10147
            else {
 
10148
                return APR_SUCCESS;
 
10149
            }
 
10150
        }
 
10151
        else {
 
10152
            WSGIDaemonThread *thread = &wsgi_worker_threads[first];
 
10153
            if (apr_atomic_cas32(&(stack->state),
 
10154
                                 (state ^ first) | thread->next,
 
10155
                                 state) != state) {
 
10156
                continue;
 
10157
            }
 
10158
            else {
 
10159
                /*
 
10160
                 * Flag that thread should be woken up and then
 
10161
                 * signal it via the condition variable.
 
10162
                 */
 
10163
 
 
10164
                apr_status_t rv;
 
10165
                if ((rv = apr_thread_mutex_lock(thread->mutex)) !=
 
10166
                    APR_SUCCESS) {
 
10167
                    return rv;
 
10168
                }
 
10169
 
 
10170
                thread->wakeup = 1;
 
10171
 
 
10172
                if ((rv = apr_thread_mutex_unlock(thread->mutex)) !=
 
10173
                    APR_SUCCESS) {
 
10174
                    return rv;
 
10175
                }
 
10176
 
 
10177
                return apr_thread_cond_signal(thread->condition);
 
10178
            }
 
10179
        }
 
10180
    }
 
10181
}
 
10182
 
 
10183
static apr_status_t wsgi_worker_shutdown()
 
10184
{
 
10185
    int i;
 
10186
    apr_status_t rv;
 
10187
    WSGIThreadStack *stack = wsgi_worker_stack;
 
10188
 
 
10189
    while (1) {
 
10190
        apr_uint32_t state = stack->state;
 
10191
        if (apr_atomic_cas32(&(stack->state), state | WSGI_STACK_TERMINATED,
 
10192
                           state) == state) {
 
10193
            break;
 
10194
        }
 
10195
    }
 
10196
    for (i = 0; i < wsgi_daemon_process->group->threads; i++) {
 
10197
        if ((rv = wsgi_worker_release()) != APR_SUCCESS) {
 
10198
            return rv;
 
10199
        }
 
10200
    }
 
10201
    return APR_SUCCESS;
 
10202
}
 
10203
 
8261
10204
static void wsgi_daemon_worker(apr_pool_t *p, WSGIDaemonThread *thread)
8262
10205
{
8263
10206
    apr_status_t status;
8280
10223
    while (!wsgi_daemon_shutdown) {
8281
10224
        apr_status_t rv;
8282
10225
 
 
10226
        apr_time_t start;
 
10227
        apr_time_t duration;
 
10228
 
8283
10229
        /*
8284
10230
         * Only allow one thread in this process to attempt to
8285
10231
         * acquire the global process lock as the global process
8291
10237
         * GIL contention.
8292
10238
         */
8293
10239
 
8294
 
        apr_thread_mutex_lock(wsgi_daemon_lock);
 
10240
        wsgi_worker_acquire(thread->id);
8295
10241
 
8296
10242
        if (wsgi_daemon_shutdown)
8297
10243
            break;
8351
10297
            if (wsgi_daemon_shutdown) {
8352
10298
                apr_proc_mutex_unlock(group->mutex);
8353
10299
 
8354
 
                apr_thread_mutex_unlock(wsgi_daemon_lock);
 
10300
                wsgi_worker_release();
8355
10301
 
8356
10302
                break;
8357
10303
            }
8398
10344
            if (group->mutex)
8399
10345
                apr_proc_mutex_unlock(group->mutex);
8400
10346
 
8401
 
            apr_thread_mutex_unlock(wsgi_daemon_lock);
 
10347
            wsgi_worker_release();
8402
10348
 
8403
10349
            apr_pool_destroy(ptrans);
8404
10350
 
8409
10355
            if (group->mutex)
8410
10356
                apr_proc_mutex_unlock(group->mutex);
8411
10357
 
8412
 
            apr_thread_mutex_unlock(wsgi_daemon_lock);
 
10358
            wsgi_worker_release();
8413
10359
 
8414
10360
            apr_pool_destroy(ptrans);
8415
10361
 
8425
10371
            rv = apr_proc_mutex_unlock(group->mutex);
8426
10372
            if (rv != APR_SUCCESS) {
8427
10373
                if (!wsgi_daemon_shutdown) {
8428
 
                    apr_thread_mutex_unlock(wsgi_daemon_lock);
 
10374
                    wsgi_worker_release();
 
10375
 
8429
10376
                    ap_log_error(APLOG_MARK, WSGI_LOG_CRIT(rv),
8430
10377
                                 wsgi_server, "mod_wsgi (pid=%d): "
8431
10378
                                 "Couldn't release accept mutex '%s'.",
8432
10379
                                 getpid(), group->socket);
 
10380
 
8433
10381
                    apr_pool_destroy(ptrans);
8434
10382
                    thread->running = 0;
8435
10383
 
8438
10386
            }
8439
10387
        }
8440
10388
 
8441
 
        apr_thread_mutex_unlock(wsgi_daemon_lock);
 
10389
        wsgi_worker_release();
8442
10390
 
8443
10391
        if (status != APR_SUCCESS && APR_STATUS_IS_EINTR(status)) {
8444
10392
            apr_pool_destroy(ptrans);
8481
10429
    WSGIDaemonThread *thread = data;
8482
10430
    apr_pool_t *p = apr_thread_pool_get(thd);
8483
10431
 
 
10432
    apr_thread_mutex_lock(thread->mutex);
 
10433
 
8484
10434
    wsgi_daemon_worker(p, thread);
8485
10435
 
8486
10436
    apr_thread_exit(thd, APR_SUCCESS);
8507
10457
{
8508
10458
    WSGIDaemonProcess *daemon = data;
8509
10459
 
8510
 
    ap_log_error(APLOG_MARK, WSGI_LOG_INFO(0), wsgi_server,
8511
 
                 "mod_wsgi (pid=%d): Enable deadlock thread in "
8512
 
                 "process '%s'.", getpid(), daemon->group->name);
 
10460
    if (wsgi_server_config->verbose_debugging) {
 
10461
        ap_log_error(APLOG_MARK, WSGI_LOG_DEBUG(0), wsgi_server,
 
10462
                     "mod_wsgi (pid=%d): Enable deadlock thread in "
 
10463
                     "process '%s'.", getpid(), daemon->group->name);
 
10464
    }
8513
10465
 
8514
10466
    apr_thread_mutex_lock(wsgi_shutdown_lock);
8515
10467
    wsgi_deadlock_shutdown_time = apr_time_now();
8535
10487
{
8536
10488
    WSGIDaemonProcess *daemon = data;
8537
10489
 
8538
 
    ap_log_error(APLOG_MARK, WSGI_LOG_INFO(0), wsgi_server,
8539
 
                 "mod_wsgi (pid=%d): Enable monitor thread in "
8540
 
                 "process '%s'.", getpid(), daemon->group->name);
 
10490
    if (wsgi_server_config->verbose_debugging) {
 
10491
        ap_log_error(APLOG_MARK, WSGI_LOG_DEBUG(0), wsgi_server,
 
10492
                     "mod_wsgi (pid=%d): Enable monitor thread in "
 
10493
                     "process '%s'.", getpid(), daemon->group->name);
8541
10494
 
8542
 
    ap_log_error(APLOG_MARK, WSGI_LOG_DEBUG(0), wsgi_server,
8543
 
                 "mod_wsgi (pid=%d): Deadlock timeout is %d.",
8544
 
                 getpid(), (int)(apr_time_sec(wsgi_deadlock_timeout)));
8545
 
    ap_log_error(APLOG_MARK, WSGI_LOG_DEBUG(0), wsgi_server,
8546
 
                 "mod_wsgi (pid=%d): Inactivity timeout is %d.",
8547
 
                 getpid(), (int)(apr_time_sec(wsgi_inactivity_timeout)));
 
10495
        ap_log_error(APLOG_MARK, WSGI_LOG_DEBUG(0), wsgi_server,
 
10496
                     "mod_wsgi (pid=%d): Deadlock timeout is %d.",
 
10497
                     getpid(), (int)(apr_time_sec(wsgi_deadlock_timeout)));
 
10498
        ap_log_error(APLOG_MARK, WSGI_LOG_DEBUG(0), wsgi_server,
 
10499
                     "mod_wsgi (pid=%d): Inactivity timeout is %d.",
 
10500
                     getpid(), (int)(apr_time_sec(wsgi_inactivity_timeout)));
 
10501
    }
8548
10502
 
8549
10503
    while (1) {
8550
10504
        apr_time_t now;
8613
10567
 
8614
10568
static void wsgi_daemon_main(apr_pool_t *p, WSGIDaemonProcess *daemon)
8615
10569
{
8616
 
    WSGIDaemonThread *threads;
8617
10570
    apr_threadattr_t *thread_attr;
8618
10571
    apr_thread_t *reaper = NULL;
8619
10572
 
8694
10647
                               daemon, p);
8695
10648
    }
8696
10649
 
 
10650
    /* Initialise worker stack. */
 
10651
 
 
10652
    wsgi_worker_stack = (WSGIThreadStack *)apr_palloc(p,
 
10653
            sizeof(WSGIThreadStack));
 
10654
    wsgi_worker_stack->state = WSGI_STACK_NO_LISTENER | WSGI_STACK_LAST;
 
10655
 
8697
10656
    /* Start the required number of threads. */
8698
10657
 
8699
 
    threads = (WSGIDaemonThread *)apr_pcalloc(p, daemon->group->threads
8700
 
                                              * sizeof(WSGIDaemonThread));
 
10658
    wsgi_worker_threads = (WSGIDaemonThread *)apr_pcalloc(p,
 
10659
                           daemon->group->threads * sizeof(WSGIDaemonThread));
8701
10660
 
8702
 
    ap_log_error(APLOG_MARK, WSGI_LOG_DEBUG(0), wsgi_server,
8703
 
                 "mod_wsgi (pid=%d): Starting %d threads in daemon "
8704
 
                 "process '%s'.", getpid(), daemon->group->threads,
8705
 
                 daemon->group->name);
 
10661
    if (wsgi_server_config->verbose_debugging) {
 
10662
        ap_log_error(APLOG_MARK, WSGI_LOG_DEBUG(0), wsgi_server,
 
10663
                     "mod_wsgi (pid=%d): Starting %d threads in daemon "
 
10664
                     "process '%s'.", getpid(), daemon->group->threads,
 
10665
                     daemon->group->name);
 
10666
    }
8706
10667
 
8707
10668
    for (i=0; i<daemon->group->threads; i++) {
8708
 
        ap_log_error(APLOG_MARK, WSGI_LOG_DEBUG(0), wsgi_server,
8709
 
                     "mod_wsgi (pid=%d): Starting thread %d in daemon "
8710
 
                     "process '%s'.", getpid(), i+1, daemon->group->name);
8711
 
 
8712
 
        threads[i].process = daemon;
8713
 
        threads[i].running = 0;
8714
 
 
8715
 
        rv = apr_thread_create(&threads[i].thread, thread_attr,
8716
 
                               wsgi_daemon_thread, &threads[i], p);
 
10669
        WSGIDaemonThread *thread = &wsgi_worker_threads[i];
 
10670
 
 
10671
        if (wsgi_server_config->verbose_debugging) {
 
10672
            ap_log_error(APLOG_MARK, WSGI_LOG_DEBUG(0), wsgi_server,
 
10673
                         "mod_wsgi (pid=%d): Starting thread %d in daemon "
 
10674
                         "process '%s'.", getpid(), i+1, daemon->group->name);
 
10675
        }
 
10676
 
 
10677
        /* Create the mutex and condition variable for this thread. */
 
10678
 
 
10679
        rv = apr_thread_cond_create(&thread->condition, p);
 
10680
 
 
10681
        if (rv != APR_SUCCESS) {
 
10682
            ap_log_error(APLOG_MARK, WSGI_LOG_ALERT(rv), wsgi_server,
 
10683
                         "mod_wsgi (pid=%d): Couldn't create worker "
 
10684
                         "thread %d state condition variable in daemon "
 
10685
                         "process '%s'.", getpid(), i, daemon->group->name);
 
10686
 
 
10687
            /*
 
10688
             * Try to force an exit of the process if fail
 
10689
             * to create the worker threads.
 
10690
             */
 
10691
 
 
10692
            kill(getpid(), SIGTERM);
 
10693
            sleep(5);
 
10694
        }
 
10695
 
 
10696
        rv = apr_thread_mutex_create(&thread->mutex,
 
10697
                                     APR_THREAD_MUTEX_DEFAULT, p);
 
10698
 
 
10699
        if (rv != APR_SUCCESS) {
 
10700
            ap_log_error(APLOG_MARK, WSGI_LOG_ALERT(rv), wsgi_server,
 
10701
                         "mod_wsgi (pid=%d): Couldn't create worker "
 
10702
                         "thread %d state mutex variable in daemon "
 
10703
                         "process '%s'.", getpid(), i, daemon->group->name);
 
10704
 
 
10705
            /*
 
10706
             * Try to force an exit of the process if fail
 
10707
             * to create the worker threads.
 
10708
             */
 
10709
 
 
10710
            kill(getpid(), SIGTERM);
 
10711
            sleep(5);
 
10712
        }
 
10713
 
 
10714
        /* Now create the actual thread. */
 
10715
 
 
10716
        thread->id = i;
 
10717
        thread->process = daemon;
 
10718
        thread->running = 0;
 
10719
 
 
10720
        rv = apr_thread_create(&thread->thread, thread_attr,
 
10721
                               wsgi_daemon_thread, thread, p);
8717
10722
 
8718
10723
        if (rv != APR_SUCCESS) {
8719
10724
            ap_log_error(APLOG_MARK, WSGI_LOG_ALERT(rv), wsgi_server,
8737
10742
        rv = apr_poll(&poll_fd, 1, &poll_count, -1);
8738
10743
    } while (APR_STATUS_IS_EINTR(rv));
8739
10744
 
 
10745
    if (wsgi_cpu_time_limit_exceeded) {
 
10746
        ap_log_error(APLOG_MARK, WSGI_LOG_INFO(0), wsgi_server,
 
10747
                     "mod_wsgi (pid=%d): Exceeded CPU time limit '%s'.",
 
10748
                     getpid(), daemon->group->name);
 
10749
    }
 
10750
 
8740
10751
    ap_log_error(APLOG_MARK, WSGI_LOG_INFO(0), wsgi_server,
8741
10752
                 "mod_wsgi (pid=%d): Shutdown requested '%s'.",
8742
10753
                 getpid(), daemon->group->name);
8770
10781
     * cut off or lost.
8771
10782
     */
8772
10783
 
 
10784
    wsgi_worker_shutdown();
 
10785
 
8773
10786
    for (i=0; i<daemon->group->threads; i++) {
8774
 
        if (threads[i].thread && threads[i].running) {
8775
 
            rv = apr_thread_join(&thread_rv, threads[i].thread);
 
10787
        if (wsgi_worker_threads[i].thread && wsgi_worker_threads[i].running) {
 
10788
            rv = apr_thread_join(&thread_rv, wsgi_worker_threads[i].thread);
8776
10789
            if (rv != APR_SUCCESS) {
8777
10790
                ap_log_error(APLOG_MARK, WSGI_LOG_CRIT(rv), wsgi_server,
8778
10791
                             "mod_wsgi (pid=%d): Couldn't join with "
8862
10875
 
8863
10876
        wsgi_setup_daemon_name(daemon, p);
8864
10877
 
 
10878
        /* Adjust CPU priority if overridden. */
 
10879
 
 
10880
        if (daemon->group->cpu_priority != 0) {
 
10881
            if (setpriority(PRIO_PROCESS, 0,
 
10882
                            daemon->group->cpu_priority) == -1) {
 
10883
                ap_log_error(APLOG_MARK, WSGI_LOG_ERR(errno), wsgi_server,
 
10884
                             "mod_wsgi (pid=%d): Couldn't set CPU priority "
 
10885
                             "in daemon process '%d'.", getpid(),
 
10886
                             daemon->group->cpu_priority);
 
10887
            }
 
10888
        }
 
10889
 
8865
10890
        /* Setup daemon process user/group/umask etc. */
8866
10891
 
8867
10892
        wsgi_setup_access(daemon);
8969
10994
 
8970
10995
        apr_signal(SIGINT, wsgi_signal_handler);
8971
10996
        apr_signal(SIGTERM, wsgi_signal_handler);
 
10997
#ifdef SIGXCPU
 
10998
        apr_signal(SIGXCPU, wsgi_signal_handler);
 
10999
#endif
 
11000
 
 
11001
        /* Set limits on amount of CPU time that can be used. */
 
11002
 
 
11003
        if (daemon->group->cpu_time_limit > 0) {
 
11004
            struct rlimit limit;
 
11005
 
 
11006
            limit.rlim_cur = daemon->group->cpu_time_limit;
 
11007
 
 
11008
            limit.rlim_max = daemon->group->cpu_time_limit + 1;
 
11009
            limit.rlim_max += daemon->group->shutdown_timeout;
 
11010
 
 
11011
            if (setrlimit(RLIMIT_CPU, &limit) == -1) {
 
11012
                ap_log_error(APLOG_MARK, WSGI_LOG_CRIT(0), wsgi_server,
 
11013
                             "mod_wsgi (pid=%d): Couldn't set CPU time "
 
11014
                             "limit of %d seconds for process '%s'.", getpid(),
 
11015
                             daemon->group->cpu_time_limit,
 
11016
                             daemon->group->name);
 
11017
            }
 
11018
        }
8972
11019
 
8973
11020
        /*
8974
11021
         * Flag whether multiple daemon processes or denoted
8987
11034
        apr_pool_create(&wsgi_daemon_pool, p);
8988
11035
 
8989
11036
        /*
 
11037
         * Initialise Python if required to be done in the child
 
11038
         * process. Note that it will not be initialised if
 
11039
         * mod_python loaded and it has already been done.
 
11040
         */
 
11041
 
 
11042
        if (wsgi_python_after_fork)
 
11043
            wsgi_python_init(p);
 
11044
 
 
11045
        /*
8990
11046
         * If mod_python is also being loaded and thus it was
8991
11047
         * responsible for initialising Python it can leave in
8992
11048
         * place an active thread state. Under normal conditions
9013
11069
        }
9014
11070
 
9015
11071
        /*
 
11072
         * If the daemon is associated with a virtual host then
 
11073
         * we can close all other error logs so long as they
 
11074
         * aren't the same one as being used for the virtual
 
11075
         * host. If the virtual host error log is different to
 
11076
         * the main server error log, then also tie stderr to
 
11077
         * that log file instead. This way any debugging sent
 
11078
         * direct to stderr from C code also goes to the virtual
 
11079
         * host error log. We close the error logs that aren't
 
11080
         * required as that eliminates possibility that user
 
11081
         * code executing in daemon process could maliciously
 
11082
         * dump messages into error log for a different virtual
 
11083
         * host, as well as stop them being reopened with mode
 
11084
         * that would allow seeking back to start of file and
 
11085
         * read any information in them.
 
11086
         */
 
11087
 
 
11088
        if (daemon->group->server->is_virtual) {
 
11089
            server_rec *server = NULL;
 
11090
            apr_file_t *errfile = NULL;
 
11091
 
 
11092
            /*
 
11093
             * Iterate over all servers and close any error
 
11094
             * logs different to that for virtual host. Note that
 
11095
             * if errors are being redirected to syslog, then
 
11096
             * the server error log reference will actually be
 
11097
             * a null pointer, so need to ensure that check for
 
11098
             * that and don't attempt to close it in that case.
 
11099
             */
 
11100
 
 
11101
            server = wsgi_server;
 
11102
 
 
11103
            while (server != NULL) {
 
11104
                if (server->error_log &&
 
11105
                    server->error_log != daemon->group->server->error_log) {
 
11106
                    apr_file_close(server->error_log);
 
11107
                }
 
11108
 
 
11109
                server = server->next;
 
11110
            }
 
11111
 
 
11112
            /*
 
11113
            * Reassociate stderr output with error log from the
 
11114
            * virtual host the daemon is associated with. Close
 
11115
            * the virtual host error log and point it at stderr
 
11116
            * log instead. Do the latter so don't get two
 
11117
            * references to same open file. Just in case
 
11118
            * anything still accesses error log of main server,
 
11119
            * map main server error log to that of the virtual
 
11120
            * host. Note that cant do this if errors are being
 
11121
            * redirected to syslog, as indicated by virtual
 
11122
            * host error log being a null pointer. In that case
 
11123
            * just leave everything as it was. Also can't remap
 
11124
            * the error log for main server if it was being
 
11125
            * redirected to syslog but virtual host wasn't.
 
11126
             */
 
11127
 
 
11128
            if (daemon->group->server->error_log  &&
 
11129
                daemon->group->server->error_log != wsgi_server->error_log) {
 
11130
                apr_file_open_stderr(&errfile, wsgi_server->process->pool);
 
11131
                apr_file_dup2(errfile, daemon->group->server->error_log,
 
11132
                              wsgi_server->process->pool);
 
11133
 
 
11134
                apr_file_close(daemon->group->server->error_log);
 
11135
                daemon->group->server->error_log = errfile;
 
11136
 
 
11137
                if (wsgi_server->error_log)
 
11138
                    wsgi_server->error_log = daemon->group->server->error_log;
 
11139
            }
 
11140
        }
 
11141
 
 
11142
        /*
9016
11143
         * Update reference to server object in case daemon
9017
11144
         * process is actually associated with a virtual host.
9018
11145
         * This way all logging actually goes into the virtual
9019
11146
         * hosts log file.
9020
11147
         */
9021
11148
 
9022
 
        wsgi_server = daemon->group->server;
 
11149
        if (daemon->group->server) {
 
11150
            if (wsgi_server_config->verbose_debugging) {
 
11151
                ap_log_error(APLOG_MARK, WSGI_LOG_DEBUG(0), wsgi_server,
 
11152
                             "mod_wsgi (pid=%d): Process '%s' logging to "
 
11153
                             "'%s' with log level %d.", getpid(),
 
11154
                             daemon->group->name,
 
11155
                             daemon->group->server->server_hostname,
 
11156
                             daemon->group->server->loglevel);
 
11157
            }
 
11158
 
 
11159
            wsgi_server = daemon->group->server;
 
11160
        }
 
11161
        else {
 
11162
            if (wsgi_server_config->verbose_debugging) {
 
11163
                ap_log_error(APLOG_MARK, WSGI_LOG_DEBUG(0), wsgi_server,
 
11164
                             "mod_wsgi (pid=%d): Process '%s' forced to log "
 
11165
                             "to '%s' with log level %d.", getpid(),
 
11166
                             daemon->group->name, wsgi_server->server_hostname,
 
11167
                             wsgi_server->loglevel);
 
11168
            }
 
11169
        }
9023
11170
 
9024
11171
        /* Retain a reference to daemon process details. */
9025
11172
 
9049
11196
 
9050
11197
        apr_os_sock_put(&daemon->listener, &daemon->group->listener_fd, p);
9051
11198
 
9052
 
        apr_thread_mutex_create(&wsgi_daemon_lock,
9053
 
                                APR_THREAD_MUTEX_UNNESTED, p);
9054
 
 
9055
11199
        /* Run the main routine for the daemon process. */
9056
11200
 
9057
11201
        wsgi_daemon_main(p, daemon);
9085
11229
    WSGIProcessGroup *entry = NULL;
9086
11230
    WSGIDaemonProcess *process = NULL;
9087
11231
 
 
11232
    int mpm_generation = 0;
 
11233
 
9088
11234
    int i, j;
9089
11235
 
9090
11236
    /* Do we need to create any daemon processes. */
9092
11238
    if (!wsgi_daemon_list)
9093
11239
        return OK;
9094
11240
 
 
11241
    /* What server generation is this. */
 
11242
 
 
11243
#if defined(AP_MPMQ_GENERATION)
 
11244
    ap_mpm_query(AP_MPMQ_GENERATION, &mpm_generation);
 
11245
#else
 
11246
    mpm_generation = ap_my_generation;
 
11247
#endif
 
11248
 
9095
11249
    /*
9096
11250
     * Cache references to root server and pool as will need
9097
11251
     * to access these when restarting daemon process when
9127
11281
         */
9128
11282
 
9129
11283
        if (entry->uid == ap_uname2id(DEFAULT_USER)) {
9130
 
            entry->uid = unixd_config.user_id;
9131
 
            entry->user = unixd_config.user_name;
 
11284
            entry->uid = ap_unixd_config.user_id;
 
11285
            entry->user = ap_unixd_config.user_name;
9132
11286
 
9133
11287
            ap_log_error(APLOG_MARK, WSGI_LOG_DEBUG(0), wsgi_server,
9134
11288
                         "mod_wsgi (pid=%d): Reset default user for "
9137
11291
        }
9138
11292
 
9139
11293
        if (entry->gid == ap_gname2id(DEFAULT_GROUP)) {
9140
 
            entry->gid = unixd_config.group_id;
 
11294
            entry->gid = ap_unixd_config.group_id;
9141
11295
 
9142
11296
            ap_log_error(APLOG_MARK, WSGI_LOG_DEBUG(0), wsgi_server,
9143
11297
                         "mod_wsgi (pid=%d): Reset default group for "
9152
11306
 
9153
11307
        entry->socket = apr_psprintf(p, "%s.%d.%d.%d.sock",
9154
11308
                                     wsgi_server_config->socket_prefix,
9155
 
                                     getpid(), ap_my_generation, entry->id);
 
11309
                                     getpid(), mpm_generation, entry->id);
9156
11310
 
9157
11311
        apr_hash_set(wsgi_daemon_index, entry->name, APR_HASH_KEY_STRING,
9158
11312
                     entry);
9180
11334
        if (entry->processes > 1) {
9181
11335
            entry->mutex_path = apr_psprintf(p, "%s.%d.%d.%d.lock",
9182
11336
                                             wsgi_server_config->socket_prefix,
9183
 
                                             getpid(), ap_my_generation,
 
11337
                                             getpid(), mpm_generation,
9184
11338
                                             entry->id);
9185
11339
 
9186
11340
            status = apr_proc_mutex_create(&entry->mutex, entry->mutex_path,
9428
11582
    return APR_SUCCESS;
9429
11583
}
9430
11584
 
 
11585
static void wsgi_discard_output(apr_bucket_brigade *bb)
 
11586
{
 
11587
    apr_bucket *e;
 
11588
    const char *buf;
 
11589
    apr_size_t len;
 
11590
    apr_status_t rv;
 
11591
 
 
11592
    for (e = APR_BRIGADE_FIRST(bb);
 
11593
         e != APR_BRIGADE_SENTINEL(bb);
 
11594
         e = APR_BUCKET_NEXT(e))
 
11595
    {
 
11596
        if (APR_BUCKET_IS_EOS(e)) {
 
11597
            break;
 
11598
        }
 
11599
        rv = apr_bucket_read(e, &buf, &len, APR_BLOCK_READ);
 
11600
        if (rv != APR_SUCCESS) {
 
11601
            break;
 
11602
        }
 
11603
    }
 
11604
}
 
11605
 
9431
11606
static int wsgi_execute_remote(request_rec *r)
9432
11607
{
9433
11608
    WSGIRequestConfig *config = NULL;
9435
11610
    WSGIProcessGroup *group = NULL;
9436
11611
 
9437
11612
    char *key = NULL;
9438
 
    char const *hash = NULL;
 
11613
    const char *hash = NULL;
9439
11614
 
9440
11615
    int status;
9441
11616
    apr_status_t rv;
9448
11623
    apr_bucket_brigade *bbin;
9449
11624
    apr_bucket *b;
9450
11625
 
 
11626
    const char *location = NULL;
 
11627
 
9451
11628
    /* Grab request configuration. */
9452
11629
 
9453
11630
    config = (WSGIRequestConfig *)ap_get_module_config(r->request_config,
9520
11697
    }
9521
11698
 
9522
11699
    /*
 
11700
     * Check restrictions related to the group of the WSGI
 
11701
     * script file and who has write access to the directory it
 
11702
     * is contained in. If not satisfied forbid access.
 
11703
     */
 
11704
 
 
11705
    if (group->script_group) {
 
11706
        apr_uid_t gid;
 
11707
        struct group *grent = NULL;
 
11708
        const char *grname = NULL;
 
11709
        apr_finfo_t finfo;
 
11710
        const char *path = NULL;
 
11711
 
 
11712
        if (!(r->finfo.valid & APR_FINFO_GROUP)) {
 
11713
            wsgi_log_script_error(r, apr_psprintf(r->pool, "Group "
 
11714
                                  "information not available for WSGI "
 
11715
                                  "script file"), r->filename);
 
11716
            return HTTP_FORBIDDEN;
 
11717
        }
 
11718
 
 
11719
        gid = r->finfo.group;
 
11720
 
 
11721
        if ((grent = getgrgid(gid)) == NULL) {
 
11722
            wsgi_log_script_error(r, apr_psprintf(r->pool, "Couldn't "
 
11723
                                  "determine group of WSGI script file, "
 
11724
                                  "gid=%ld", (long)gid), r->filename);
 
11725
            return HTTP_FORBIDDEN;
 
11726
        }
 
11727
 
 
11728
        grname = grent->gr_name;
 
11729
 
 
11730
        if (strcmp(group->script_group, grname)) {
 
11731
            wsgi_log_script_error(r, apr_psprintf(r->pool, "Group of WSGI "
 
11732
                                  "script file does not match required group "
 
11733
                                  "for daemon process, group=%s", grname),
 
11734
                                  r->filename);
 
11735
            return HTTP_FORBIDDEN;
 
11736
        }
 
11737
 
 
11738
        if (!(r->finfo.valid & APR_FINFO_WPROT)) {
 
11739
            wsgi_log_script_error(r, apr_psprintf(r->pool, "World "
 
11740
                                  "permissions not available for WSGI "
 
11741
                                  "script file"), r->filename);
 
11742
            return HTTP_FORBIDDEN;
 
11743
        }
 
11744
 
 
11745
        if (r->finfo.protection & APR_FPROT_WWRITE) {
 
11746
            wsgi_log_script_error(r, apr_psprintf(r->pool, "WSGI script "
 
11747
                                  "file is writable to world"), r->filename);
 
11748
            return HTTP_FORBIDDEN;
 
11749
        }
 
11750
 
 
11751
        path = ap_make_dirstr_parent(r->pool, r->filename);
 
11752
 
 
11753
        if (apr_stat(&finfo, path, APR_FINFO_NORM, r->pool) != APR_SUCCESS) {
 
11754
            wsgi_log_script_error(r, apr_psprintf(r->pool, "Unable to stat "
 
11755
                                  "parent directory of WSGI script"), path);
 
11756
            return HTTP_FORBIDDEN;
 
11757
        }
 
11758
 
 
11759
        gid = finfo.group;
 
11760
 
 
11761
        if ((grent = getgrgid(gid)) == NULL) {
 
11762
            wsgi_log_script_error(r, apr_psprintf(r->pool, "Couldn't "
 
11763
                                  "determine group of parent directory of "
 
11764
                                  "WSGI script file, gid=%ld", (long)gid),
 
11765
                                  r->filename);
 
11766
            return HTTP_FORBIDDEN;
 
11767
        }
 
11768
 
 
11769
        grname = grent->gr_name;
 
11770
 
 
11771
        if (strcmp(group->script_group, grname)) {
 
11772
            wsgi_log_script_error(r, apr_psprintf(r->pool, "Group of parent "
 
11773
                                  "directory of WSGI script file does not "
 
11774
                                  "match required group for daemon process, "
 
11775
                                  "group=%s", grname), r->filename);
 
11776
            return HTTP_FORBIDDEN;
 
11777
        }
 
11778
 
 
11779
        if (finfo.protection & APR_FPROT_WWRITE) {
 
11780
            wsgi_log_script_error(r, apr_psprintf(r->pool, "Parent directory "
 
11781
                                  "of WSGI script file is writable to world"),
 
11782
                                  r->filename);
 
11783
            return HTTP_FORBIDDEN;
 
11784
        }
 
11785
    }
 
11786
 
 
11787
    /*
 
11788
     * Check restrictions related to who can be the owner of
 
11789
     * the WSGI script file and who has write access to the
 
11790
     * directory it is contained in. If not satisfied forbid
 
11791
     * access.
 
11792
     */
 
11793
 
 
11794
    if (group->script_user) {
 
11795
        apr_uid_t uid;
 
11796
        struct passwd *pwent = NULL;
 
11797
        const char *pwname = NULL;
 
11798
        apr_finfo_t finfo;
 
11799
        const char *path = NULL;
 
11800
 
 
11801
        if (!(r->finfo.valid & APR_FINFO_USER)) {
 
11802
            wsgi_log_script_error(r, apr_psprintf(r->pool, "User "
 
11803
                                  "information not available for WSGI "
 
11804
                                  "script file"), r->filename);
 
11805
            return HTTP_FORBIDDEN;
 
11806
        }
 
11807
 
 
11808
        uid = r->finfo.user;
 
11809
 
 
11810
        if ((pwent = getpwuid(uid)) == NULL) {
 
11811
            wsgi_log_script_error(r, apr_psprintf(r->pool, "Couldn't "
 
11812
                                  "determine owner of WSGI script file, "
 
11813
                                  "uid=%ld", (long)uid), r->filename);
 
11814
            return HTTP_FORBIDDEN;
 
11815
        }
 
11816
 
 
11817
        pwname = pwent->pw_name;
 
11818
 
 
11819
        if (strcmp(group->script_user, pwname)) {
 
11820
            wsgi_log_script_error(r, apr_psprintf(r->pool, "Owner of WSGI "
 
11821
                                  "script file does not match required user "
 
11822
                                  "for daemon process, user=%s", pwname),
 
11823
                                  r->filename);
 
11824
            return HTTP_FORBIDDEN;
 
11825
        }
 
11826
 
 
11827
        if (!(r->finfo.valid & APR_FINFO_GPROT)) {
 
11828
            wsgi_log_script_error(r, apr_psprintf(r->pool, "Group "
 
11829
                                  "permissions not available for WSGI "
 
11830
                                  "script file"), r->filename);
 
11831
            return HTTP_FORBIDDEN;
 
11832
        }
 
11833
 
 
11834
        if (r->finfo.protection & APR_FPROT_GWRITE) {
 
11835
            wsgi_log_script_error(r, apr_psprintf(r->pool, "WSGI script "
 
11836
                                  "file is writable to group"), r->filename);
 
11837
            return HTTP_FORBIDDEN;
 
11838
        }
 
11839
 
 
11840
        if (!(r->finfo.valid & APR_FINFO_WPROT)) {
 
11841
            wsgi_log_script_error(r, apr_psprintf(r->pool, "World "
 
11842
                                  "permissions not available for WSGI "
 
11843
                                  "script file"), r->filename);
 
11844
            return HTTP_FORBIDDEN;
 
11845
        }
 
11846
 
 
11847
        if (r->finfo.protection & APR_FPROT_WWRITE) {
 
11848
            wsgi_log_script_error(r, apr_psprintf(r->pool, "WSGI script "
 
11849
                                  "file is writable to world"), r->filename);
 
11850
            return HTTP_FORBIDDEN;
 
11851
        }
 
11852
 
 
11853
        path = ap_make_dirstr_parent(r->pool, r->filename);
 
11854
 
 
11855
        if (apr_stat(&finfo, path, APR_FINFO_NORM, r->pool) != APR_SUCCESS) {
 
11856
            wsgi_log_script_error(r, apr_psprintf(r->pool, "Unable to stat "
 
11857
                                  "parent directory of WSGI script"), path);
 
11858
            return HTTP_FORBIDDEN;
 
11859
        }
 
11860
 
 
11861
        uid = finfo.user;
 
11862
 
 
11863
        if ((pwent = getpwuid(uid)) == NULL) {
 
11864
            wsgi_log_script_error(r, apr_psprintf(r->pool, "Couldn't "
 
11865
                                  "determine owner of parent directory of "
 
11866
                                  "WSGI script file, uid=%ld", (long)uid),
 
11867
                                  r->filename);
 
11868
            return HTTP_FORBIDDEN;
 
11869
        }
 
11870
 
 
11871
        pwname = pwent->pw_name;
 
11872
 
 
11873
        if (strcmp(group->script_user, pwname)) {
 
11874
            wsgi_log_script_error(r, apr_psprintf(r->pool, "Owner of parent "
 
11875
                                  "directory of WSGI script file does not "
 
11876
                                  "match required user for daemon process, "
 
11877
                                  "user=%s", pwname), r->filename);
 
11878
            return HTTP_FORBIDDEN;
 
11879
        }
 
11880
 
 
11881
        if (finfo.protection & APR_FPROT_WWRITE) {
 
11882
            wsgi_log_script_error(r, apr_psprintf(r->pool, "Parent directory "
 
11883
                                  "of WSGI script file is writable to world"),
 
11884
                                  r->filename);
 
11885
            return HTTP_FORBIDDEN;
 
11886
        }
 
11887
 
 
11888
        if (finfo.protection & APR_FPROT_GWRITE) {
 
11889
            wsgi_log_script_error(r, apr_psprintf(r->pool, "Parent directory "
 
11890
                                  "of WSGI script file is writable to group"),
 
11891
                                  r->filename);
 
11892
            return HTTP_FORBIDDEN;
 
11893
        }
 
11894
    }
 
11895
 
 
11896
    /*
9523
11897
     * Add magic marker into request environment so that daemon
9524
11898
     * process can verify that request is from a sender that can
9525
11899
     * be trusted. Wipe out original key to make it a bit harder
9527
11901
     * memory looking for unhashed string.
9528
11902
     */
9529
11903
 
9530
 
    key = apr_psprintf(r->pool, "%ld|%s|%s", group->random,
9531
 
                       group->socket, r->filename);
 
11904
    key = apr_psprintf(r->pool, "%ld|%s|%s|%s", group->random,
 
11905
                       group->socket, r->filename, config->handler_script);
9532
11906
    hash = ap_md5(r->pool, (const unsigned char *)key);
9533
11907
    memset(key, '\0', strlen(key));
9534
11908
 
9547
11921
 
9548
11922
    /* Send request details and subprocess environment. */
9549
11923
 
 
11924
    if (wsgi_server_config->verbose_debugging) {
 
11925
        ap_log_error(APLOG_MARK, WSGI_LOG_DEBUG(0), wsgi_server,
 
11926
                     "mod_wsgi (pid=%d): Request server was "
 
11927
                     "'%s|%d'.", getpid(), r->server->server_hostname,
 
11928
                     r->server->port);
 
11929
    }
 
11930
 
9550
11931
    if ((rv = wsgi_send_request(r, config, daemon)) != APR_SUCCESS) {
9551
11932
        ap_log_rerror(APLOG_MARK, WSGI_LOG_ERR(rv), r,
9552
11933
                     "mod_wsgi (pid=%d): Unable to send request details "
9586
11967
     * therefore create a connection to daemon process again.
9587
11968
     */
9588
11969
 
9589
 
    if (*config->process_group &&
9590
 
        config->reload_mechanism == WSGI_RELOAD_PROCESS) {
9591
 
 
 
11970
    if (*config->process_group) {
9592
11971
        int retries = 0;
9593
11972
        int maximum = (2*group->processes)+1;
9594
11973
 
9678
12057
        }
9679
12058
    }
9680
12059
 
 
12060
 
9681
12061
    /*
9682
12062
     * Need to reset request status value to HTTP_OK else it
9683
12063
     * screws up HTTP input filter when processing a POST
9772
12152
    if (r->status == 0)
9773
12153
        return HTTP_INTERNAL_SERVER_ERROR;
9774
12154
 
 
12155
    /*
 
12156
     * Look for 'Location' header and if an internal
 
12157
     * redirect, execute the redirect. This behaviour is
 
12158
     * consistent with how mod_cgi and mod_cgid work and
 
12159
     * what is permitted by the CGI specification.
 
12160
     */
 
12161
 
 
12162
    location = apr_table_get(r->headers_out, "Location");
 
12163
 
 
12164
    if (location && location[0] == '/' && r->status == 200) {
 
12165
        /*
 
12166
         * Discard all response content returned from
 
12167
         * the daemon process.
 
12168
         */
 
12169
 
 
12170
        wsgi_discard_output(bbin);
 
12171
        apr_brigade_destroy(bbin);
 
12172
 
 
12173
        /*
 
12174
         * The internal redirect needs to be a GET no
 
12175
         * matter what the original method was.
 
12176
         */
 
12177
 
 
12178
        r->method = apr_pstrdup(r->pool, "GET");
 
12179
        r->method_number = M_GET;
 
12180
 
 
12181
        /*
 
12182
         * We already read the message body (if any), so
 
12183
         * don't allow the redirected request to think
 
12184
         * it has one. Not sure if we need to worry
 
12185
         * about removing 'Transfer-Encoding' header.
 
12186
         */
 
12187
 
 
12188
        apr_table_unset(r->headers_in, "Content-Length");
 
12189
 
 
12190
        ap_internal_redirect_handler(location, r);
 
12191
 
 
12192
        return OK;
 
12193
    }
 
12194
 
 
12195
    /*
 
12196
     * Allow the web server to override any error
 
12197
     * page produced by the WSGI application.
 
12198
     */
 
12199
 
 
12200
    if (config->error_override && ap_is_HTTP_ERROR(r->status)) {
 
12201
        status = r->status;
 
12202
 
 
12203
        r->status = HTTP_OK;
 
12204
        r->status_line = NULL;
 
12205
 
 
12206
        /*
 
12207
         * Discard all response content returned from
 
12208
         * the daemon process if any expected.
 
12209
         */
 
12210
 
 
12211
        if (!r->header_only && /* not HEAD request */
 
12212
            (status != HTTP_NO_CONTENT) && /* not 204 */
 
12213
            (status != HTTP_NOT_MODIFIED)) { /* not 304 */
 
12214
            wsgi_discard_output(bbin);
 
12215
            apr_brigade_destroy(bbin);
 
12216
        }
 
12217
 
 
12218
        return status;
 
12219
    }
 
12220
 
9775
12221
    /* Transfer any response content. */
9776
12222
 
9777
12223
    ap_pass_brigade(r->output_filters, bbin);
9956
12402
    char *key;
9957
12403
    apr_sockaddr_t *addr;
9958
12404
 
9959
 
    char const *magic;
9960
 
    char const *hash;
 
12405
    const char *filename;
 
12406
    const char *script;
 
12407
    const char *magic;
 
12408
    const char *hash;
9961
12409
 
9962
12410
    WSGIRequestConfig *config;
9963
12411
 
9969
12417
    ap_filter_t *current = NULL;
9970
12418
    ap_filter_t *next = NULL;
9971
12419
 
 
12420
    const apr_array_header_t *head = NULL;
 
12421
    const apr_table_entry_t *elts = NULL;
 
12422
 
 
12423
    int i = 0;
 
12424
 
 
12425
    const char *item;
 
12426
 
9972
12427
    /* Don't do anything if not in daemon process. */
9973
12428
 
9974
12429
    if (!wsgi_daemon_pool)
10104
12559
        return HTTP_INTERNAL_SERVER_ERROR;
10105
12560
    }
10106
12561
 
10107
 
    /* Set target of request and recalculate modification time. */
10108
 
 
10109
 
    r->filename = (char *)apr_table_get(r->subprocess_env, "SCRIPT_FILENAME");
10110
 
 
10111
 
    if ((rv = apr_stat(&r->finfo, r->filename, APR_FINFO_NORM,
 
12562
    /* Check magic marker used to validate origin of request. */
 
12563
 
 
12564
    filename = apr_table_get(r->subprocess_env, "SCRIPT_FILENAME");
 
12565
    script = apr_table_get(r->subprocess_env, "mod_wsgi.handler_script");
 
12566
 
 
12567
    magic = apr_table_get(r->subprocess_env, "mod_wsgi.magic");
 
12568
 
 
12569
    if (!magic) {
 
12570
        ap_log_error(APLOG_MARK, WSGI_LOG_ALERT(rv), wsgi_server,
 
12571
                     "mod_wsgi (pid=%d): Request origin could not be "
 
12572
                     "validated.", getpid());
 
12573
 
 
12574
        apr_pool_destroy(p);
 
12575
 
 
12576
        return HTTP_INTERNAL_SERVER_ERROR;
 
12577
    }
 
12578
 
 
12579
    key = apr_psprintf(r->pool, "%ld|%s|%s|%s",
 
12580
                       wsgi_daemon_process->group->random,
 
12581
                       wsgi_daemon_process->group->socket, filename, script);
 
12582
    hash = ap_md5(r->pool, (const unsigned char *)key);
 
12583
    memset(key, '\0', strlen(key));
 
12584
 
 
12585
    if (strcmp(magic, hash) != 0) {
 
12586
        ap_log_error(APLOG_MARK, WSGI_LOG_ALERT(rv), wsgi_server,
 
12587
                     "mod_wsgi (pid=%d): Request origin could not be "
 
12588
                     "validated.", getpid());
 
12589
 
 
12590
        apr_pool_destroy(p);
 
12591
 
 
12592
        return HTTP_INTERNAL_SERVER_ERROR;
 
12593
    }
 
12594
 
 
12595
    apr_table_unset(r->subprocess_env, "mod_wsgi.magic");
 
12596
 
 
12597
    /*
 
12598
     * If we are executing in a chroot environment, we need to
 
12599
     * adjust SCRIPT_FILENAME to remove leading portion of path
 
12600
     * that corresponds to the location of the chroot directory.
 
12601
     * Also need to adjust DOCUMENT_ROOT as well, although in
 
12602
     * that case if it doesn't actually fall within the choot
 
12603
     * directory, we just delete it outright as would be incorrect
 
12604
     * if that directory lay outside of the chroot directory.
 
12605
     */
 
12606
 
 
12607
    if (wsgi_daemon_process->group->root) {
 
12608
        const char *root;
 
12609
        const char *path;
 
12610
 
 
12611
        root = wsgi_daemon_process->group->root;
 
12612
 
 
12613
        path = filename;
 
12614
 
 
12615
        if (strstr(path, root) == path && path[strlen(root)] == '/') {
 
12616
            path += strlen(root);
 
12617
 
 
12618
            apr_table_set(r->subprocess_env, "SCRIPT_FILENAME", path);
 
12619
 
 
12620
            filename = path;
 
12621
        }
 
12622
        else {
 
12623
            ap_log_error(APLOG_MARK, WSGI_LOG_CRIT(rv), wsgi_server,
 
12624
                         "mod_wsgi (pid=%d): WSGI script '%s' not located "
 
12625
                         "within chroot directory '%s'.", getpid(), path, root);
 
12626
 
 
12627
            return HTTP_INTERNAL_SERVER_ERROR;
 
12628
        }
 
12629
 
 
12630
        path = (char *)apr_table_get(r->subprocess_env, "DOCUMENT_ROOT");
 
12631
 
 
12632
        if (strstr(path, root) == path) {
 
12633
            path += strlen(root);
 
12634
 
 
12635
            apr_table_set(r->subprocess_env, "DOCUMENT_ROOT", path);
 
12636
        }
 
12637
        else {
 
12638
            apr_table_unset(r->subprocess_env, "DOCUMENT_ROOT");
 
12639
        }
 
12640
    }
 
12641
 
 
12642
    r->filename = (char *)filename;
 
12643
 
 
12644
    /* Recalculate WSGI script file modification time. */
 
12645
 
 
12646
    if ((rv = apr_stat(&r->finfo, filename, APR_FINFO_NORM,
10112
12647
                       r->pool)) != APR_SUCCESS) {
10113
12648
        /*
10114
12649
         * Don't fail at this point. Allow the lack of file to
10117
12652
 
10118
12653
        ap_log_error(APLOG_MARK, WSGI_LOG_WARNING(rv), wsgi_server,
10119
12654
                     "mod_wsgi (pid=%d): Unable to stat target WSGI script "
10120
 
                     "'%s'.", getpid(), r->filename);
 
12655
                     "'%s'.", getpid(), filename);
10121
12656
 
10122
12657
        r->finfo.mtime = 0;
10123
12658
    }
10124
12659
 
10125
 
    /* Check magic marker used to validate origin of request. */
10126
 
 
10127
 
    magic = apr_table_get(r->subprocess_env, "mod_wsgi.magic");
10128
 
 
10129
 
    if (!magic) {
10130
 
        ap_log_error(APLOG_MARK, WSGI_LOG_ALERT(rv), wsgi_server,
10131
 
                     "mod_wsgi (pid=%d): Request origin could not be "
10132
 
                     "validated.", getpid());
10133
 
 
10134
 
        apr_pool_destroy(p);
10135
 
 
10136
 
        return HTTP_INTERNAL_SERVER_ERROR;
10137
 
    }
10138
 
 
10139
 
    key = apr_psprintf(r->pool, "%ld|%s|%s",
10140
 
                       wsgi_daemon_process->group->random,
10141
 
                       wsgi_daemon_process->group->socket, r->filename);
10142
 
    hash = ap_md5(r->pool, (const unsigned char *)key);
10143
 
    memset(key, '\0', strlen(key));
10144
 
 
10145
 
    if (strcmp(magic, hash) != 0) {
10146
 
        ap_log_error(APLOG_MARK, WSGI_LOG_ALERT(rv), wsgi_server,
10147
 
                     "mod_wsgi (pid=%d): Request origin could not be "
10148
 
                     "validated.", getpid());
10149
 
 
10150
 
        apr_pool_destroy(p);
10151
 
 
10152
 
        return HTTP_INTERNAL_SERVER_ERROR;
10153
 
    }
10154
 
 
10155
 
    apr_table_unset(r->subprocess_env, "mod_wsgi.magic");
10156
 
 
10157
12660
    /*
10158
12661
     * Trigger mapping of host information to server configuration
10159
12662
     * so that when logging errors they go to the correct error log
10169
12672
                       apr_table_get(r->subprocess_env,
10170
12673
                                     "mod_wsgi.listener_port"));
10171
12674
 
 
12675
    if (wsgi_server_config->verbose_debugging) {
 
12676
        ap_log_error(APLOG_MARK, WSGI_LOG_DEBUG(0), wsgi_server,
 
12677
                     "mod_wsgi (pid=%d): Server listener address '%s'.",
 
12678
                     getpid(), key);
 
12679
    }
 
12680
 
10172
12681
    addr = (apr_sockaddr_t *)apr_hash_get(wsgi_daemon_listeners,
10173
12682
                                          key, APR_HASH_KEY_STRING);
10174
12683
 
10175
 
    if (addr)
 
12684
    if (wsgi_server_config->verbose_debugging) {
 
12685
        ap_log_error(APLOG_MARK, WSGI_LOG_DEBUG(0), wsgi_server,
 
12686
                     "mod_wsgi (pid=%d): Server listener address '%s' was"
 
12687
                     "%s found.", getpid(), key, addr ? "" : " not");
 
12688
    }
 
12689
 
 
12690
    if (addr) {
10176
12691
        c->local_addr = addr;
 
12692
    }
10177
12693
 
10178
12694
    ap_update_vhost_given_ip(r->connection);
10179
12695
 
 
12696
    if (wsgi_server_config->verbose_debugging) {
 
12697
        ap_log_error(APLOG_MARK, WSGI_LOG_DEBUG(0), wsgi_server,
 
12698
                     "mod_wsgi (pid=%d): Connection server matched was "
 
12699
                     "'%s|%d'.", getpid(), c->base_server->server_hostname,
 
12700
                     c->base_server->port);
 
12701
    }
 
12702
 
10180
12703
    r->server = c->base_server;
10181
12704
 
10182
12705
    if (apr_table_get(r->subprocess_env, "HTTP_HOST")) {
10186
12709
 
10187
12710
    ap_update_vhost_from_headers(r);
10188
12711
 
 
12712
    if (wsgi_server_config->verbose_debugging) {
 
12713
        ap_log_error(APLOG_MARK, WSGI_LOG_DEBUG(0), wsgi_server,
 
12714
                     "mod_wsgi (pid=%d): Request server matched was '%s|%d'.",
 
12715
                     getpid(), r->server->server_hostname, r->server->port);
 
12716
    }
 
12717
 
10189
12718
    /*
10190
12719
     * Set content length of any request content and add the
10191
12720
     * standard HTTP input filter so that standard input routines
10192
12721
     * for request content will work.
10193
12722
     */
10194
12723
 
10195
 
    if (apr_table_get(r->subprocess_env, "CONTENT_LENGTH")) {
10196
 
        apr_table_setn(r->headers_in, "Content-Length",
10197
 
                       apr_table_get(r->subprocess_env, "CONTENT_LENGTH"));
10198
 
    }
 
12724
    item = apr_table_get(r->subprocess_env, "CONTENT_LENGTH");
 
12725
 
 
12726
    if (item)
 
12727
        apr_table_setn(r->headers_in, "Content-Length", item);
 
12728
 
 
12729
    /* Install the standard HTTP input filter. */
10199
12730
 
10200
12731
    ap_add_input_filter("HTTP_IN", NULL, r, r->connection);
10201
12732
 
10208
12739
    config->callable_object = apr_table_get(r->subprocess_env,
10209
12740
                                            "mod_wsgi.callable_object");
10210
12741
 
 
12742
    config->handler_script = apr_table_get(r->subprocess_env,
 
12743
                                           "mod_wsgi.handler_script");
 
12744
 
10211
12745
    config->script_reloading = atoi(apr_table_get(r->subprocess_env,
10212
12746
                                                  "mod_wsgi.script_reloading"));
10213
 
    config->reload_mechanism = atoi(apr_table_get(r->subprocess_env,
10214
 
                                                  "mod_wsgi.reload_mechanism"));
10215
12747
 
10216
12748
    /*
10217
12749
     * Define how input data is to be processed. This
10224
12756
    ap_setup_client_block(r, REQUEST_CHUNKED_ERROR);
10225
12757
 
10226
12758
    /*
 
12759
     * Where original request used chunked transfer
 
12760
     * encoding, we have to do a further fiddle here and
 
12761
     * make Apache think that request content length is
 
12762
     * maximum length possible. This is to satisfy the
 
12763
     * HTTP_IN input filter. Also flag request as being
 
12764
     * chunked so WSGI input function doesn't think that
 
12765
     * there may actually be that amount of data
 
12766
     * remaining.
 
12767
     */
 
12768
 
 
12769
    item = apr_table_get(r->subprocess_env, "mod_wsgi.input_chunked");
 
12770
 
 
12771
    if (item && !strcasecmp(item, "1")) {
 
12772
        if (sizeof(apr_off_t) == sizeof(long)) {
 
12773
            apr_table_setn(r->headers_in, "Content-Length",
 
12774
                           apr_psprintf(r->pool, "%ld", LONG_MAX));
 
12775
        }
 
12776
        else {
 
12777
            apr_table_setn(r->headers_in, "Content-Length",
 
12778
                           apr_psprintf(r->pool, "%d", INT_MAX));
 
12779
        }
 
12780
 
 
12781
        r->read_chunked = 1;
 
12782
    }
 
12783
 
 
12784
    /*
10227
12785
     * Execute the actual target WSGI application. In
10228
12786
     * normal cases OK should always be returned. If
10229
12787
     * however an error occurs in importing or executing
10301
12859
 
10302
12860
    ap_add_version_component(pconf, package);
10303
12861
 
 
12862
    /* Record Python version string with Apache. */
 
12863
 
 
12864
    if (!Py_IsInitialized()) {
 
12865
        char buffer[256];
 
12866
        const char *token = NULL;
 
12867
        const char *version = NULL;
 
12868
        
 
12869
        version = Py_GetVersion();
 
12870
 
 
12871
        token = version;
 
12872
        while (*token && *token != ' ')
 
12873
            token++;
 
12874
 
 
12875
        strcpy(buffer, "Python/");
 
12876
        strncat(buffer, version, token - version);
 
12877
 
 
12878
        ap_add_version_component(pconf, buffer);
 
12879
    }
 
12880
 
10304
12881
    /* Retain reference to base server. */
10305
12882
 
10306
12883
    wsgi_server = s;
10324
12901
 
10325
12902
    wsgi_server_config = ap_get_module_config(s->module_config, &wsgi_module);
10326
12903
 
10327
 
    /* Initialise Python if not already done. */
10328
 
 
10329
 
    wsgi_python_init(pconf);
 
12904
    /*
 
12905
     * Check that the version of Python found at
 
12906
     * runtime is what was used at compilation.
 
12907
     */
 
12908
 
 
12909
    wsgi_python_version();
 
12910
 
 
12911
    /*
 
12912
     * Initialise Python if required to be done in
 
12913
     * the parent process. Note that it will not be
 
12914
     * initialised if mod_python loaded and it has
 
12915
     * already been done.
 
12916
     */
 
12917
 
 
12918
    if (wsgi_python_required == -1)
 
12919
        wsgi_python_required = 1;
 
12920
 
 
12921
    if (!wsgi_python_after_fork)
 
12922
        wsgi_python_init(pconf);
10330
12923
 
10331
12924
    /* Startup separate named daemon processes. */
10332
12925
 
10339
12932
 
10340
12933
static void wsgi_hook_child_init(apr_pool_t *p, server_rec *s)
10341
12934
{
10342
 
#if defined(MOD_WSGI_WITH_DAEMONS)
 
12935
#if defined(MOD_WSGI_WITH_DAEMONS) 
10343
12936
    WSGIProcessGroup *entries = NULL;
10344
12937
    WSGIProcessGroup *entry = NULL;
10345
12938
 
10359
12952
    }
10360
12953
#endif
10361
12954
 
10362
 
    /* Setup Python in Apache worker processes. */
10363
 
 
10364
 
    wsgi_python_child_init(p);
 
12955
    if (wsgi_python_required) {
 
12956
        /*
 
12957
         * Initialise Python if required to be done in
 
12958
         * the child process. Note that it will not be
 
12959
         * initialised if mod_python loaded and it has
 
12960
         * already been done.
 
12961
         */
 
12962
 
 
12963
        if (wsgi_python_after_fork)
 
12964
            wsgi_python_init(p);
 
12965
 
 
12966
        /*
 
12967
         * Now perform additional initialisation steps
 
12968
         * always done in child process.
 
12969
         */
 
12970
 
 
12971
        wsgi_python_child_init(p);
 
12972
    }
10365
12973
}
10366
12974
 
10367
12975
#if defined(MOD_WSGI_WITH_AAA_HANDLERS)
10393
13001
    return apr_pstrmemdup(r->pool, first, last - first);
10394
13002
}
10395
13003
 
 
13004
static char *wsgi_http2env(apr_pool_t *a, const char *w)
 
13005
{
 
13006
    char *res = (char *)apr_palloc(a, sizeof("HTTP_") + strlen(w));
 
13007
    char *cp = res;
 
13008
    char c;
 
13009
 
 
13010
    *cp++ = 'H';
 
13011
    *cp++ = 'T';
 
13012
    *cp++ = 'T';
 
13013
    *cp++ = 'P';
 
13014
    *cp++ = '_';
 
13015
 
 
13016
    while ((c = *w++) != 0) {
 
13017
        if (!apr_isalnum(c)) {
 
13018
            *cp++ = '_';
 
13019
        }
 
13020
        else {
 
13021
            *cp++ = apr_toupper(c);
 
13022
        }
 
13023
    }
 
13024
    *cp = 0;
 
13025
 
 
13026
    return res;
 
13027
}
 
13028
 
10396
13029
typedef struct {
10397
13030
        PyObject_HEAD
10398
13031
        request_rec *r;
10399
13032
        WSGIRequestConfig *config;
10400
 
        LogObject *log;
 
13033
        PyObject *log;
10401
13034
} AuthObject;
10402
13035
 
10403
13036
static AuthObject *newAuthObject(request_rec *r, WSGIRequestConfig *config)
10412
13045
 
10413
13046
    self->r = r;
10414
13047
 
10415
 
    self->log = newLogObject(r, APLOG_ERR);
 
13048
    self->log = newLogObject(r, APLOG_ERR, NULL);
10416
13049
 
10417
13050
    return self;
10418
13051
}
10432
13065
    request_rec *r = self->r;
10433
13066
    server_rec *s = r->server;
10434
13067
    conn_rec *c = r->connection;
10435
 
    const char *host;
10436
13068
    apr_port_t rport;
10437
13069
 
 
13070
    const apr_array_header_t *hdrs_arr;
 
13071
    const apr_table_entry_t *hdrs;
 
13072
 
 
13073
    const char *value = NULL;
 
13074
 
 
13075
    int i;
 
13076
 
10438
13077
    vars = PyDict_New();
10439
13078
 
10440
 
    object = PyString_FromString(ap_psignature("", r));
 
13079
    hdrs_arr = apr_table_elts(r->headers_in);
 
13080
    hdrs = (const apr_table_entry_t *) hdrs_arr->elts;
 
13081
 
 
13082
    for (i = 0; i < hdrs_arr->nelts; ++i) {
 
13083
        if (!hdrs[i].key) {
 
13084
            continue;
 
13085
        }
 
13086
 
 
13087
        if (!strcasecmp(hdrs[i].key, "Content-type")) {
 
13088
#if PY_MAJOR_VERSION >= 3
 
13089
            object = PyUnicode_DecodeLatin1(hdrs[i].val,
 
13090
                                            strlen(hdrs[i].val), NULL);
 
13091
#else
 
13092
            object = PyString_FromString(hdrs[i].val);
 
13093
#endif
 
13094
            PyDict_SetItemString(vars, "CONTENT_TYPE", object);
 
13095
            Py_DECREF(object);
 
13096
        }
 
13097
        else if (!strcasecmp(hdrs[i].key, "Content-length")) {
 
13098
#if PY_MAJOR_VERSION >= 3
 
13099
            object = PyUnicode_DecodeLatin1(hdrs[i].val,
 
13100
                                            strlen(hdrs[i].val), NULL);
 
13101
#else
 
13102
            object = PyString_FromString(hdrs[i].val);
 
13103
#endif
 
13104
            PyDict_SetItemString(vars, "CONTENT_LENGTH", object);
 
13105
            Py_DECREF(object);
 
13106
        }
 
13107
        else if (!strcasecmp(hdrs[i].key, "Authorization")
 
13108
                 || !strcasecmp(hdrs[i].key, "Proxy-Authorization")) {
 
13109
            continue;
 
13110
        }
 
13111
        else {
 
13112
#if PY_MAJOR_VERSION >= 3
 
13113
            object = PyUnicode_DecodeLatin1(hdrs[i].val,
 
13114
                                            strlen(hdrs[i].val), NULL);
 
13115
#else
 
13116
            object = PyString_FromString(hdrs[i].val);
 
13117
#endif
 
13118
            PyDict_SetItemString(vars, wsgi_http2env(r->pool, hdrs[i].key),
 
13119
                                 object);
 
13120
            Py_DECREF(object);
 
13121
        }
 
13122
    }
 
13123
 
 
13124
    value = ap_psignature("", r);
 
13125
#if PY_MAJOR_VERSION >= 3
 
13126
    object = PyUnicode_DecodeLatin1(value, strlen(value), NULL);
 
13127
#else
 
13128
    object = PyString_FromString(value);
 
13129
#endif
10441
13130
    PyDict_SetItemString(vars, "SERVER_SIGNATURE", object);
10442
13131
    Py_DECREF(object);
10443
13132
 
10444
 
    object = PyString_FromString(ap_get_server_version());
 
13133
#if AP_MODULE_MAGIC_AT_LEAST(20060905,0)
 
13134
    value = ap_get_server_banner();
 
13135
#else
 
13136
    value = ap_get_server_version();
 
13137
#endif
 
13138
#if PY_MAJOR_VERSION >= 3
 
13139
    object = PyUnicode_DecodeLatin1(value, strlen(value), NULL);
 
13140
#else
 
13141
    object = PyString_FromString(value);
 
13142
#endif
10445
13143
    PyDict_SetItemString(vars, "SERVER_SOFTWARE", object);
10446
13144
    Py_DECREF(object);
10447
13145
 
10448
 
    object = PyString_FromString(ap_escape_html(r->pool,
10449
 
                                 ap_get_server_name(r)));
 
13146
    value = ap_escape_html(r->pool, ap_get_server_name(r));
 
13147
#if PY_MAJOR_VERSION >= 3
 
13148
    object = PyUnicode_DecodeLatin1(value, strlen(value), NULL);
 
13149
#else
 
13150
    object = PyString_FromString(value);
 
13151
#endif
10450
13152
    PyDict_SetItemString(vars, "SERVER_NAME", object);
10451
13153
    Py_DECREF(object);
10452
13154
 
10453
13155
    if (r->connection->local_ip) {
10454
 
        object = PyString_FromString(r->connection->local_ip);
 
13156
        value = r->connection->local_ip;
 
13157
#if PY_MAJOR_VERSION >= 3
 
13158
        object = PyUnicode_DecodeLatin1(value, strlen(value), NULL);
 
13159
#else
 
13160
        object = PyString_FromString(value);
 
13161
#endif
10455
13162
        PyDict_SetItemString(vars, "SERVER_ADDR", object);
10456
13163
        Py_DECREF(object);
10457
13164
    }
10458
13165
 
10459
 
    object = PyString_FromString(apr_psprintf(r->pool, "%u",
10460
 
                                 ap_get_server_port(r)));
 
13166
    value = apr_psprintf(r->pool, "%u", ap_get_server_port(r));
 
13167
#if PY_MAJOR_VERSION >= 3
 
13168
    object = PyUnicode_DecodeLatin1(value, strlen(value), NULL);
 
13169
#else
 
13170
    object = PyString_FromString(value);
 
13171
#endif
10461
13172
    PyDict_SetItemString(vars, "SERVER_PORT", object);
10462
13173
    Py_DECREF(object);
10463
13174
 
10464
 
    host = ap_get_remote_host(c, r->per_dir_config, REMOTE_HOST, NULL);
10465
 
    if (host) {
10466
 
        object = PyString_FromString(host);
 
13175
    value = ap_get_remote_host(c, r->per_dir_config, REMOTE_HOST, NULL);
 
13176
    if (value) {
 
13177
#if PY_MAJOR_VERSION >= 3
 
13178
        object = PyUnicode_DecodeLatin1(value, strlen(value), NULL);
 
13179
#else
 
13180
        object = PyString_FromString(value);
 
13181
#endif
10467
13182
        PyDict_SetItemString(vars, "REMOTE_HOST", object);
10468
13183
        Py_DECREF(object);
10469
13184
    }
10470
13185
 
10471
13186
    if (c->remote_ip) {
10472
 
        object = PyString_FromString(c->remote_ip);
 
13187
        value = c->remote_ip;
 
13188
#if PY_MAJOR_VERSION >= 3
 
13189
        object = PyUnicode_DecodeLatin1(value, strlen(value), NULL);
 
13190
#else
 
13191
        object = PyString_FromString(value);
 
13192
#endif
10473
13193
        PyDict_SetItemString(vars, "REMOTE_ADDR", object);
10474
13194
        Py_DECREF(object);
10475
13195
    }
10476
13196
 
 
13197
#if PY_MAJOR_VERSION >= 3
 
13198
    value = ap_document_root(r);
 
13199
    object = PyUnicode_Decode(value, strlen(value),
 
13200
                             Py_FileSystemDefaultEncoding,
 
13201
                             "surrogateescape");
 
13202
#else
10477
13203
    object = PyString_FromString(ap_document_root(r));
 
13204
#endif
10478
13205
    PyDict_SetItemString(vars, "DOCUMENT_ROOT", object);
10479
13206
    Py_DECREF(object);
10480
13207
 
10481
13208
    if (s->server_admin) {
10482
 
        object = PyString_FromString(s->server_admin);
 
13209
        value = s->server_admin;
 
13210
#if PY_MAJOR_VERSION >= 3
 
13211
        object = PyUnicode_DecodeLatin1(value, strlen(value), NULL);
 
13212
#else
 
13213
        object = PyString_FromString(value);
 
13214
#endif
10483
13215
        PyDict_SetItemString(vars, "SERVER_ADMIN", object);
10484
13216
        Py_DECREF(object);
10485
13217
    }
10486
13218
 
10487
13219
    rport = c->remote_addr->port;
10488
 
    object = PyString_FromString(apr_itoa(r->pool, rport));
 
13220
    value = apr_itoa(r->pool, rport);
 
13221
#if PY_MAJOR_VERSION >= 3
 
13222
    object = PyUnicode_DecodeLatin1(value, strlen(value), NULL);
 
13223
#else
 
13224
    object = PyString_FromString(value);
 
13225
#endif
10489
13226
    PyDict_SetItemString(vars, "REMOTE_PORT", object);
10490
13227
    Py_DECREF(object);
10491
13228
 
10492
 
    object = PyString_FromString(r->protocol);
 
13229
    value = r->protocol;
 
13230
#if PY_MAJOR_VERSION >= 3
 
13231
    object = PyUnicode_DecodeLatin1(value, strlen(value), NULL);
 
13232
#else
 
13233
    object = PyString_FromString(value);
 
13234
#endif
10493
13235
    PyDict_SetItemString(vars, "SERVER_PROTOCOL", object);
10494
13236
    Py_DECREF(object);
10495
13237
 
10496
 
    object = PyString_FromString(r->method);
 
13238
    value = r->method;
 
13239
#if PY_MAJOR_VERSION >= 3
 
13240
    object = PyUnicode_DecodeLatin1(value, strlen(value), NULL);
 
13241
#else
 
13242
    object = PyString_FromString(value);
 
13243
#endif
10497
13244
    PyDict_SetItemString(vars, "REQUEST_METHOD", object);
10498
13245
    Py_DECREF(object);
10499
13246
 
10500
 
    object = PyString_FromString(r->args ? r->args : "");
 
13247
    value = r->args ? r->args : "";
 
13248
#if PY_MAJOR_VERSION >= 3
 
13249
    object = PyUnicode_DecodeLatin1(value, strlen(value), NULL);
 
13250
#else
 
13251
    object = PyString_FromString(value);
 
13252
#endif
10501
13253
    PyDict_SetItemString(vars, "QUERY_STRING", object);
10502
13254
    Py_DECREF(object);
10503
13255
 
10504
 
    object = PyString_FromString(wsgi_original_uri(r));
 
13256
    value = wsgi_original_uri(r);
 
13257
#if PY_MAJOR_VERSION >= 3
 
13258
    object = PyUnicode_DecodeLatin1(value, strlen(value), NULL);
 
13259
#else
 
13260
    object = PyString_FromString(value);
 
13261
#endif
10505
13262
    PyDict_SetItemString(vars, "REQUEST_URI", object);
10506
13263
    Py_DECREF(object);
10507
13264
 
 
13265
#if PY_MAJOR_VERSION >= 3
 
13266
    object = PyUnicode_FromString("");
 
13267
#else
10508
13268
    object = PyString_FromString("");
 
13269
#endif
10509
13270
    PyDict_SetItemString(vars, "mod_wsgi.process_group", object);
10510
13271
    Py_DECREF(object);
10511
13272
 
 
13273
#if PY_MAJOR_VERSION >= 3
 
13274
    object = PyUnicode_DecodeLatin1(group, strlen(group), NULL);
 
13275
#else
10512
13276
    object = PyString_FromString(group);
 
13277
#endif
10513
13278
    PyDict_SetItemString(vars, "mod_wsgi.application_group", object);
10514
13279
    Py_DECREF(object);
10515
13280
 
10516
 
    object = PyInt_FromLong(self->config->script_reloading);
 
13281
    object = PyLong_FromLong(self->config->script_reloading);
10517
13282
    PyDict_SetItemString(vars, "mod_wsgi.script_reloading", object);
10518
13283
    Py_DECREF(object);
10519
13284
 
10520
 
    object = PyInt_FromLong(self->config->reload_mechanism);
10521
 
    PyDict_SetItemString(vars, "mod_wsgi.reload_mechanism", object);
10522
 
    Py_DECREF(object);
10523
 
 
10524
13285
    /*
10525
13286
     * Setup log object for WSGI errors. Don't decrement
10526
13287
     * reference to log object as keep reference to it.
10534
13295
     * to the Apache request_rec structure instance.
10535
13296
     */
10536
13297
 
10537
 
    if (!wsgi_daemon_pool && self->config->apache_extensions) {
 
13298
    if (!wsgi_daemon_pool && self->config->pass_apache_request) {
10538
13299
        object = PyCObject_FromVoidPtr(self->r, 0);
10539
13300
        PyDict_SetItemString(vars, "apache.request_rec", object);
10540
13301
        Py_DECREF(object);
10544
13305
}
10545
13306
 
10546
13307
static PyTypeObject Auth_Type = {
10547
 
    /* The ob_type field must be initialized in the module init function
10548
 
     * to be portable to Windows without using C++. */
10549
 
    PyObject_HEAD_INIT(NULL)
10550
 
    0,                      /*ob_size*/
 
13308
    PyVarObject_HEAD_INIT(NULL, 0)
10551
13309
    "mod_wsgi.Auth",        /*tp_name*/
10552
13310
    sizeof(AuthObject),     /*tp_basicsize*/
10553
13311
    0,                      /*tp_itemsize*/
10590
13348
    0,                      /*tp_is_gc*/
10591
13349
};
10592
13350
 
10593
 
#if defined(MOD_WSGI_WITH_AUTH_PROVIDER)
 
13351
#if defined(MOD_WSGI_WITH_AUTHN_PROVIDER)
10594
13352
static authn_status wsgi_check_password(request_rec *r, const char *user,
10595
13353
                                        const char *password)
10596
13354
{
10667
13425
     */
10668
13426
 
10669
13427
    if (module && config->script_reloading) {
10670
 
        if (wsgi_reload_required(r->pool, r, script, module)) {
 
13428
        if (wsgi_reload_required(r->pool, r, script, module, NULL)) {
10671
13429
            /*
10672
13430
             * Script file has changed. Only support module
10673
13431
             * reloading for authentication scripts. Remove the
10712
13470
            PyObject *vars = NULL;
10713
13471
            PyObject *args = NULL;
10714
13472
            PyObject *result = NULL;
 
13473
            PyObject *method = NULL;
10715
13474
 
10716
13475
            AuthObject *adapter = NULL;
10717
13476
 
10756
13515
 
10757
13516
                adapter->r = NULL;
10758
13517
 
10759
 
                /*
10760
 
                 * Flush any data held within error log object
10761
 
                 * and mark it as expired so that it can't be
10762
 
                 * used beyond life of the request. We hope that
10763
 
                 * this doesn't error, as it will overwrite any
10764
 
                 * error from application if it does.
10765
 
                 */
10766
 
 
10767
 
                args = PyTuple_New(0);
10768
 
                object = Log_flush(adapter->log, args);
 
13518
                /* Close the log object so data is flushed. */
 
13519
 
 
13520
                method = PyObject_GetAttrString(adapter->log, "close");
 
13521
 
 
13522
                if (!method) {
 
13523
                    PyErr_Format(PyExc_AttributeError,
 
13524
                                 "'%s' object has no attribute 'close'",
 
13525
                                 adapter->log->ob_type->tp_name);
 
13526
                }
 
13527
                else {
 
13528
                    args = PyTuple_New(0);
 
13529
                    object = PyEval_CallObject(method, args);
 
13530
                    Py_DECREF(args);
 
13531
                }
 
13532
 
10769
13533
                Py_XDECREF(object);
10770
 
                Py_DECREF(args);
 
13534
                Py_XDECREF(method);
10771
13535
 
10772
 
                adapter->log->r = NULL;
10773
 
                adapter->log->expired = 1;
 
13536
                /* No longer need adapter object. */
10774
13537
 
10775
13538
                Py_DECREF((PyObject *)adapter);
10776
13539
            }
10788
13551
 
10789
13552
        /* Log any details of exceptions if execution failed. */
10790
13553
 
10791
 
        if (PyErr_Occurred()) {
10792
 
            LogObject *log;
10793
 
            log = newLogObject(r, APLOG_ERR);
10794
 
            wsgi_log_python_error(r, log, script);
10795
 
            Py_DECREF(log);
10796
 
        }
 
13554
        if (PyErr_Occurred())
 
13555
            wsgi_log_python_error(r, NULL, script);
10797
13556
    }
10798
13557
 
10799
13558
    /* Cleanup and release interpreter, */
10881
13640
     */
10882
13641
 
10883
13642
    if (module && config->script_reloading) {
10884
 
        if (wsgi_reload_required(r->pool, r, script, module)) {
 
13643
        if (wsgi_reload_required(r->pool, r, script, module, NULL)) {
10885
13644
            /*
10886
13645
             * Script file has changed. Only support module
10887
13646
             * reloading for authentication scripts. Remove the
10926
13685
            PyObject *vars = NULL;
10927
13686
            PyObject *args = NULL;
10928
13687
            PyObject *result = NULL;
 
13688
            PyObject *method = NULL;
10929
13689
 
10930
13690
            AuthObject *adapter = NULL;
10931
13691
 
10951
13711
 
10952
13712
                        status = AUTH_USER_FOUND;
10953
13713
                    }
 
13714
#if PY_MAJOR_VERSION >= 3
 
13715
                    else if (PyUnicode_Check(result)) {
 
13716
                        PyObject *latin_item;
 
13717
                        latin_item = PyUnicode_AsLatin1String(result);
 
13718
                        if (!latin_item) {
 
13719
                            PyErr_SetString(PyExc_TypeError, "Digest auth "
 
13720
                                            "provider must return None "
 
13721
                                            "or string object, value "
 
13722
                                            "containing non 'latin-1' "
 
13723
                                            "characters found");
 
13724
                        }
 
13725
                        else {
 
13726
                            Py_DECREF(result);
 
13727
                            result = latin_item;
 
13728
 
 
13729
                            *rethash = PyString_AsString(result);
 
13730
                            *rethash = apr_pstrdup(r->pool, *rethash);
 
13731
 
 
13732
                            status = AUTH_USER_FOUND;
 
13733
                        }
 
13734
                    }
 
13735
#endif
10954
13736
                    else {
10955
13737
                        PyErr_SetString(PyExc_TypeError, "Digest auth "
10956
13738
                                        "provider must return None "
10970
13752
 
10971
13753
                adapter->r = NULL;
10972
13754
 
10973
 
                /*
10974
 
                 * Flush any data held within error log object
10975
 
                 * and mark it as expired so that it can't be
10976
 
                 * used beyond life of the request. We hope that
10977
 
                 * this doesn't error, as it will overwrite any
10978
 
                 * error from application if it does.
10979
 
                 */
10980
 
 
10981
 
                args = PyTuple_New(0);
10982
 
                object = Log_flush(adapter->log, args);
 
13755
                /* Close the log object so data is flushed. */
 
13756
 
 
13757
                method = PyObject_GetAttrString(adapter->log, "close");
 
13758
 
 
13759
                if (!method) {
 
13760
                    PyErr_Format(PyExc_AttributeError,
 
13761
                                 "'%s' object has no attribute 'close'",
 
13762
                                 adapter->log->ob_type->tp_name);
 
13763
                }
 
13764
                else {
 
13765
                    args = PyTuple_New(0);
 
13766
                    object = PyEval_CallObject(method, args);
 
13767
                    Py_DECREF(args);
 
13768
                }
 
13769
 
10983
13770
                Py_XDECREF(object);
10984
 
                Py_DECREF(args);
 
13771
                Py_XDECREF(method);
10985
13772
 
10986
 
                adapter->log->r = NULL;
10987
 
                adapter->log->expired = 1;
 
13773
                /* No longer need adapter object. */
10988
13774
 
10989
13775
                Py_DECREF((PyObject *)adapter);
10990
13776
            }
11002
13788
 
11003
13789
        /* Log any details of exceptions if execution failed. */
11004
13790
 
11005
 
        if (PyErr_Occurred()) {
11006
 
            LogObject *log;
11007
 
            log = newLogObject(r, APLOG_ERR);
11008
 
            wsgi_log_python_error(r, log, script);
11009
 
            Py_DECREF(log);
11010
 
        }
 
13791
        if (PyErr_Occurred())
 
13792
            wsgi_log_python_error(r, NULL, script);
11011
13793
    }
11012
13794
 
11013
13795
    /* Cleanup and release interpreter, */
11100
13882
     */
11101
13883
 
11102
13884
    if (module && config->script_reloading) {
11103
 
        if (wsgi_reload_required(r->pool, r, script, module)) {
 
13885
        if (wsgi_reload_required(r->pool, r, script, module, NULL)) {
11104
13886
            /*
11105
13887
             * Script file has changed. Only support module
11106
13888
             * reloading for authentication scripts. Remove the
11145
13927
            PyObject *vars = NULL;
11146
13928
            PyObject *args = NULL;
11147
13929
            PyObject *sequence = NULL;
 
13930
            PyObject *method = NULL;
11148
13931
 
11149
13932
            AuthObject *adapter = NULL;
11150
13933
 
11172
13955
                        status = OK;
11173
13956
 
11174
13957
                        while ((item = PyIter_Next(iterator))) {
 
13958
#if PY_MAJOR_VERSION >= 3
 
13959
                            if (PyUnicode_Check(item)) {
 
13960
                                PyObject *latin_item;
 
13961
                                latin_item = PyUnicode_AsLatin1String(item);
 
13962
                                if (!latin_item) {
 
13963
                                    Py_BEGIN_ALLOW_THREADS
 
13964
                                    ap_log_rerror(APLOG_MARK, WSGI_LOG_ERR(0),
 
13965
                                                  r, "mod_wsgi (pid=%d): "
 
13966
                                                  "Groups for user returned "
 
13967
                                                  "from '%s' must be an "
 
13968
                                                  "iterable sequence of "
 
13969
                                                  "byte strings, value "
 
13970
                                                  "containing non 'latin-1' "
 
13971
                                                  "characters found",
 
13972
                                                  getpid(), script);
 
13973
                                    Py_END_ALLOW_THREADS
 
13974
 
 
13975
                                    Py_DECREF(item);
 
13976
 
 
13977
                                    status = HTTP_INTERNAL_SERVER_ERROR;
 
13978
 
 
13979
                                    break;
 
13980
                                }
 
13981
                                else {
 
13982
                                    Py_DECREF(item);
 
13983
                                    item = latin_item;
 
13984
                                }
 
13985
                            }
 
13986
#endif
 
13987
 
11175
13988
                            if (!PyString_Check(item)) {
11176
13989
                                Py_BEGIN_ALLOW_THREADS
11177
13990
                                ap_log_rerror(APLOG_MARK, WSGI_LOG_ERR(0), r,
11178
13991
                                              "mod_wsgi (pid=%d): Groups for "
11179
13992
                                              "user returned from '%s' must "
11180
13993
                                              "be an iterable sequence of "
11181
 
                                              "strings.", getpid(), script);
 
13994
                                              "byte strings.", getpid(),
 
13995
                                              script);
11182
13996
                                Py_END_ALLOW_THREADS
11183
13997
 
11184
13998
                                Py_DECREF(item);
11203
14017
                        ap_log_rerror(APLOG_MARK, WSGI_LOG_ERR(0), r,
11204
14018
                                      "mod_wsgi (pid=%d): Groups for user "
11205
14019
                                      "returned from '%s' must be an iterable "
11206
 
                                      "sequence of strings.", getpid(),
 
14020
                                      "sequence of byte strings.", getpid(),
11207
14021
                                      script);
11208
14022
                        Py_END_ALLOW_THREADS
11209
14023
                    }
11221
14035
 
11222
14036
                adapter->r = NULL;
11223
14037
 
11224
 
                /*
11225
 
                 * Flush any data held within error log object
11226
 
                 * and mark it as expired so that it can't be
11227
 
                 * used beyond life of the request. We hope that
11228
 
                 * this doesn't error, as it will overwrite any
11229
 
                 * error from application if it does.
11230
 
                 */
11231
 
 
11232
 
                args = PyTuple_New(0);
11233
 
                object = Log_flush(adapter->log, args);
 
14038
                /* Close the log object so data is flushed. */
 
14039
 
 
14040
                method = PyObject_GetAttrString(adapter->log, "close");
 
14041
 
 
14042
                if (!method) {
 
14043
                    PyErr_Format(PyExc_AttributeError,
 
14044
                                 "'%s' object has no attribute 'close'",
 
14045
                                 adapter->log->ob_type->tp_name);
 
14046
                }
 
14047
                else {
 
14048
                    args = PyTuple_New(0);
 
14049
                    object = PyEval_CallObject(method, args);
 
14050
                    Py_DECREF(args);
 
14051
                }
 
14052
 
11234
14053
                Py_XDECREF(object);
11235
 
                Py_DECREF(args);
 
14054
                Py_XDECREF(method);
11236
14055
 
11237
 
                adapter->log->r = NULL;
11238
 
                adapter->log->expired = 1;
 
14056
                /* No longer need adapter object. */
11239
14057
 
11240
14058
                Py_DECREF((PyObject *)adapter);
11241
14059
            }
11253
14071
 
11254
14072
        /* Log any details of exceptions if execution failed. */
11255
14073
 
11256
 
        if (PyErr_Occurred()) {
11257
 
            LogObject *log;
11258
 
            log = newLogObject(r, APLOG_ERR);
11259
 
            wsgi_log_python_error(r, log, script);
11260
 
            Py_DECREF(log);
11261
 
        }
 
14074
        if (PyErr_Occurred())
 
14075
            wsgi_log_python_error(r, NULL, script);
11262
14076
    }
11263
14077
 
11264
14078
    /* Cleanup and release interpreter, */
11345
14159
     */
11346
14160
 
11347
14161
    if (module && config->script_reloading) {
11348
 
        if (wsgi_reload_required(r->pool, r, script, module)) {
 
14162
        if (wsgi_reload_required(r->pool, r, script, module, NULL)) {
11349
14163
            /*
11350
14164
             * Script file has changed. Only support module
11351
14165
             * reloading for authentication scripts. Remove the
11390
14204
            PyObject *vars = NULL;
11391
14205
            PyObject *args = NULL;
11392
14206
            PyObject *flag = NULL;
 
14207
            PyObject *method = NULL;
11393
14208
 
11394
14209
            AuthObject *adapter = NULL;
11395
14210
 
11436
14251
 
11437
14252
                adapter->r = NULL;
11438
14253
 
11439
 
                /*
11440
 
                 * Flush any data held within error log object
11441
 
                 * and mark it as expired so that it can't be
11442
 
                 * used beyond life of the request. We hope that
11443
 
                 * this doesn't error, as it will overwrite any
11444
 
                 * error from application if it does.
11445
 
                 */
11446
 
 
11447
 
                args = PyTuple_New(0);
11448
 
                object = Log_flush(adapter->log, args);
 
14254
                /* Close the log object so data is flushed. */
 
14255
 
 
14256
                method = PyObject_GetAttrString(adapter->log, "close");
 
14257
 
 
14258
                if (!method) {
 
14259
                    PyErr_Format(PyExc_AttributeError,
 
14260
                                 "'%s' object has no attribute 'close'",
 
14261
                                 adapter->log->ob_type->tp_name);
 
14262
                }
 
14263
                else {
 
14264
                    args = PyTuple_New(0);
 
14265
                    object = PyEval_CallObject(method, args);
 
14266
                    Py_DECREF(args);
 
14267
                }
 
14268
 
11449
14269
                Py_XDECREF(object);
11450
 
                Py_DECREF(args);
 
14270
                Py_XDECREF(method);
11451
14271
 
11452
 
                adapter->log->r = NULL;
11453
 
                adapter->log->expired = 1;
 
14272
                /* No longer need adapter object. */
11454
14273
 
11455
14274
                Py_DECREF((PyObject *)adapter);
11456
14275
            }
11468
14287
 
11469
14288
        /* Log any details of exceptions if execution failed. */
11470
14289
 
11471
 
        if (PyErr_Occurred()) {
11472
 
            LogObject *log;
11473
 
            log = newLogObject(r, APLOG_ERR);
11474
 
            wsgi_log_python_error(r, log, script);
11475
 
            Py_DECREF(log);
11476
 
        }
 
14290
        if (PyErr_Occurred())
 
14291
            wsgi_log_python_error(r, NULL, script);
11477
14292
    }
11478
14293
 
11479
14294
    /* Cleanup and release interpreter, */
11594
14409
     */
11595
14410
 
11596
14411
    if (module && config->script_reloading) {
11597
 
        if (wsgi_reload_required(r->pool, r, script, module)) {
 
14412
        if (wsgi_reload_required(r->pool, r, script, module, NULL)) {
11598
14413
            /*
11599
14414
             * Script file has changed. Only support module
11600
14415
             * reloading for authentication scripts. Remove the
11639
14454
            PyObject *vars = NULL;
11640
14455
            PyObject *args = NULL;
11641
14456
            PyObject *result = NULL;
 
14457
            PyObject *method = NULL;
11642
14458
 
11643
14459
            AuthObject *adapter = NULL;
11644
14460
 
11702
14518
 
11703
14519
                adapter->r = NULL;
11704
14520
 
11705
 
                /*
11706
 
                 * Flush any data held within error log object
11707
 
                 * and mark it as expired so that it can't be
11708
 
                 * used beyond life of the request. We hope that
11709
 
                 * this doesn't error, as it will overwrite any
11710
 
                 * error from application if it does.
11711
 
                 */
11712
 
 
11713
 
                args = PyTuple_New(0);
11714
 
                object = Log_flush(adapter->log, args);
 
14521
                /* Close the log object so data is flushed. */
 
14522
 
 
14523
                method = PyObject_GetAttrString(adapter->log, "close");
 
14524
 
 
14525
                if (!method) {
 
14526
                    PyErr_Format(PyExc_AttributeError,
 
14527
                                 "'%s' object has no attribute 'close'",
 
14528
                                 adapter->log->ob_type->tp_name);
 
14529
                }
 
14530
                else {
 
14531
                    args = PyTuple_New(0);
 
14532
                    object = PyEval_CallObject(method, args);
 
14533
                    Py_DECREF(args);
 
14534
                }
 
14535
 
11715
14536
                Py_XDECREF(object);
11716
 
                Py_DECREF(args);
 
14537
                Py_XDECREF(method);
11717
14538
 
11718
 
                adapter->log->r = NULL;
11719
 
                adapter->log->expired = 1;
 
14539
                /* No longer need adapter object. */
11720
14540
 
11721
14541
                Py_DECREF((PyObject *)adapter);
11722
14542
            }
11734
14554
 
11735
14555
        /* Log any details of exceptions if execution failed. */
11736
14556
 
11737
 
        if (PyErr_Occurred()) {
11738
 
            LogObject *log;
11739
 
            log = newLogObject(r, APLOG_ERR);
11740
 
            wsgi_log_python_error(r, log, script);
11741
 
            Py_DECREF(log);
11742
 
        }
 
14557
        if (PyErr_Occurred())
 
14558
            wsgi_log_python_error(r, NULL, script);
11743
14559
    }
11744
14560
 
11745
14561
    /* Cleanup and release interpreter, */
11751
14567
    return status;
11752
14568
}
11753
14569
 
 
14570
#if defined(MOD_WSGI_WITH_AUTHZ_PROVIDER)
 
14571
 
 
14572
static authz_status wsgi_check_authorization(request_rec *r,
 
14573
                                             const char *require_args)
 
14574
{
 
14575
    WSGIRequestConfig *config;
 
14576
 
 
14577
    apr_table_t *grpstatus = NULL;
 
14578
    const char *t, *w;
 
14579
    int status;
 
14580
 
 
14581
    config = wsgi_create_req_config(r->pool, r);
 
14582
 
 
14583
    if (!config->auth_group_script) {
 
14584
        ap_log_error(APLOG_MARK, WSGI_LOG_ERR(0), wsgi_server,
 
14585
                     "mod_wsgi (pid=%d): Location of WSGI group "
 
14586
                     "authorization script not provided.", getpid());
 
14587
 
 
14588
        return AUTHZ_DENIED;
 
14589
    }
 
14590
 
 
14591
    status = wsgi_groups_for_user(r, config, &grpstatus);
 
14592
 
 
14593
    if (status != OK)
 
14594
        return AUTHZ_DENIED;
 
14595
 
 
14596
    if (apr_table_elts(grpstatus)->nelts == 0) {
 
14597
        ap_log_rerror(APLOG_MARK, WSGI_LOG_ERR(0), r, "mod_wsgi (pid=%d): "
 
14598
                      "Authorization of user '%s' to access '%s' failed. ",
 
14599
                      "User is not a member of any groups.", getpid(),
 
14600
                      r->user, r->uri);
 
14601
        return AUTHZ_DENIED;
 
14602
    }
 
14603
 
 
14604
    t = require_args;
 
14605
    while ((w = ap_getword_conf(r->pool, &t)) && w[0]) {
 
14606
        if (apr_table_get(grpstatus, w)) {
 
14607
            return AUTHZ_GRANTED;
 
14608
        }
 
14609
    }
 
14610
 
 
14611
    ap_log_rerror(APLOG_MARK, WSGI_LOG_ERR(0), r, "mod_wsgi (pid=%d): "
 
14612
                  "Authorization of user '%s' to access '%s' failed. "
 
14613
                  "User is not a member of designated groups.", getpid(),
 
14614
                  r->user, r->uri);
 
14615
 
 
14616
    return AUTHZ_DENIED;
 
14617
}
 
14618
 
 
14619
static const authz_provider wsgi_authz_provider =
 
14620
{
 
14621
    &wsgi_check_authorization,
 
14622
};
 
14623
 
 
14624
#else
 
14625
 
11754
14626
static int wsgi_hook_auth_checker(request_rec *r)
11755
14627
{
11756
14628
    WSGIRequestConfig *config;
11785
14657
        t = reqs[x].requirement;
11786
14658
        w = ap_getword_white(r->pool, &t);
11787
14659
 
11788
 
        if (!strcasecmp(w, "group")) {
 
14660
        if (!strcasecmp(w, "group") || !strcasecmp(w, "wsgi-group")) {
11789
14661
            required_group = 1;
11790
14662
 
11791
14663
            if (!grpstatus) {
11826
14698
 
11827
14699
#endif
11828
14700
 
 
14701
#endif
 
14702
 
11829
14703
APR_OPTIONAL_FN_TYPE(ap_logio_add_bytes_out) *wsgi_logio_add_bytes_out;
11830
14704
 
11831
14705
static void ap_logio_add_bytes_out(conn_rec *c, apr_off_t bytes)
11861
14735
    static const char * const n2[] = { "core.c", NULL };
11862
14736
 
11863
14737
#if defined(MOD_WSGI_WITH_AAA_HANDLERS)
11864
 
#if !defined(MOD_WSGI_WITH_AUTH_PROVIDER)
 
14738
#if !defined(MOD_WSGI_WITH_AUTHN_PROVIDER)
11865
14739
    static const char * const p3[] = { "mod_auth.c", NULL };
11866
14740
#endif
 
14741
#if !defined(MOD_WSGI_WITH_AUTHZ_PROVIDER)
11867
14742
    static const char * const n4[] = { "mod_authz_user.c", NULL };
 
14743
#endif
11868
14744
    static const char * const n5[] = { "mod_authz_host.c", NULL };
11869
14745
#endif
11870
14746
 
11885
14761
#endif
11886
14762
 
11887
14763
#if defined(MOD_WSGI_WITH_AAA_HANDLERS)
11888
 
#if !defined(MOD_WSGI_WITH_AUTH_PROVIDER)
 
14764
#if !defined(MOD_WSGI_WITH_AUTHN_PROVIDER)
11889
14765
    ap_hook_check_user_id(wsgi_hook_check_user_id, p3, NULL, APR_HOOK_MIDDLE);
11890
14766
#else
11891
 
    ap_register_provider(p, AUTHN_PROVIDER_GROUP, "wsgi", "0",
11892
 
                         &wsgi_authn_provider);
 
14767
    ap_register_provider(p, AUTHN_PROVIDER_GROUP, "wsgi",
 
14768
                         AUTHN_PROVIDER_VERSION, &wsgi_authn_provider);
11893
14769
#endif
 
14770
#if !defined(MOD_WSGI_WITH_AUTHZ_PROVIDER)
11894
14771
    ap_hook_auth_checker(wsgi_hook_auth_checker, NULL, n4, APR_HOOK_MIDDLE);
 
14772
#else
 
14773
    ap_register_provider(p, AUTHZ_PROVIDER_GROUP, "wsgi-group",
 
14774
                         AUTHZ_PROVIDER_VERSION, &wsgi_authz_provider);
 
14775
#endif
11895
14776
    ap_hook_access_checker(wsgi_hook_access_checker, NULL, n5, APR_HOOK_MIDDLE);
11896
14777
#endif
11897
14778
}
11898
14779
 
11899
14780
static const command_rec wsgi_commands[] =
11900
14781
{
11901
 
    AP_INIT_TAKE2("WSGIScriptAlias", wsgi_add_script_alias,
 
14782
    AP_INIT_RAW_ARGS("WSGIScriptAlias", wsgi_add_script_alias,
11902
14783
        NULL, RSRC_CONF, "Map location to target WSGI script file."),
11903
 
    AP_INIT_TAKE2("WSGIScriptAliasMatch", wsgi_add_script_alias,
 
14784
    AP_INIT_RAW_ARGS("WSGIScriptAliasMatch", wsgi_add_script_alias,
11904
14785
        "*", RSRC_CONF, "Map location pattern to target WSGI script file."),
11905
14786
 
11906
14787
#if defined(MOD_WSGI_WITH_DAEMONS)
11910
14791
        NULL, RSRC_CONF, "Path prefix for the daemon process sockets."),
11911
14792
    AP_INIT_TAKE1("WSGIAcceptMutex", wsgi_set_accept_mutex,
11912
14793
        NULL, RSRC_CONF, "Set accept mutex type for daemon processes."),
11913
 
#endif
11914
 
 
 
14794
 
 
14795
    AP_INIT_TAKE1("WSGILazyInitialization", wsgi_set_lazy_initialization,
 
14796
        NULL, RSRC_CONF, "Enable/Disable lazy Python initialization."),
 
14797
#endif
 
14798
 
 
14799
    AP_INIT_TAKE1("WSGIVerboseDebugging", wsgi_set_verbose_debugging,
 
14800
        NULL, RSRC_CONF, "Enable/Disable verbose debugging messages."),
 
14801
 
 
14802
#if PY_MAJOR_VERSION == 2 && PY_MINOR_VERSION >= 6
 
14803
    AP_INIT_TAKE1("WSGIPy3kWarningFlag", wsgi_set_py3k_warning_flag,
 
14804
        NULL, RSRC_CONF, "Enable/Disable Python 3.0 warnings."),
 
14805
#endif
 
14806
 
 
14807
    AP_INIT_TAKE1("WSGIPythonWarnings", wsgi_add_python_warnings,
 
14808
        NULL, RSRC_CONF, "Control Python warning messages."),
11915
14809
    AP_INIT_TAKE1("WSGIPythonOptimize", wsgi_set_python_optimize,
11916
14810
        NULL, RSRC_CONF, "Set level of Python compiler optimisations."),
11917
 
#ifndef WIN32
11918
14811
    AP_INIT_TAKE1("WSGIPythonHome", wsgi_set_python_home,
11919
14812
        NULL, RSRC_CONF, "Python prefix/exec_prefix absolute path names."),
11920
 
#endif
11921
14813
    AP_INIT_TAKE1("WSGIPythonPath", wsgi_set_python_path,
11922
14814
        NULL, RSRC_CONF, "Python module search path."),
11923
14815
    AP_INIT_TAKE1("WSGIPythonEggs", wsgi_set_python_eggs,
11924
14816
        NULL, RSRC_CONF, "Python eggs cache directory."),
11925
14817
 
 
14818
#if defined(MOD_WSGI_WITH_DAEMONS)
11926
14819
    AP_INIT_TAKE1("WSGIRestrictEmbedded", wsgi_set_restrict_embedded,
11927
14820
        NULL, RSRC_CONF, "Enable/Disable use of embedded mode."),
 
14821
#endif
11928
14822
    AP_INIT_TAKE1("WSGIRestrictStdin", wsgi_set_restrict_stdin,
11929
14823
        NULL, RSRC_CONF, "Enable/Disable restrictions on use of STDIN."),
11930
14824
    AP_INIT_TAKE1("WSGIRestrictStdout", wsgi_set_restrict_stdout,
11952
14846
    AP_INIT_RAW_ARGS("WSGIDispatchScript", wsgi_set_dispatch_script,
11953
14847
        NULL, ACCESS_CONF|RSRC_CONF, "Location of WSGI dispatch script."),
11954
14848
 
11955
 
    AP_INIT_TAKE1("WSGIApacheExtensions", wsgi_set_apache_extensions,
11956
 
        NULL, ACCESS_CONF|RSRC_CONF, "Enable/Disable Apache extensions."),
 
14849
    AP_INIT_TAKE1("WSGIPassApacheRequest", wsgi_set_pass_apache_request,
 
14850
        NULL, ACCESS_CONF|RSRC_CONF, "Enable/Disable Apache request object."),
11957
14851
    AP_INIT_TAKE1("WSGIPassAuthorization", wsgi_set_pass_authorization,
11958
14852
        NULL, OR_FILEINFO, "Enable/Disable WSGI authorization."),
11959
14853
    AP_INIT_TAKE1("WSGIScriptReloading", wsgi_set_script_reloading,
11960
14854
        NULL, OR_FILEINFO, "Enable/Disable script reloading mechanism."),
11961
 
    AP_INIT_TAKE1("WSGIReloadMechanism", wsgi_set_reload_mechanism,
11962
 
        NULL, OR_FILEINFO, "Defines what is reloaded when a reload occurs."),
 
14855
    AP_INIT_TAKE1("WSGIErrorOverride", wsgi_set_error_override,
 
14856
        NULL, OR_FILEINFO, "Enable/Disable overriding of error pages."),
 
14857
    AP_INIT_TAKE1("WSGIChunkedRequest", wsgi_set_chunked_request,
 
14858
        NULL, OR_FILEINFO, "Enable/Disable support for chunked requests."),
11963
14859
 
11964
14860
#if defined(MOD_WSGI_WITH_AAA_HANDLERS)
11965
14861
    AP_INIT_RAW_ARGS("WSGIAccessScript", wsgi_set_access_script,
11968
14864
        NULL, OR_AUTHCFG, "Location of WSGI user auth script file."),
11969
14865
    AP_INIT_RAW_ARGS("WSGIAuthGroupScript", wsgi_set_auth_group_script,
11970
14866
        NULL, OR_AUTHCFG, "Location of WSGI group auth script file."),
11971
 
#if !defined(MOD_WSGI_WITH_AUTH_PROVIDER)
 
14867
#if !defined(MOD_WSGI_WITH_AUTHN_PROVIDER)
11972
14868
    AP_INIT_TAKE1("WSGIUserAuthoritative", wsgi_set_user_authoritative,
11973
14869
        NULL, OR_AUTHCFG, "Enable/Disable as being authoritative on users."),
11974
14870
#endif
11976
14872
        NULL, OR_AUTHCFG, "Enable/Disable as being authoritative on groups."),
11977
14873
#endif
11978
14874
 
 
14875
    AP_INIT_RAW_ARGS("WSGIHandlerScript", wsgi_add_handler_script,
 
14876
        NULL, ACCESS_CONF|RSRC_CONF, "Location of WSGI handler script file."),
 
14877
 
11979
14878
    { NULL }
11980
14879
};
11981
14880