2
* Copyright 2004 Apache Software Foundation
4
* Licensed under the Apache License, Version 2.0 (the "License"); you
5
* may not use this file except in compliance with the License. You
6
* may obtain a copy of the License at
8
* http://www.apache.org/licenses/LICENSE-2.0
10
* Unless required by applicable law or agreed to in writing, software
11
* distributed under the License is distributed on an "AS IS" BASIS,
12
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
13
* implied. See the License for the specific language governing
14
* permissions and limitations under the License.
16
* Originally developed by Gregory Trubetskoy.
21
* $Id: requestobject.c 481717 2006-12-03 04:36:37Z grahamd $
25
#include "mod_python.h"
27
/* mod_ssl.h is not safe for inclusion in 2.0, so duplicate the
28
* optional function declarations. */
29
APR_DECLARE_OPTIONAL_FN(char *, ssl_var_lookup,
30
(apr_pool_t *, server_rec *,
31
conn_rec *, request_rec *,
33
APR_DECLARE_OPTIONAL_FN(int, ssl_is_https, (conn_rec *));
35
/* Optional functions imported from mod_ssl when loaded: */
36
static APR_OPTIONAL_FN_TYPE(ssl_var_lookup) *optfn_ssl_var_lookup = NULL;
37
static APR_OPTIONAL_FN_TYPE(ssl_is_https) *optfn_is_https = NULL;
41
** MpRequest_FromRequest
43
* This routine creates a Python requestobject given an Apache
44
* request_rec pointer.
48
PyObject * MpRequest_FromRequest(request_rec *req)
50
requestobject *result;
52
result = PyObject_GC_New(requestobject, &MpRequest_Type);
54
return PyErr_NoMemory();
56
result->dict = PyDict_New();
58
return PyErr_NoMemory();
59
result->request_rec = req;
60
result->connection = NULL;
61
result->server = NULL;
62
result->headers_in = MpTable_FromTable(req->headers_in);
63
result->headers_out = MpTable_FromTable(req->headers_out);
64
result->err_headers_out = MpTable_FromTable(req->err_headers_out);
65
result->subprocess_env = MpTable_FromTable(req->subprocess_env);
66
result->notes = MpTable_FromTable(req->notes);
68
result->extension = NULL;
69
result->content_type_set = 0;
70
result->bytes_queued = 0;
72
/* PYTHON 2.5: 'PyList_New' uses Py_ssize_t for input parameters */
73
result->callbacks = PyList_New(0);
74
if (!result->callbacks)
75
return PyErr_NoMemory();
77
result->rbuff_pos = 0;
78
result->rbuff_len = 0;
80
/* we make sure that the object dictionary is there
81
* before registering the object with the GC
83
PyObject_GC_Track(result);
85
return (PyObject *) result;
92
** request.add_common_vars(reqeust self)
94
* Interface to ap_add_common_vars. Adds a bunch of CGI
95
* environment variables.
99
static PyObject * req_add_common_vars(requestobject *self)
102
ap_add_common_vars(self->request_rec);
112
* utility func - makes sure a phase is valid
115
static int valid_phase(const char *p)
117
if ((strcmp(p, "PythonHandler") != 0) &&
118
(strcmp(p, "PythonAuthenHandler") != 0) &&
119
(strcmp(p, "PythonPostReadRequestHandler") != 0) &&
120
(strcmp(p, "PythonTransHandler") != 0) &&
121
(strcmp(p, "PythonHeaderParserHandler") != 0) &&
122
(strcmp(p, "PythonAccessHandler") != 0) &&
123
(strcmp(p, "PythonAuthzHandler") != 0) &&
124
(strcmp(p, "PythonTypeHandler") != 0) &&
125
(strcmp(p, "PythonFixupHandler") != 0) &&
126
(strcmp(p, "PythonLogHandler") != 0) &&
127
(strcmp(p, "PythonInitHandler") != 0))
134
** request.add_handler(request self, string phase, string handler)
136
* Allows to add another handler to the handler list.
139
static PyObject *req_add_handler(requestobject *self, PyObject *args)
142
char *handler = NULL;
143
PyObject *callable = NULL;
144
const char *dir = NULL;
145
const char *currphase;
147
if (! PyArg_ParseTuple(args, "ss|z", &phase, &handler, &dir)) {
149
if (! PyArg_ParseTuple(args, "sO|z", &phase, &callable, &dir)) {
150
PyErr_SetString(PyExc_ValueError,
151
"handler must be a string or callable object");
156
if (! valid_phase(phase)) {
157
PyErr_SetString(PyExc_IndexError,
158
apr_psprintf(self->request_rec->pool,
159
"Invalid phase: %s", phase));
164
if (!PyCallable_Check(callable)) {
165
PyErr_SetString(PyExc_ValueError,
166
"handler must be a string or callable object");
169
/* Cache reference in list of callable handler objects
170
* so that they can be dereferenced when request object
171
* destroyed at end of phase. */
172
if (PyList_Append(self->callbacks, callable) == -1)
177
/* Canonicalize path and add trailing slash at
178
* this point if directory was provided. */
185
rv = apr_filepath_merge(&newpath, NULL, dir,
186
APR_FILEPATH_TRUENAME,
187
self->request_rec->pool);
189
/* If there is a failure, use the original path
190
* which was supplied. */
192
if (rv == APR_SUCCESS || rv == APR_EPATHWILD) {
194
if (dir[strlen(dir) - 1] != '/') {
195
dir = apr_pstrcat(self->request_rec->pool, dir, "/", NULL);
199
/* dir is from Python, so duplicate it */
201
dir = apr_pstrdup(self->request_rec->pool, dir);
205
/* handler is from Python, so duplicate it */
207
handler = apr_pstrdup(self->request_rec->pool, handler);
209
/* which phase are we processing? */
210
currphase = PyString_AsString(self->phase);
212
/* are we in same phase as what's being added? */
213
if (strcmp(currphase, phase) == 0) {
215
/* then just append to hlist */
216
hlist_append(self->request_rec->pool, self->hlo->head,
217
handler, callable, dir, 0, NULL, NULL, 0, NULL, NOTSILENT,
221
/* this is a phase that we're not in */
223
py_req_config *req_config;
226
/* get request config */
227
req_config = (py_req_config *)
228
ap_get_module_config(self->request_rec->request_config,
231
hle = apr_hash_get(req_config->dynhls, phase, APR_HASH_KEY_STRING);
234
hle = hlist_new(self->request_rec->pool, handler, callable, dir,
235
0, NULL, NULL, 0, NULL, NOTSILENT, self->hlo->head);
236
apr_hash_set(req_config->dynhls, phase, APR_HASH_KEY_STRING, hle);
239
hlist_append(self->request_rec->pool, hle, handler, callable, dir,
240
0, NULL, NULL, 0, NULL, NOTSILENT, self->hlo->head);
249
** request.add_input_filter(request self, string name)
251
* Specifies that a pre registered filter be added to input filter chain.
254
static PyObject *req_add_input_filter(requestobject *self, PyObject *args)
257
py_req_config *req_config;
258
python_filter_ctx *ctx;
260
if (! PyArg_ParseTuple(args, "s", &name))
263
req_config = (py_req_config *) ap_get_module_config(
264
self->request_rec->request_config, &python_module);
266
if (apr_hash_get(req_config->in_filters, name, APR_HASH_KEY_STRING)) {
267
ctx = (python_filter_ctx *) apr_pcalloc(self->request_rec->pool,
268
sizeof(python_filter_ctx));
269
ctx->name = apr_pstrdup(self->request_rec->pool, name);
271
ap_add_input_filter(FILTER_NAME, ctx, self->request_rec,
272
self->request_rec->connection);
274
ap_add_input_filter(name, NULL, self->request_rec,
275
self->request_rec->connection);
283
** request.add_output_filter(request self, string name)
285
* Specifies that a pre registered filter be added to output filter chain.
288
static PyObject *req_add_output_filter(requestobject *self, PyObject *args)
291
py_req_config *req_config;
292
python_filter_ctx *ctx;
294
if (! PyArg_ParseTuple(args, "s", &name))
297
req_config = (py_req_config *) ap_get_module_config(
298
self->request_rec->request_config, &python_module);
300
if (apr_hash_get(req_config->out_filters, name, APR_HASH_KEY_STRING)) {
301
ctx = (python_filter_ctx *) apr_pcalloc(self->request_rec->pool,
302
sizeof(python_filter_ctx));
303
ctx->name = apr_pstrdup(self->request_rec->pool, name);
305
ap_add_output_filter(FILTER_NAME, ctx, self->request_rec,
306
self->request_rec->connection);
308
ap_add_output_filter(name, NULL, self->request_rec,
309
self->request_rec->connection);
317
** request.register_input_filter(request self, string name, string handler, list dir)
319
* Registers an input filter active for life of the request.
322
static PyObject *req_register_input_filter(requestobject *self, PyObject *args)
325
char *handler = NULL;
326
PyObject *callable = NULL;
328
py_req_config *req_config;
331
if (! PyArg_ParseTuple(args, "ss|s", &name, &handler, &dir)) {
333
if (! PyArg_ParseTuple(args, "sO|s", &name, &callable, &dir)) {
334
PyErr_SetString(PyExc_ValueError,
335
"handler must be a string or callable object");
341
/* Cache reference in list of callable filter objects
342
* so that they can be dereferenced when request object
343
* destroyed at end of phase. */
344
if (PyList_Append(self->callbacks, callable) == -1)
348
req_config = (py_req_config *) ap_get_module_config(
349
self->request_rec->request_config, &python_module);
351
fh = (py_handler *) apr_pcalloc(self->request_rec->pool,
353
fh->handler = apr_pstrdup(self->request_rec->pool, handler);
354
fh->callable = callable;
355
fh->parent = self->hlo->head;
357
/* Canonicalize path and add trailing slash at
358
* this point if directory was provided. */
365
rv = apr_filepath_merge(&newpath, NULL, dir,
366
APR_FILEPATH_TRUENAME,
367
self->request_rec->pool);
369
/* If there is a failure, use the original path
370
* which was supplied. */
372
if (rv == APR_SUCCESS || rv == APR_EPATHWILD) {
374
if (dir[strlen(dir) - 1] != '/') {
375
dir = apr_pstrcat(self->request_rec->pool, dir, "/", NULL);
379
fh->directory = apr_pstrdup(self->request_rec->pool, dir);
383
apr_hash_set(req_config->in_filters,
384
apr_pstrdup(self->request_rec->pool, name),
385
APR_HASH_KEY_STRING, fh);
392
** request.register_output_filter(request self, string name, string handler, list dir)
394
* Registers an output filter active for life of the request.
397
static PyObject *req_register_output_filter(requestobject *self, PyObject *args)
400
char *handler = NULL;
401
PyObject *callable = NULL;
403
py_req_config *req_config;
406
if (! PyArg_ParseTuple(args, "ss|s", &name, &handler, &dir)) {
408
if (! PyArg_ParseTuple(args, "sO|s", &name, &callable, &dir)) {
409
PyErr_SetString(PyExc_ValueError,
410
"handler must be a string or callable object");
416
/* Cache reference in list of callable filter objects
417
* so that they can be dereferenced when request object
418
* destroyed at end of phase. */
419
if (PyList_Append(self->callbacks, callable) == -1)
423
req_config = (py_req_config *) ap_get_module_config(
424
self->request_rec->request_config, &python_module);
426
fh = (py_handler *) apr_pcalloc(self->request_rec->pool,
428
fh->handler = apr_pstrdup(self->request_rec->pool, handler);
429
fh->callable = callable;
430
fh->parent = self->hlo->head;
432
/* Canonicalize path and add trailing slash at
433
* this point if directory was provided. */
440
rv = apr_filepath_merge(&newpath, NULL, dir,
441
APR_FILEPATH_TRUENAME,
442
self->request_rec->pool);
444
/* If there is a failure, use the original path
445
* which was supplied. */
447
if (rv == APR_SUCCESS || rv == APR_EPATHWILD) {
449
if (dir[strlen(dir) - 1] != '/') {
450
dir = apr_pstrcat(self->request_rec->pool, dir, "/", NULL);
454
fh->directory = apr_pstrdup(self->request_rec->pool, dir);
458
apr_hash_set(req_config->out_filters,
459
apr_pstrdup(self->request_rec->pool, name),
460
APR_HASH_KEY_STRING, fh);
467
** request.allow_methods(request self, list methods, reset=0)
469
* a wrapper around ap_allow_methods. (used for the "allow:" header
470
* to be passed to client when needed.)
473
static PyObject *req_allow_methods(requestobject *self, PyObject *args)
480
if (! PyArg_ParseTuple(args, "O|i", &methods, &reset))
483
if (! PySequence_Check(methods)){
484
PyErr_SetString(PyExc_TypeError,
485
"First argument must be a sequence");
489
/* PYTHON 2.5: 'PySequence_Length' uses Py_ssize_t for input parameters */
490
len = PySequence_Length(methods);
496
/* PYTHON 2.5: 'PySequence_GetItem' uses Py_ssize_t for input parameters */
497
method = PySequence_GetItem(methods, 0);
498
if (! PyString_Check(method)) {
499
PyErr_SetString(PyExc_TypeError,
500
"Methods must be strings");
504
ap_allow_methods(self->request_rec, (reset == REPLACE_ALLOW),
505
PyString_AS_STRING(method), NULL);
507
for (i = 1; i < len; i++) {
508
/* PYTHON 2.5: 'PySequence_GetItem' uses Py_ssize_t for input parameters */
509
method = PySequence_GetItem(methods, i);
510
if (! PyString_Check(method)) {
511
PyErr_SetString(PyExc_TypeError,
512
"Methods must be strings");
516
ap_allow_methods(self->request_rec, MERGE_ALLOW,
517
PyString_AS_STRING(method), NULL);
527
** request.is_https(self)
529
* mod_ssl ssl_is_https() wrapper
532
static PyObject * req_is_https(requestobject *self)
537
optfn_is_https = APR_RETRIEVE_OPTIONAL_FN(ssl_is_https);
539
is_https = optfn_is_https && optfn_is_https(self->request_rec->connection);
541
return PyInt_FromLong(is_https);
546
** request.ssl_var_lookup(self, string variable_name)
548
* mod_ssl ssl_var_lookup() wrapper
551
static PyObject * req_ssl_var_lookup(requestobject *self, PyObject *args)
555
if (! PyArg_ParseTuple(args, "s", &var_name))
556
return NULL; /* error */
558
if (!optfn_ssl_var_lookup)
559
optfn_ssl_var_lookup = APR_RETRIEVE_OPTIONAL_FN(ssl_var_lookup);
561
if (optfn_ssl_var_lookup) {
563
val = optfn_ssl_var_lookup(self->request_rec->pool,
564
self->request_rec->server,
565
self->request_rec->connection,
569
return PyString_FromString(val);
572
/* variable not found, or mod_ssl is not loaded */
579
** request.document_root(self)
581
* ap_docuement_root wrapper
584
static PyObject *req_document_root(requestobject *self)
587
return PyString_FromString(ap_document_root(self->request_rec));
592
** request.get_basic_auth_pw(request self)
594
* get basic authentication password,
595
* similar to ap_get_basic_auth_pw
598
static PyObject * req_get_basic_auth_pw(requestobject *self, PyObject *args)
603
req = self->request_rec;
605
if (! ap_get_basic_auth_pw(req, &pw))
606
return PyString_FromString(pw);
614
** request.auth_name(self)
616
* ap_auth_name wrapper
619
static PyObject *req_auth_name(requestobject *self)
621
const char *auth_name = ap_auth_name(self->request_rec);
627
return PyString_FromString(auth_name);
631
** request.auth_type(self)
633
* ap_auth_type wrapper
636
static PyObject *req_auth_type(requestobject *self)
638
const char *auth_type = ap_auth_type(self->request_rec);
645
return PyString_FromString(auth_type);
649
** request.construct_url(self)
651
* ap_construct_url wrapper
654
static PyObject *req_construct_url(requestobject *self, PyObject *args)
658
if (! PyArg_ParseTuple(args, "s", &uri))
661
return PyString_FromString(ap_construct_url(self->request_rec->pool,
662
uri, self->request_rec));
666
** request.discard_request_body(request self)
668
* discard content supplied with request
671
static PyObject * req_discard_request_body(requestobject *self)
673
return PyInt_FromLong(ap_discard_request_body(self->request_rec));
677
** request.get_addhandler_exts(request self)
679
* Returns file extentions that were given as argument to AddHandler mod_mime
680
* directive, if any, if at all. This is useful for the Publisher, which can
681
* chop off file extentions for modules based on this info.
683
* XXX Due to the way this is implemented, it is best stay undocumented.
686
static PyObject * req_get_addhandler_exts(requestobject *self, PyObject *args)
689
char *exts = get_addhandler_extensions(self->request_rec);
692
return PyString_FromString(exts);
694
return PyString_FromString("");
698
** request.get_config(request self)
700
* Returns the config directives set through Python* apache directives.
701
* except for Python*Handler and PythonOption (which you get via get_options).
704
static PyObject * req_get_config(requestobject *self)
707
(py_config *) ap_get_module_config(self->request_rec->per_dir_config,
709
return MpTable_FromTable(conf->directives);
713
** request.get_remodte_host(request self, [int type])
715
* An interface to the ap_get_remote_host function.
718
static PyObject * req_get_remote_host(requestobject *self, PyObject *args)
721
int type = REMOTE_NAME;
722
PyObject *str_is_ip = Py_None;
726
if (! PyArg_ParseTuple(args, "|iO", &type, &str_is_ip))
729
if (str_is_ip != Py_None) {
730
host = ap_get_remote_host(self->request_rec->connection,
731
self->request_rec->per_dir_config, type, &_str_is_ip);
734
host = ap_get_remote_host(self->request_rec->connection,
735
self->request_rec->per_dir_config, type, NULL);
743
if (str_is_ip != Py_None) {
744
return Py_BuildValue("(s,i)", host, _str_is_ip);
747
return PyString_FromString(host);
753
** request.get_options(request self)
757
static PyObject * req_get_options(requestobject *self, PyObject *args)
760
(py_config *) ap_get_module_config(self->request_rec->per_dir_config,
762
apr_table_t* table = conf->options;
765
const apr_array_header_t* ah = apr_table_elts(table);
766
apr_table_entry_t* elts = (apr_table_entry_t *) ah->elts;
769
* We remove the empty values, since they cannot have been defined
772
for(i=0;i<ah->nelts;i++,elts++) {
773
if(strlen(elts->val)==0) {
774
apr_table_unset(table,elts->key);
778
/* XXX shouldn't we free the apr_array_header_t* ah ? */
780
return MpTable_FromTable(table);
785
** request.internal_redirect(request self, string newuri)
789
static PyObject * req_internal_redirect(requestobject *self, PyObject *args)
793
if (! PyArg_ParseTuple(args, "z", &new_uri))
794
return NULL; /* error */
796
Py_BEGIN_ALLOW_THREADS
797
ap_internal_redirect(new_uri, self->request_rec);
805
** request.log_error(req self, string message, int level)
807
* calls ap_log_rerror
810
static PyObject * req_log_error(requestobject *self, PyObject *args)
813
char *message = NULL;
815
if (! PyArg_ParseTuple(args, "z|i", &message, &level))
816
return NULL; /* error */
821
level = APLOG_NOERRNO|APLOG_ERR;
823
ap_log_rerror(APLOG_MARK, level, 0, self->request_rec, "%s", message);
831
** request.meets_conditions(req self)
833
* ap_meets_conditions wrapper
836
static PyObject * req_meets_conditions(requestobject *self) {
837
return PyInt_FromLong(ap_meets_conditions(self->request_rec));
842
** request.read(request self, int bytes)
844
* Reads stuff like POST requests from the client
845
* (based on the old net_read)
848
static PyObject * req_read(requestobject *self, PyObject *args)
850
int rc, bytes_read, chunk_len;
856
if (! PyArg_ParseTuple(args, "|l", &len))
860
return PyString_FromString("");
863
/* is this the first read? */
864
if (! self->request_rec->read_length) {
866
/* then do some initial setting up */
867
rc = ap_setup_client_block(self->request_rec, REQUEST_CHUNKED_ERROR);
869
PyObject *val = PyInt_FromLong(rc);
872
PyErr_SetObject(get_ServerReturn(), val);
877
if (! ap_should_client_block(self->request_rec)) {
878
/* client has nothing to send */
879
return PyString_FromString("");
884
/* XXX ok to use request_rec->remaining? */
885
len = self->request_rec->remaining +
886
(self->rbuff_len - self->rbuff_pos);
888
/* PYTHON 2.5: 'PyString_FromStringAndSize' uses Py_ssize_t for input parameters */
889
result = PyString_FromStringAndSize(NULL, len);
891
/* possibly no more memory */
895
buffer = PyString_AS_STRING((PyStringObject *) result);
897
/* if anything left in the readline buffer */
898
while ((self->rbuff_pos < self->rbuff_len) && (copied < len))
899
buffer[copied++] = self->rbuff[self->rbuff_pos++];
901
/* Free rbuff if we're done with it */
902
if (self->rbuff_pos >= self->rbuff_len && self->rbuff != NULL) {
908
return result; /* we're done! */
911
Py_BEGIN_ALLOW_THREADS
912
chunk_len = ap_get_client_block(self->request_rec, buffer, len);
914
bytes_read = chunk_len;
916
/* if this is a "short read", try reading more */
917
while ((bytes_read < len) && (chunk_len != 0)) {
918
Py_BEGIN_ALLOW_THREADS
919
chunk_len = ap_get_client_block(self->request_rec,
920
buffer+bytes_read, len-bytes_read);
922
if (chunk_len == -1) {
923
PyErr_SetObject(PyExc_IOError,
924
PyString_FromString("Client read error (Timeout?)"));
928
bytes_read += chunk_len;
931
/* resize if necessary */
932
if (bytes_read < len)
933
/* PYTHON 2.5: '_PyString_Resize' uses Py_ssize_t for input parameters */
934
if(_PyString_Resize(&result, bytes_read))
941
** request.readline(request self, int maxbytes)
943
* Reads stuff like POST requests from the client
944
* (based on the old net_read) until EOL
947
static PyObject * req_readline(requestobject *self, PyObject *args)
950
int rc, chunk_len, bytes_read;
956
if (! PyArg_ParseTuple(args, "|l", &len))
960
return PyString_FromString("");
963
/* is this the first read? */
964
if (! self->request_rec->read_length) {
966
/* then do some initial setting up */
967
rc = ap_setup_client_block(self->request_rec, REQUEST_CHUNKED_ERROR);
970
PyObject *val = PyInt_FromLong(rc);
973
PyErr_SetObject(get_ServerReturn(), val);
978
if (! ap_should_client_block(self->request_rec)) {
979
/* client has nothing to send */
980
return PyString_FromString("");
985
len = self->request_rec->remaining +
986
(self->rbuff_len - self->rbuff_pos);
988
/* create the result buffer */
989
/* PYTHON 2.5: 'PyString_FromStringAndSize' uses Py_ssize_t for input parameters */
990
result = PyString_FromStringAndSize(NULL, len);
992
/* possibly no more memory */
996
buffer = PyString_AS_STRING((PyStringObject *) result);
998
/* is there anything left in the rbuff from previous reads? */
999
if (self->rbuff_pos < self->rbuff_len) {
1001
/* if yes, process that first */
1002
while (self->rbuff_pos < self->rbuff_len) {
1004
buffer[copied++] = self->rbuff[self->rbuff_pos];
1005
if ((self->rbuff[self->rbuff_pos++] == '\n') ||
1008
/* our work is done */
1010
/* resize if necessary */
1012
/* PYTHON 2.5: '_PyString_Resize' uses Py_ssize_t for input parameters */
1013
if(_PyString_Resize(&result, copied))
1016
/* fix for MODPYTHON-181 leak */
1017
if (self->rbuff_pos >= self->rbuff_len && self->rbuff != NULL) {
1027
/* Free old rbuff as the old contents have been copied over and
1028
we are about to allocate a new rbuff. Perhaps this could be reused
1030
if (self->rbuff_pos >= self->rbuff_len && self->rbuff != NULL)
1036
/* if got this far, the buffer should be empty, we need to read more */
1038
/* create a read buffer
1040
The buffer len will be at least HUGE_STRING_LEN in size,
1041
to avoid memory fragmention
1043
self->rbuff_len = len > HUGE_STRING_LEN ? len : HUGE_STRING_LEN;
1044
self->rbuff_pos = 0;
1045
self->rbuff = malloc(self->rbuff_len);
1047
return PyErr_NoMemory();
1050
Py_BEGIN_ALLOW_THREADS
1051
chunk_len = ap_get_client_block(self->request_rec, self->rbuff,
1053
Py_END_ALLOW_THREADS;
1055
/* ap_get_client_block could return -1 on error */
1056
if (chunk_len == -1) {
1058
/* Free rbuff since returning NULL here should end the request */
1062
PyErr_SetObject(PyExc_IOError,
1063
PyString_FromString("Client read error (Timeout?)"));
1067
bytes_read = chunk_len;
1069
/* if this is a "short read", try reading more */
1070
while ((chunk_len != 0 ) && (bytes_read + copied < len)) {
1072
Py_BEGIN_ALLOW_THREADS
1073
chunk_len = ap_get_client_block(self->request_rec,
1074
self->rbuff + bytes_read,
1075
self->rbuff_len - bytes_read);
1076
Py_END_ALLOW_THREADS
1078
if (chunk_len == -1) {
1080
/* Free rbuff since returning NULL here should end the request */
1084
PyErr_SetObject(PyExc_IOError,
1085
PyString_FromString("Client read error (Timeout?)"));
1089
bytes_read += chunk_len;
1091
self->rbuff_len = bytes_read;
1092
self->rbuff_pos = 0;
1094
/* now copy the remaining bytes */
1095
while (self->rbuff_pos < self->rbuff_len) {
1097
buffer[copied++] = self->rbuff[self->rbuff_pos];
1098
if ((self->rbuff[self->rbuff_pos++] == '\n') ||
1100
/* our work is done */
1104
/* Free rbuff if we're done with it */
1105
if (self->rbuff_pos >= self->rbuff_len && self->rbuff != NULL)
1111
/* resize if necessary */
1113
/* PYTHON 2.5: '_PyString_Resize' uses Py_ssize_t for input parameters */
1114
if(_PyString_Resize(&result, copied))
1121
** request.readlines([long maxsize])
1123
* just like file.readlines()
1126
static PyObject *req_readlines(requestobject *self, PyObject *args)
1129
/* PYTHON 2.5: 'PyList_New' uses Py_ssize_t for input parameters */
1130
PyObject *result = PyList_New(0);
1131
PyObject *line, *rlargs;
1136
if (! PyArg_ParseTuple(args, "|l", &sizehint))
1140
return PyErr_NoMemory();
1142
/* PYTHON 2.5: 'PyTuple_New' uses Py_ssize_t for input parameters */
1143
rlargs = PyTuple_New(0);
1145
return PyErr_NoMemory();
1147
line = req_readline(self, rlargs);
1148
/* PYTHON 2.5: 'PyString_Size' uses Py_ssize_t for input parameters */
1149
while (line && ((linesize=PyString_Size(line))>0)) {
1150
PyList_Append(result, line);
1152
if ((sizehint != -1) && (size >= sizehint))
1155
line = req_readline(self, args);
1166
** request.register_cleanup(handler, data)
1168
* registers a cleanup at request pool destruction time.
1169
* optional data argument will be passed to the cleanup function.
1172
static PyObject *req_register_cleanup(requestobject *self, PyObject *args)
1175
PyObject *handler = NULL;
1176
PyObject *data = NULL;
1177
PyObject *name_obj = NULL;
1180
if (! PyArg_ParseTuple(args, "O|O", &handler, &data))
1181
return NULL; /* bad args */
1183
ci = (cleanup_info *)malloc(sizeof(cleanup_info));
1184
ci->request_rec = self->request_rec;
1185
ci->server_rec = self->request_rec->server;
1186
if (PyCallable_Check(handler)) {
1188
ci->handler = handler;
1189
name_obj = python_interpreter_name();
1190
name = (char *)malloc(strlen(PyString_AsString(name_obj))+1);
1191
strcpy(name, PyString_AsString(name_obj));
1192
ci->interpreter = name;
1203
PyErr_SetString(PyExc_ValueError,
1204
"first argument must be a callable object");
1209
apr_pool_cleanup_register(self->request_rec->pool, ci, python_cleanup,
1210
apr_pool_cleanup_null);
1218
** request.requires(self)
1220
* Interface to ap_requires()
1223
static PyObject * req_requires(requestobject *self)
1226
/* This function returns everything specified after the "requires"
1227
as is, without any attempts to parse/organize because
1228
"requires" args only need to be grokable by mod_auth if it is
1229
authoritative. When AuthAuthoritative is off, anything can
1230
follow requires, e.g. "requires role terminator".
1233
const apr_array_header_t *reqs_arr = ap_requires(self->request_rec);
1240
return Py_BuildValue("()");
1243
/* PYTHON 2.5: 'PyTuple_New' uses Py_ssize_t for input parameters */
1244
result = PyTuple_New(reqs_arr->nelts);
1246
reqs = (require_line *) reqs_arr->elts;
1248
for (i = 0; i < reqs_arr->nelts; ++i) {
1249
if (reqs[i].method_mask & (AP_METHOD_BIT << self->request_rec->method_number)) {
1250
/* PYTHON 2.5: 'PyTuple_SetItem' uses Py_ssize_t for input parameters */
1251
PyTuple_SetItem(result, ti++,
1252
PyString_FromString(reqs[i].requirement));
1256
/* PYTHON 2.5: '_PyTuple_Resize' uses Py_ssize_t for input parameters */
1257
_PyTuple_Resize(&result, ti);
1263
** request.send_http_header(request self)
1265
* this is a noop, just so we don't break old scripts
1268
static PyObject * req_send_http_header(requestobject *self)
1275
** request.set_content_length(request self, long content_length)
1277
* write output to the client
1280
static PyObject * req_set_content_length(requestobject *self, PyObject *args)
1284
if (! PyArg_ParseTuple(args, "l", &len))
1285
return NULL; /* bad args */
1287
ap_set_content_length(self->request_rec, len);
1294
** request.set_etag(request self)
1296
* sets the outgoing ETag header
1299
static PyObject * req_set_etag(requestobject *self, PyObject *args)
1301
ap_set_etag(self->request_rec);
1308
** request.set_last_modified(request self)
1310
* set the Last-modified header
1313
static PyObject * req_set_last_modified(requestobject *self, PyObject *args)
1315
ap_set_last_modified(self->request_rec);
1322
** request.update_mtime(request self, long mtime)
1324
* updates mtime attribute if newer
1327
static PyObject * req_update_mtime(requestobject *self, PyObject *args)
1331
if (! PyArg_ParseTuple(args, "d", &mtime))
1332
return NULL; /* bad args */
1334
ap_update_mtime(self->request_rec, apr_time_from_sec(mtime));
1341
** request.write(request self, string what, flush=1)
1343
* write output to the client
1346
static PyObject * req_write(requestobject *self, PyObject *args)
1353
if (! PyArg_ParseTuple(args, "s#|i", &buff, &len, &flush))
1354
return NULL; /* bad args */
1358
Py_BEGIN_ALLOW_THREADS
1359
rc = ap_rwrite(buff, len, self->request_rec);
1360
if (flush && (rc != -1))
1361
rc = ap_rflush(self->request_rec);
1362
Py_END_ALLOW_THREADS
1364
PyErr_SetString(PyExc_IOError, "Write failed, client closed connection.");
1369
self->bytes_queued += len;
1377
** request.flush(request self)
1379
* flush output buffer
1382
static PyObject * req_flush(requestobject *self)
1386
Py_BEGIN_ALLOW_THREADS
1387
rc = ap_rflush(self->request_rec);
1388
Py_END_ALLOW_THREADS
1390
PyErr_SetString(PyExc_IOError, "Flush failed, client closed connection.");
1403
static PyObject * req_sendfile(requestobject *self, PyObject *args)
1407
apr_size_t offset=0, len=-1, nbytes;
1408
apr_status_t status;
1409
PyObject * py_result = NULL;
1412
if (! PyArg_ParseTuple(args, "s|ll", &fname, &offset, &len))
1413
return NULL; /* bad args */
1415
Py_BEGIN_ALLOW_THREADS
1416
status=apr_stat(&finfo, fname,
1417
APR_FINFO_SIZE, self->request_rec->pool);
1418
Py_END_ALLOW_THREADS
1419
if (status != APR_SUCCESS) {
1420
PyErr_SetString(PyExc_IOError, "Could not stat file for reading");
1424
Py_BEGIN_ALLOW_THREADS
1425
status=apr_file_open(&fd, fname,
1426
APR_READ, APR_OS_DEFAULT,
1427
self->request_rec->pool);
1428
Py_END_ALLOW_THREADS
1429
if (status != APR_SUCCESS) {
1430
PyErr_SetString(PyExc_IOError, "Could not open file for reading");
1434
if (len==-1) len=finfo.size;
1436
Py_BEGIN_ALLOW_THREADS
1437
status = ap_send_fd(fd, self->request_rec, offset,
1439
Py_END_ALLOW_THREADS
1442
if (status != APR_SUCCESS) {
1443
PyErr_SetString(PyExc_IOError, "Write failed, client closed connection.");
1447
self->bytes_queued += len;
1449
py_result = PyLong_FromLong (nbytes);
1450
Py_INCREF(py_result);
1454
static PyMethodDef request_methods[] = {
1455
{"add_common_vars", (PyCFunction) req_add_common_vars, METH_NOARGS},
1456
{"add_handler", (PyCFunction) req_add_handler, METH_VARARGS},
1457
{"add_input_filter", (PyCFunction) req_add_input_filter, METH_VARARGS},
1458
{"add_output_filter", (PyCFunction) req_add_output_filter, METH_VARARGS},
1459
{"allow_methods", (PyCFunction) req_allow_methods, METH_VARARGS},
1460
{"auth_name", (PyCFunction) req_auth_name, METH_NOARGS},
1461
{"auth_type", (PyCFunction) req_auth_type, METH_NOARGS},
1462
{"construct_url", (PyCFunction) req_construct_url, METH_VARARGS},
1463
{"discard_request_body", (PyCFunction) req_discard_request_body, METH_NOARGS},
1464
{"get_config", (PyCFunction) req_get_config, METH_NOARGS},
1465
{"document_root", (PyCFunction) req_document_root, METH_NOARGS},
1466
{"flush", (PyCFunction) req_flush, METH_NOARGS},
1467
{"get_basic_auth_pw", (PyCFunction) req_get_basic_auth_pw, METH_NOARGS},
1468
{"get_addhandler_exts", (PyCFunction) req_get_addhandler_exts, METH_NOARGS},
1469
{"get_remote_host", (PyCFunction) req_get_remote_host, METH_VARARGS},
1470
{"get_options", (PyCFunction) req_get_options, METH_NOARGS},
1471
{"internal_redirect", (PyCFunction) req_internal_redirect, METH_VARARGS},
1472
{"is_https", (PyCFunction) req_is_https, METH_NOARGS},
1473
{"log_error", (PyCFunction) req_log_error, METH_VARARGS},
1474
{"meets_conditions", (PyCFunction) req_meets_conditions, METH_NOARGS},
1475
{"read", (PyCFunction) req_read, METH_VARARGS},
1476
{"readline", (PyCFunction) req_readline, METH_VARARGS},
1477
{"readlines", (PyCFunction) req_readlines, METH_VARARGS},
1478
{"register_cleanup", (PyCFunction) req_register_cleanup, METH_VARARGS},
1479
{"register_input_filter", (PyCFunction) req_register_input_filter, METH_VARARGS},
1480
{"register_output_filter", (PyCFunction) req_register_output_filter, METH_VARARGS},
1481
{"requires", (PyCFunction) req_requires, METH_NOARGS},
1482
{"send_http_header", (PyCFunction) req_send_http_header, METH_NOARGS},
1483
{"sendfile", (PyCFunction) req_sendfile, METH_VARARGS},
1484
{"set_content_length", (PyCFunction) req_set_content_length, METH_VARARGS},
1485
{"set_etag", (PyCFunction) req_set_etag, METH_NOARGS},
1486
{"set_last_modified", (PyCFunction) req_set_last_modified, METH_NOARGS},
1487
{"ssl_var_lookup", (PyCFunction) req_ssl_var_lookup, METH_VARARGS},
1488
{"update_mtime", (PyCFunction) req_update_mtime, METH_VARARGS},
1489
{"write", (PyCFunction) req_write, METH_VARARGS},
1490
{ NULL, NULL } /* sentinel */
1495
These are offsets into the Apache request_rec structure.
1496
They are accessed via getset functions. Note that the types
1497
specified here are irrelevant if a function other than
1498
getreq_recmbr() is used. E.g. bytes_sent is a long long,
1499
and is retrieved via getreq_recmbr_off() which ignores what's
1503
#define OFF(x) offsetof(request_rec, x)
1505
static struct PyMemberDef request_rec_mbrs[] = {
1506
{"the_request", T_STRING, OFF(the_request)},
1507
{"assbackwards", T_INT, OFF(assbackwards)},
1508
{"proxyreq", T_INT, OFF(proxyreq)},
1509
{"header_only", T_INT, OFF(header_only)},
1510
{"protocol", T_STRING, OFF(protocol)},
1511
{"proto_num", T_INT, OFF(proto_num)},
1512
{"hostname", T_STRING, OFF(hostname)},
1513
{"request_time", T_LONG, OFF(request_time)},
1514
{"status_line", T_STRING, OFF(status_line)},
1515
{"status", T_INT, OFF(status)},
1516
{"method", T_STRING, OFF(method)},
1517
{"method_number", T_INT, OFF(method_number)},
1518
{"allowed", T_LONG, OFF(allowed)},
1519
{"allowed_xmethods", T_OBJECT, OFF(allowed_xmethods)},
1520
{"allowed_methods", T_OBJECT, OFF(allowed_methods)},
1521
{"sent_bodyct", T_LONG, OFF(sent_bodyct)},
1522
{"bytes_sent", T_LONG, OFF(bytes_sent)},
1523
{"mtime", T_LONG, OFF(mtime)},
1524
{"chunked", T_INT, OFF(chunked)},
1525
{"range", T_STRING, OFF(range)},
1526
{"clength", T_LONG, OFF(clength)},
1527
{"remaining", T_LONG, OFF(remaining)},
1528
{"read_length", T_LONG, OFF(read_length)},
1529
{"read_body", T_INT, OFF(read_body)},
1530
{"read_chunked", T_INT, OFF(read_chunked)},
1531
{"expecting_100", T_INT, OFF(expecting_100)},
1532
{"content_type", T_STRING, OFF(content_type)},
1533
{"handler", T_STRING, OFF(handler)},
1534
{"content_encoding", T_STRING, OFF(content_encoding)},
1535
{"content_languages", T_OBJECT, OFF(content_languages)},
1536
{"vlist_validator", T_STRING, OFF(vlist_validator)},
1537
{"user", T_STRING, OFF(user)},
1538
{"ap_auth_type", T_STRING, OFF(ap_auth_type)},
1539
{"no_cache", T_INT, OFF(no_cache)},
1540
{"no_local_copy", T_INT, OFF(no_local_copy)},
1541
{"unparsed_uri", T_STRING, OFF(unparsed_uri)},
1542
{"uri", T_STRING, OFF(uri)},
1543
{"filename", T_STRING, OFF(filename)},
1544
{"canonical_filename", T_STRING, OFF(canonical_filename)},
1545
{"path_info", T_STRING, OFF(path_info)},
1546
{"args", T_STRING, OFF(args)},
1547
{"finfo", T_OBJECT, OFF(finfo)},
1548
{"parsed_uri", T_OBJECT, OFF(parsed_uri)},
1549
{"used_path_info", T_INT, OFF(used_path_info)},
1550
{"eos_sent", T_INT, OFF(eos_sent)},
1551
{NULL} /* Sentinel */
1557
* Retrieves request_rec structure members
1560
static PyObject *getreq_recmbr(requestobject *self, void *name)
1563
* apparently at least ap_internal_fast_redirect blatently
1564
* substitute request members, and so we always have to make
1565
* sure that various apr_tables referenced haven't been
1566
* replaced in between handlers and we're left with a stale.
1569
if (strcmp(name, "interpreter") == 0) {
1570
return python_interpreter_name();
1572
else if (strcmp(name, "headers_in") == 0) {
1573
if (((tableobject*)self->headers_in)->table != self->request_rec->headers_in)
1574
((tableobject*)self->headers_in)->table = self->request_rec->headers_in;
1575
Py_INCREF(self->headers_in);
1576
return self->headers_in;
1578
else if (strcmp(name, "headers_out") == 0) {
1579
if (((tableobject*)self->headers_out)->table != self->request_rec->headers_out)
1580
((tableobject*)self->headers_out)->table = self->request_rec->headers_out;
1581
Py_INCREF(self->headers_out);
1582
return self->headers_out;
1584
else if (strcmp(name, "err_headers_out") == 0) {
1585
if (((tableobject*)self->err_headers_out)->table != self->request_rec->err_headers_out)
1586
((tableobject*)self->err_headers_out)->table = self->request_rec->err_headers_out;
1587
Py_INCREF(self->err_headers_out);
1588
return self->err_headers_out;
1590
else if (strcmp(name, "subprocess_env") == 0) {
1591
if (((tableobject*)self->subprocess_env)->table != self->request_rec->subprocess_env)
1592
((tableobject*)self->subprocess_env)->table = self->request_rec->subprocess_env;
1593
Py_INCREF(self->subprocess_env);
1594
return self->subprocess_env;
1596
else if (strcmp(name, "notes") == 0) {
1597
if (((tableobject*)self->notes)->table != self->request_rec->notes)
1598
((tableobject*)self->notes)->table = self->request_rec->notes;
1599
Py_INCREF(self->notes);
1602
else if (strcmp(name, "_bytes_queued") == 0) {
1603
if (sizeof(apr_off_t) == sizeof(LONG_LONG)) {
1604
LONG_LONG l = self->bytes_queued;
1605
return PyLong_FromLongLong(l);
1608
/* assume it's long */
1609
long l = self->bytes_queued;
1610
return PyLong_FromLong(l);
1613
else if (strcmp(name, "_request_rec") == 0) {
1614
return PyCObject_FromVoidPtr(self->request_rec, 0);
1617
return PyMember_GetOne((char*)self->request_rec,
1618
find_memberdef(request_rec_mbrs, name));
1624
* Sets request_rec structure members
1627
static int setreq_recmbr(requestobject *self, PyObject *val, void *name)
1630
if (strcmp(name, "content_type") == 0) {
1631
if (! PyString_Check(val)) {
1632
PyErr_SetString(PyExc_TypeError, "content_type must be a string");
1635
ap_set_content_type(self->request_rec,
1636
apr_pstrdup(self->request_rec->pool,
1637
PyString_AsString(val)));
1638
self->content_type_set = 1;
1641
else if (strcmp(name, "user") == 0) {
1642
if (! PyString_Check(val)) {
1643
PyErr_SetString(PyExc_TypeError, "user must be a string");
1646
self->request_rec->user =
1647
apr_pstrdup(self->request_rec->pool, PyString_AsString(val));
1650
else if (strcmp(name, "ap_auth_type") == 0) {
1651
if (! PyString_Check(val)) {
1652
PyErr_SetString(PyExc_TypeError, "ap_auth_type must be a string");
1655
self->request_rec->ap_auth_type =
1656
apr_pstrdup(self->request_rec->pool, PyString_AsString(val));
1659
else if (strcmp(name, "filename") == 0) {
1660
if (! PyString_Check(val)) {
1661
PyErr_SetString(PyExc_TypeError, "filename must be a string");
1664
self->request_rec->filename =
1665
apr_pstrdup(self->request_rec->pool, PyString_AsString(val));
1668
else if (strcmp(name, "canonical_filename") == 0) {
1669
if (! PyString_Check(val)) {
1670
PyErr_SetString(PyExc_TypeError, "canonical_filename must be a string");
1673
self->request_rec->canonical_filename =
1674
apr_pstrdup(self->request_rec->pool, PyString_AsString(val));
1677
else if (strcmp(name, "path_info") == 0) {
1678
if (! PyString_Check(val)) {
1679
PyErr_SetString(PyExc_TypeError, "path_info must be a string");
1682
self->request_rec->path_info =
1683
apr_pstrdup(self->request_rec->pool, PyString_AsString(val));
1686
else if (strcmp(name, "args") == 0) {
1687
if (! PyString_Check(val)) {
1688
PyErr_SetString(PyExc_TypeError, "args must be a string");
1691
self->request_rec->args =
1692
apr_pstrdup(self->request_rec->pool, PyString_AsString(val));
1695
else if (strcmp(name, "handler") == 0) {
1696
if (val == Py_None) {
1697
self->request_rec->handler = 0;
1700
if (! PyString_Check(val)) {
1701
PyErr_SetString(PyExc_TypeError, "handler must be a string");
1704
self->request_rec->handler =
1705
apr_pstrdup(self->request_rec->pool, PyString_AsString(val));
1708
else if (strcmp(name, "uri") == 0) {
1709
if (! PyString_Check(val)) {
1710
PyErr_SetString(PyExc_TypeError, "uri must be a string");
1713
self->request_rec->uri =
1714
apr_pstrdup(self->request_rec->pool, PyString_AsString(val));
1717
else if (strcmp(name, "finfo") == 0) {
1719
if (! MpFinfo_Check(val)) {
1720
PyErr_SetString(PyExc_TypeError, "finfo must be a finfoobject");
1723
f = (finfoobject *)val;
1724
self->request_rec->finfo = *f->finfo;
1725
self->request_rec->finfo.fname = apr_pstrdup(self->request_rec->pool,
1727
self->request_rec->finfo.name = apr_pstrdup(self->request_rec->pool,
1733
return PyMember_SetOne((char*)self->request_rec,
1734
find_memberdef(request_rec_mbrs, (char*)name),
1739
** getreq_recmbr_time
1741
* Retrieves apr_time_t request_rec members
1744
static PyObject *getreq_recmbr_time(requestobject *self, void *name)
1746
PyMemberDef *md = find_memberdef(request_rec_mbrs, name);
1747
char *addr = (char *)self->request_rec + md->offset;
1748
apr_time_t time = *(apr_time_t*)addr;
1749
return PyFloat_FromDouble(time*0.000001);
1753
** getreq_recmbr_off
1755
* Retrieves apr_off_t request_rec members
1758
static PyObject *getreq_recmbr_off(requestobject *self, void *name)
1760
PyMemberDef *md = find_memberdef(request_rec_mbrs, name);
1761
char *addr = (char *)self->request_rec + md->offset;
1762
if (sizeof(apr_off_t) == sizeof(LONG_LONG)) {
1763
LONG_LONG l = *(LONG_LONG*)addr;
1764
return PyLong_FromLongLong(l);
1767
/* assume it's long */
1768
long l = *(long*)addr;
1769
return PyLong_FromLong(l);
1776
* For array headers that will get converted to tuple
1779
static PyObject *getreq_rec_ah(requestobject *self, void *name)
1781
const PyMemberDef *md = find_memberdef(request_rec_mbrs, name);
1782
apr_array_header_t *ah =
1783
*(apr_array_header_t **)((char *)self->request_rec + md->offset);
1785
return tuple_from_array_header(ah);
1791
* For method lists that will get converted to tuple
1794
static PyObject *getreq_rec_ml(requestobject *self, void *name)
1796
const PyMemberDef *md = find_memberdef(request_rec_mbrs, (char*)name);
1797
ap_method_list_t *ml =
1798
*(ap_method_list_t **)((char *)self->request_rec + md->offset);
1800
return tuple_from_method_list(ml);
1806
* For file info that will get converted to tuple
1809
static PyObject *getreq_rec_fi(requestobject *self, void *name)
1811
const PyMemberDef *md = find_memberdef(request_rec_mbrs, (char*)name);
1813
(apr_finfo_t *)((char *)self->request_rec + md->offset);
1815
return MpFinfo_FromFinfo(fi);
1821
* For parsed uri that will get converted to tuple
1824
static PyObject *getreq_rec_uri(requestobject *self, void *name)
1826
const PyMemberDef *md = find_memberdef(request_rec_mbrs, (char*)name);
1827
apr_uri_t *uri = (apr_uri_t *)((char *)self->request_rec + md->offset);
1829
return tuple_from_apr_uri(uri);
1835
* A getter func that creates an object as needed.
1838
static PyObject *getmakeobj(requestobject* self, void *objname)
1840
char *name = (char *)objname;
1841
PyObject *result = NULL;
1843
if (strcmp(name, "connection") == 0) {
1844
if (!self->connection && self->request_rec->connection) {
1845
self->connection = MpConn_FromConn(self->request_rec->connection);
1847
result = self->connection;
1849
else if (strcmp(name, "server") == 0) {
1850
if (!self->server && self->request_rec->server) {
1851
self->server = MpServer_FromServer(self->request_rec->server);
1853
result = self->server;
1855
else if (strcmp(name, "next") == 0) {
1856
if (self->request_rec->next) {
1857
result = (PyObject*)python_get_request_object(
1858
self->request_rec->next, 0);
1861
else if (strcmp(name, "prev") == 0) {
1862
if (self->request_rec->prev) {
1863
result = (PyObject*)python_get_request_object(
1864
self->request_rec->prev, 0);
1867
else if (strcmp(name, "main") == 0) {
1868
if (self->request_rec->main) {
1869
result = (PyObject*)python_get_request_object(
1870
self->request_rec->main, 0);
1882
static PyGetSetDef request_getsets[] = {
1883
{"interpreter", (getter)getreq_recmbr, NULL, "Python interpreter name", "interpreter"},
1884
{"connection", (getter)getmakeobj, NULL, "Connection object", "connection"},
1885
{"server", (getter)getmakeobj, NULL, "Server object", "server"},
1886
{"next", (getter)getmakeobj, NULL, "If redirected, pointer to the to request", "next"},
1887
{"prev", (getter)getmakeobj, NULL, "If redirected, pointer to the from request", "prev"},
1888
{"main", (getter)getmakeobj, NULL, "If subrequest, pointer to the main request", "main"},
1889
{"the_request", (getter)getreq_recmbr, NULL, "First line of request", "the_request"},
1890
{"assbackwards", (getter)getreq_recmbr, (setter)setreq_recmbr, "HTTP/0.9 \"simple\" request", "assbackwards"},
1891
{"proxyreq", (getter)getreq_recmbr, (setter)setreq_recmbr, "A proxy request: one of apache.PROXYREQ_* values", "proxyreq"},
1892
{"header_only", (getter)getreq_recmbr, NULL, "HEAD request, as oppsed to GET", "header_only"},
1893
{"protocol", (getter)getreq_recmbr, NULL, "Protocol as given to us, or HTTP/0.9", "protocol"},
1894
{"proto_num", (getter)getreq_recmbr, NULL, "Protocol version. 1.1 = 1001", "proto_num"},
1895
{"hostname", (getter)getreq_recmbr, NULL, "Host, as set by full URI or Host:", "hostname"},
1896
{"request_time", (getter)getreq_recmbr_time, NULL, "When request started", "request_time"},
1897
{"status_line", (getter)getreq_recmbr, NULL, "Status line, if set by script", "status_line"},
1898
{"status", (getter)getreq_recmbr, (setter)setreq_recmbr, "Status", "status"},
1899
{"method", (getter)getreq_recmbr, NULL, "Request method", "method"},
1900
{"method_number", (getter)getreq_recmbr, NULL, "Request method number, one of apache.M_*", "method_number"},
1901
{"allowed", (getter)getreq_recmbr, NULL, "Status", "allowed"},
1902
{"allowed_xmethods", (getter)getreq_rec_ah, NULL, "Allowed extension methods", "allowed_xmethods"},
1903
{"allowed_methods", (getter)getreq_rec_ml, NULL, "Allowed methods", "allowed_methods"},
1904
{"sent_bodyct", (getter)getreq_recmbr_off, NULL, "Byte count in stream for body", "sent_bodyct"},
1905
{"bytes_sent", (getter)getreq_recmbr_off, NULL, "Bytes sent", "bytes_sent"},
1906
{"mtime", (getter)getreq_recmbr_time, NULL, "Time resource was last modified", "mtime"},
1907
{"chunked", (getter)getreq_recmbr, NULL, "Sending chunked transfer-coding", "chunked"},
1908
{"range", (getter)getreq_recmbr, NULL, "The Range: header", "range"},
1909
{"clength", (getter)getreq_recmbr_off, NULL, "The \"real\" contenct length", "clength"},
1910
{"remaining", (getter)getreq_recmbr_off, NULL, "Bytes left to read", "remaining"},
1911
{"read_length", (getter)getreq_recmbr_off, NULL, "Bytes that have been read", "read_length"},
1912
{"read_body", (getter)getreq_recmbr, NULL, "How the request body should be read", "read_body"},
1913
{"read_chunked", (getter)getreq_recmbr, NULL, "Reading chunked transfer-coding", "read_chunked"},
1914
{"expecting_100", (getter)getreq_recmbr, NULL, "Is client waitin for a 100 response?", "expecting_100"},
1915
{"content_type", (getter)getreq_recmbr, (setter)setreq_recmbr, "Content type", "content_type"},
1916
{"handler", (getter)getreq_recmbr, (setter)setreq_recmbr, "The handler string", "handler"},
1917
{"content_encoding", (getter)getreq_recmbr, NULL, "How to encode the data", "content_encoding"},
1918
{"content_languages", (getter)getreq_rec_ah, NULL, "Content languages", "content_languages"},
1919
{"vlist_validator", (getter)getreq_recmbr, NULL, "Variant list validator (if negotiated)", "vlist_validator"},
1920
{"user", (getter)getreq_recmbr, (setter)setreq_recmbr, "If authentication check was made, the user name", "user"},
1921
{"ap_auth_type", (getter)getreq_recmbr, (setter)setreq_recmbr, "If authentication check was made, auth type", "ap_auth_type"},
1922
{"no_cache", (getter)getreq_recmbr, (setter)setreq_recmbr, "This response in non-cacheable", "no_cache"},
1923
{"no_local_copy", (getter)getreq_recmbr, (setter)setreq_recmbr, "There is no local copy of the response", "no_local_copy"},
1924
{"unparsed_uri", (getter)getreq_recmbr, NULL, "The URI without any parsing performed", "unparsed_uri"},
1925
{"uri", (getter)getreq_recmbr, (setter)setreq_recmbr, "The path portion of URI", "uri"},
1926
{"filename", (getter)getreq_recmbr, (setter)setreq_recmbr, "The file name on disk that this request corresponds to", "filename"},
1927
{"canonical_filename", (getter)getreq_recmbr, (setter)setreq_recmbr, "The true filename (req.filename is canonicalized if they don't match)", "canonical_filename"},
1928
{"path_info", (getter)getreq_recmbr, (setter)setreq_recmbr, "Path_info, if any", "path_info"},
1929
{"args", (getter)getreq_recmbr, (setter)setreq_recmbr, "QUERY_ARGS, if any", "args"},
1930
{"finfo", (getter)getreq_rec_fi, (setter)setreq_recmbr, "File information", "finfo"},
1931
{"parsed_uri", (getter)getreq_rec_uri, NULL, "Components of URI", "parsed_uri"},
1932
{"used_path_info", (getter)getreq_recmbr, (setter)setreq_recmbr, "Flag to accept or reject path_info on current request", "used_path_info"},
1933
{"headers_in", (getter)getreq_recmbr, NULL, "Incoming headers", "headers_in"},
1934
{"headers_out", (getter)getreq_recmbr, NULL, "Outgoing headers", "headers_out"},
1935
{"err_headers_out", (getter)getreq_recmbr, NULL, "Outgoing headers for errors", "err_headers_out"},
1936
{"subprocess_env", (getter)getreq_recmbr, NULL, "Subprocess environment", "subprocess_env"},
1937
{"notes", (getter)getreq_recmbr, NULL, "Notes", "notes"},
1938
/* XXX per_dir_config */
1939
/* XXX request_config */
1941
/* XXX filters and eos */
1942
{"eos_sent", (getter)getreq_recmbr, NULL, "EOS bucket sent", "eos_sent"},
1943
{"_bytes_queued", (getter)getreq_recmbr, NULL, "Bytes queued by handler", "_bytes_queued"},
1944
{"_request_rec", (getter)getreq_recmbr, NULL, "Actual request_rec struct", "_request_rec"},
1945
{NULL} /* Sentinel */
1949
#define OFF(x) offsetof(requestobject, x)
1951
static struct PyMemberDef request_members[] = {
1952
{"_content_type_set", T_INT, OFF(content_type_set), RO},
1953
{"phase", T_OBJECT, OFF(phase), RO},
1954
{"extension", T_STRING, OFF(extension), RO},
1955
{"hlist", T_OBJECT, OFF(hlo), RO},
1956
{NULL} /* Sentinel */
1965
#ifndef CLEAR_REQUEST_MEMBER
1966
#define CLEAR_REQUEST_MEMBER(member)\
1967
tmp = (PyObject *) member;\
1972
static int request_tp_clear(requestobject *self)
1976
CLEAR_REQUEST_MEMBER(self->dict);
1977
CLEAR_REQUEST_MEMBER(self->connection);
1978
CLEAR_REQUEST_MEMBER(self->server);
1979
CLEAR_REQUEST_MEMBER(self->headers_in);
1980
CLEAR_REQUEST_MEMBER(self->headers_out);
1981
CLEAR_REQUEST_MEMBER(self->err_headers_out);
1982
CLEAR_REQUEST_MEMBER(self->subprocess_env);
1983
CLEAR_REQUEST_MEMBER(self->notes);
1984
CLEAR_REQUEST_MEMBER(self->phase);
1985
CLEAR_REQUEST_MEMBER(self->hlo);
1986
CLEAR_REQUEST_MEMBER(self->callbacks);
1998
static void request_tp_dealloc(requestobject *self)
2000
/* de-register the object from the GC
2001
* before its deallocation, to prevent the
2002
* GC to run on a partially de-allocated object
2004
PyObject_GC_UnTrack(self);
2006
/* self->rebuff is used by req_readline.
2007
* It may not have been freed if req_readline was not
2008
* enough times to consume rbuff's contents.
2010
if (self->rbuff != NULL)
2013
request_tp_clear(self);
2015
PyObject_GC_Del(self);
2019
** request_tp_traverse
2021
* Traversal of the request object
2023
#ifndef VISIT_REQUEST_MEMBER
2024
#define VISIT_REQUEST_MEMBER(member, visit, arg)\
2026
result = visit(member, arg);\
2032
static int request_tp_traverse(requestobject* self, visitproc visit, void *arg) {
2034
VISIT_REQUEST_MEMBER(self->dict, visit, arg);
2035
VISIT_REQUEST_MEMBER(self->connection, visit, arg);
2036
VISIT_REQUEST_MEMBER(self->server, visit, arg);
2037
VISIT_REQUEST_MEMBER(self->headers_in, visit, arg);
2038
VISIT_REQUEST_MEMBER(self->headers_out, visit, arg);
2039
VISIT_REQUEST_MEMBER(self->err_headers_out, visit, arg);
2040
VISIT_REQUEST_MEMBER(self->subprocess_env, visit, arg);
2041
VISIT_REQUEST_MEMBER(self->notes, visit, arg);
2042
VISIT_REQUEST_MEMBER(self->phase, visit, arg);
2044
/* no need to Py_DECREF(dict) since the reference is borrowed */
2047
static char request_doc[] =
2048
"Apache request_rec structure\n";
2050
PyTypeObject MpRequest_Type = {
2051
PyObject_HEAD_INIT(NULL)
2054
sizeof(requestobject),
2056
(destructor)request_tp_dealloc, /*tp_dealloc*/
2063
0, /*tp_as_sequence*/
2064
0, /*tp_as_mapping*/
2068
PyObject_GenericGetAttr, /* tp_getattro */
2069
PyObject_GenericSetAttr, /* tp_setattro */
2070
0, /* tp_as_buffer */
2071
Py_TPFLAGS_DEFAULT |
2072
Py_TPFLAGS_BASETYPE|
2073
Py_TPFLAGS_HAVE_GC , /* tp_flags */
2074
request_doc, /* tp_doc */
2075
(traverseproc)request_tp_traverse, /* tp_traverse */
2076
/* PYTHON 2.5: 'inquiry' should be perhaps replaced with 'lenfunc' */
2077
(inquiry)request_tp_clear, /* tp_clear */
2078
0, /* tp_richcompare */
2079
0, /* tp_weaklistoffset */
2081
0, /* tp_iternext */
2082
request_methods, /* tp_methods */
2083
request_members, /* tp_members */
2084
request_getsets, /* tp_getset */
2087
0, /* tp_descr_get */
2088
0, /* tp_descr_set */
2089
offsetof(requestobject, dict), /* tp_dictoffset */