~ubuntu-branches/ubuntu/dapper/libapache2-mod-python/dapper-security

« back to all changes in this revision

Viewing changes to src/requestobject.c

  • Committer: Bazaar Package Importer
  • Author(s): Thom May
  • Date: 2004-09-06 20:27:57 UTC
  • Revision ID: james.westby@ubuntu.com-20040906202757-yzpyu1bcabgpjtiu
Tags: upstream-3.1.3
ImportĀ upstreamĀ versionĀ 3.1.3

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/*
 
2
 * Copyright 2004 Apache Software Foundation 
 
3
 * 
 
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
 
7
 *
 
8
 *      http://www.apache.org/licenses/LICENSE-2.0
 
9
 *
 
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.
 
15
 *
 
16
 * Originally developed by Gregory Trubetskoy.
 
17
 *
 
18
 *
 
19
 * requestobject.c 
 
20
 *
 
21
 * $Id: requestobject.c,v 1.57 2004/02/16 19:47:27 grisha Exp $
 
22
 *
 
23
 */
 
24
 
 
25
#include "mod_python.h"
 
26
 
 
27
/**
 
28
 **     MpRequest_FromRequest
 
29
 **
 
30
 *      This routine creates a Python requestobject given an Apache
 
31
 *      request_rec pointer.
 
32
 *
 
33
 */
 
34
 
 
35
PyObject * MpRequest_FromRequest(request_rec *req)
 
36
{
 
37
    requestobject *result;
 
38
 
 
39
    result = PyObject_New(requestobject, &MpRequest_Type);
 
40
    if (! result)
 
41
        return PyErr_NoMemory();
 
42
 
 
43
    result->dict = PyDict_New();
 
44
    if (!result->dict)
 
45
        return PyErr_NoMemory();
 
46
    result->request_rec = req;
 
47
    result->connection = NULL;
 
48
    result->server = NULL;
 
49
    result->next = NULL;
 
50
    result->prev = NULL;
 
51
    result->main = NULL;
 
52
    result->headers_in = MpTable_FromTable(req->headers_in);
 
53
    result->headers_out = MpTable_FromTable(req->headers_out);
 
54
    result->err_headers_out = MpTable_FromTable(req->err_headers_out);
 
55
    result->subprocess_env = MpTable_FromTable(req->subprocess_env);
 
56
    result->notes = MpTable_FromTable(req->notes);
 
57
    result->phase = NULL;
 
58
    result->extension = NULL;
 
59
    result->interpreter = NULL;
 
60
    result->content_type_set = 0;
 
61
    result->hlo = NULL;
 
62
    result->rbuff = NULL;
 
63
    result->rbuff_pos = 0;
 
64
    result->rbuff_len = 0;
 
65
 
 
66
    return (PyObject *) result;
 
67
}
 
68
 
 
69
/* Methods */
 
70
 
 
71
/**
 
72
 ** request.add_common_vars(reqeust self)
 
73
 **
 
74
 *     Interface to ap_add_common_vars. Adds a bunch of CGI
 
75
 *     environment variables.
 
76
 *
 
77
 */
 
78
 
 
79
static PyObject * req_add_common_vars(requestobject *self)
 
80
{
 
81
 
 
82
    ap_add_common_vars(self->request_rec);
 
83
 
 
84
    Py_INCREF(Py_None);
 
85
    return Py_None;
 
86
 
 
87
}
 
88
 
 
89
/**
 
90
 ** valid_phase()
 
91
 **
 
92
 *  utility func - makes sure a phase is valid
 
93
 */
 
94
 
 
95
static int valid_phase(const char *p)
 
96
{
 
97
    if ((strcmp(p, "PythonHandler") != 0) &&
 
98
        (strcmp(p, "PythonAuthenHandler") != 0) &&
 
99
        (strcmp(p, "PythonPostReadRequestHandler") != 0) &&
 
100
        (strcmp(p, "PythonTransHandler") != 0) &&
 
101
        (strcmp(p, "PythonHeaderParserHandler") != 0) &&
 
102
        (strcmp(p, "PythonAccessHandler") != 0) &&
 
103
        (strcmp(p, "PythonAuthzHandler") != 0) &&
 
104
        (strcmp(p, "PythonTypeHandler") != 0) &&
 
105
        (strcmp(p, "PythonFixupHandler") != 0) &&
 
106
        (strcmp(p, "PythonLogHandler") != 0) &&
 
107
        (strcmp(p, "PythonInitHandler") != 0))
 
108
        return 0;
 
109
    else
 
110
        return 1;
 
111
}
 
112
 
 
113
/**
 
114
 ** request.add_handler(request self, string phase, string handler)
 
115
 **
 
116
 *     Allows to add another handler to the handler list.
 
117
 */
 
118
 
 
119
static PyObject *req_add_handler(requestobject *self, PyObject *args)
 
120
{
 
121
    char *phase;
 
122
    char *handler;
 
123
    const char *dir = NULL;
 
124
    const char *currphase;
 
125
 
 
126
    if (! PyArg_ParseTuple(args, "ss|s", &phase, &handler, &dir)) 
 
127
        return NULL;
 
128
 
 
129
    if (! valid_phase(phase)) {
 
130
        PyErr_SetString(PyExc_IndexError, 
 
131
                        apr_psprintf(self->request_rec->pool,
 
132
                                     "Invalid phase: %s", phase));
 
133
        return NULL;
 
134
    }
 
135
    
 
136
    /* which phase are we processing? */
 
137
    currphase = PyString_AsString(self->phase);
 
138
 
 
139
    /* are we in same phase as what's being added? */
 
140
    if (strcmp(currphase, phase) == 0) {
 
141
 
 
142
        /* then just append to hlist */
 
143
        hlist_append(self->request_rec->pool, self->hlo->head,
 
144
                     handler, dir, 0);
 
145
    }
 
146
    else {
 
147
        /* this is a phase that we're not in */
 
148
 
 
149
        py_req_config *req_config;
 
150
        hl_entry *hle;
 
151
 
 
152
        /* get request config */
 
153
        req_config = (py_req_config *) 
 
154
            ap_get_module_config(self->request_rec->request_config,
 
155
                                 &python_module);
 
156
 
 
157
        hle = apr_hash_get(req_config->dynhls, phase, APR_HASH_KEY_STRING);
 
158
 
 
159
        if (! hle) {
 
160
            hle = hlist_new(self->request_rec->pool, handler, dir, 0);
 
161
            apr_hash_set(req_config->dynhls, phase, APR_HASH_KEY_STRING, hle);
 
162
        }
 
163
        else {
 
164
            hlist_append(self->request_rec->pool, hle, handler, dir, 0);
 
165
        }
 
166
    }
 
167
    
 
168
    Py_INCREF(Py_None);
 
169
    return Py_None;
 
170
}
 
171
 
 
172
/**
 
173
 ** request.allow_methods(request self, list methods, reset=0)
 
174
 **
 
175
 *  a wrapper around ap_allow_methods. (used for the "allow:" header
 
176
 *  to be passed to client when needed.)
 
177
 */
 
178
 
 
179
static PyObject *req_allow_methods(requestobject *self, PyObject *args)
 
180
{
 
181
    
 
182
    PyObject *methods;
 
183
    int reset = 0;
 
184
    int len, i;
 
185
 
 
186
    if (! PyArg_ParseTuple(args, "O|i", &methods, &reset)) 
 
187
        return NULL;
 
188
 
 
189
    if (! PySequence_Check(methods)){
 
190
        PyErr_SetString(PyExc_TypeError,
 
191
                        "First argument must be a sequence");
 
192
        return NULL;
 
193
    }
 
194
 
 
195
    len = PySequence_Length(methods);
 
196
 
 
197
    if (len) {
 
198
 
 
199
        PyObject *method;
 
200
 
 
201
        method = PySequence_GetItem(methods, 0);
 
202
        if (! PyString_Check(method)) {
 
203
            PyErr_SetString(PyExc_TypeError, 
 
204
                            "Methods must be strings");
 
205
            return NULL;
 
206
        }
 
207
 
 
208
        ap_allow_methods(self->request_rec, (reset == REPLACE_ALLOW), 
 
209
                         PyString_AS_STRING(method), NULL);
 
210
 
 
211
        for (i = 1; i < len; i++) {
 
212
            method = PySequence_GetItem(methods, i);
 
213
            if (! PyString_Check(method)) {
 
214
                PyErr_SetString(PyExc_TypeError, 
 
215
                                "Methods must be strings");
 
216
                return NULL;
 
217
            }
 
218
 
 
219
            ap_allow_methods(self->request_rec, MERGE_ALLOW, 
 
220
                             PyString_AS_STRING(method), NULL);
 
221
        }
 
222
    }
 
223
    
 
224
    Py_INCREF(Py_None);
 
225
    return Py_None;
 
226
}
 
227
 
 
228
/**
 
229
 ** request.document_root(self)
 
230
 **
 
231
 *  ap_docuement_root wrapper
 
232
 */
 
233
 
 
234
static PyObject *req_document_root(requestobject *self)
 
235
{
 
236
 
 
237
    return PyString_FromString(ap_document_root(self->request_rec));
 
238
    
 
239
}
 
240
 
 
241
/**
 
242
 ** request.get_basic_auth_pw(request self)
 
243
 **
 
244
 *    get basic authentication password,
 
245
 *    similar to ap_get_basic_auth_pw
 
246
 */
 
247
 
 
248
static PyObject * req_get_basic_auth_pw(requestobject *self, PyObject *args)
 
249
{
 
250
    const char *pw;
 
251
    request_rec *req;
 
252
    
 
253
    req = self->request_rec;
 
254
 
 
255
    if (! ap_get_basic_auth_pw(req, &pw))
 
256
        return PyString_FromString(pw);
 
257
    else {
 
258
        Py_INCREF(Py_None);
 
259
        return Py_None;
 
260
    }
 
261
}
 
262
 
 
263
/**
 
264
 ** request.get_addhandler_exts(request self)
 
265
 **
 
266
 *     Returns file extentions that were given as argument to AddHandler mod_mime
 
267
 *     directive, if any, if at all. This is useful for the Publisher, which can
 
268
 *     chop off file extentions for modules based on this info.
 
269
 *
 
270
 *     XXX Due to the way this is implemented, it is best stay undocumented.
 
271
 */
 
272
 
 
273
static PyObject * req_get_addhandler_exts(requestobject *self, PyObject *args)
 
274
{
 
275
 
 
276
    char *exts = get_addhandler_extensions(self->request_rec);
 
277
 
 
278
    if (exts) 
 
279
        return PyString_FromString(exts);
 
280
    else
 
281
        return PyString_FromString("");
 
282
}
 
283
 
 
284
/**
 
285
 ** request.get_config(request self)
 
286
 **
 
287
 *     Returns the config directives set through Python* apache directives.
 
288
 *     except for Python*Handler and PythonOption (which you get via get_options).
 
289
 */
 
290
 
 
291
static PyObject * req_get_config(requestobject *self)
 
292
{
 
293
    py_config *conf =
 
294
        (py_config *) ap_get_module_config(self->request_rec->per_dir_config, 
 
295
                                           &python_module);
 
296
    return MpTable_FromTable(conf->directives);
 
297
}
 
298
 
 
299
/**
 
300
 ** request.get_remodte_host(request self, [int type])
 
301
 **
 
302
 *    An interface to the ap_get_remote_host function.
 
303
 */
 
304
 
 
305
static PyObject * req_get_remote_host(requestobject *self, PyObject *args)
 
306
{
 
307
 
 
308
    int type = REMOTE_NAME;
 
309
    PyObject *str_is_ip = Py_None;
 
310
    int _str_is_ip;
 
311
    const char *host;
 
312
 
 
313
    if (! PyArg_ParseTuple(args, "|iO", &type, &str_is_ip)) 
 
314
        return NULL;
 
315
    
 
316
    if (str_is_ip != Py_None) {
 
317
        host = ap_get_remote_host(self->request_rec->connection, 
 
318
                                  self->request_rec->per_dir_config, type, &_str_is_ip);
 
319
    }
 
320
    else {
 
321
        host = ap_get_remote_host(self->request_rec->connection, 
 
322
                                  self->request_rec->per_dir_config, type, NULL);
 
323
    }
 
324
 
 
325
    if (! host) {
 
326
        Py_INCREF(Py_None);
 
327
        return Py_None;
 
328
    }
 
329
    else {
 
330
        if (str_is_ip != Py_None) {
 
331
            return Py_BuildValue("(s,i)", host, _str_is_ip);
 
332
        }
 
333
        else {
 
334
            return PyString_FromString(host);
 
335
        }
 
336
    }
 
337
}
 
338
 
 
339
/**
 
340
 ** request.get_options(request self)
 
341
 **
 
342
 */
 
343
 
 
344
static PyObject * req_get_options(requestobject *self, PyObject *args)
 
345
{
 
346
    py_config *conf =
 
347
        (py_config *) ap_get_module_config(self->request_rec->per_dir_config, 
 
348
                                           &python_module);
 
349
    return MpTable_FromTable(conf->options);
 
350
}
 
351
 
 
352
/**
 
353
 ** request.internal_redirect(request self, string newuri)
 
354
 **
 
355
 */
 
356
 
 
357
static PyObject * req_internal_redirect(requestobject *self, PyObject *args)
 
358
{
 
359
    char *new_uri;
 
360
 
 
361
    if (! PyArg_ParseTuple(args, "z", &new_uri))
 
362
        return NULL; /* error */
 
363
 
 
364
    Py_BEGIN_ALLOW_THREADS
 
365
    ap_internal_redirect(new_uri, self->request_rec);
 
366
    Py_END_ALLOW_THREADS
 
367
 
 
368
    Py_INCREF(Py_None);
 
369
    return Py_None;
 
370
}
 
371
 
 
372
/**
 
373
 ** request.log_error(req self, string message, int level)
 
374
 **
 
375
 *     calls ap_log_rerror
 
376
 */
 
377
 
 
378
static PyObject * req_log_error(requestobject *self, PyObject *args)
 
379
{
 
380
    int level = 0;
 
381
    char *message = NULL;
 
382
 
 
383
    if (! PyArg_ParseTuple(args, "z|i", &message, &level))
 
384
        return NULL; /* error */
 
385
 
 
386
    if (message) {
 
387
 
 
388
        if (! level)
 
389
            level = APLOG_NOERRNO|APLOG_ERR;
 
390
 
 
391
        ap_log_rerror(APLOG_MARK, level, 0, self->request_rec, "%s", message);
 
392
    }
 
393
 
 
394
    Py_INCREF(Py_None);
 
395
    return Py_None;
 
396
}
 
397
 
 
398
/**
 
399
 ** request.read(request self, int bytes)
 
400
 **
 
401
 *     Reads stuff like POST requests from the client
 
402
 *     (based on the old net_read)
 
403
 */
 
404
 
 
405
static PyObject * req_read(requestobject *self, PyObject *args)
 
406
{
 
407
    int rc, bytes_read, chunk_len;
 
408
    char *buffer;
 
409
    PyObject *result;
 
410
    int copied = 0;
 
411
    long len = -1;
 
412
 
 
413
    if (! PyArg_ParseTuple(args, "|l", &len)) 
 
414
        return NULL;
 
415
 
 
416
    if (len == 0) {
 
417
        return PyString_FromString("");
 
418
    }
 
419
 
 
420
    /* is this the first read? */
 
421
    if (! self->request_rec->read_length) {
 
422
 
 
423
        /* then do some initial setting up */
 
424
        rc = ap_setup_client_block(self->request_rec, REQUEST_CHUNKED_ERROR);
 
425
        if(rc != OK) {
 
426
            PyObject *val = PyInt_FromLong(rc);
 
427
            if (val == NULL)
 
428
                return NULL;
 
429
            PyErr_SetObject(get_ServerReturn(), val);
 
430
            Py_DECREF(val);
 
431
            return NULL;
 
432
        }
 
433
 
 
434
        if (! ap_should_client_block(self->request_rec)) {
 
435
            /* client has nothing to send */
 
436
            return PyString_FromString("");
 
437
        }
 
438
    }
 
439
 
 
440
    if (len < 0)
 
441
        /* XXX ok to use request_rec->remaining? */
 
442
        len = self->request_rec->remaining +
 
443
            (self->rbuff_len - self->rbuff_pos);
 
444
 
 
445
    result = PyString_FromStringAndSize(NULL, len);
 
446
 
 
447
    /* possibly no more memory */
 
448
    if (result == NULL) 
 
449
        return NULL;
 
450
 
 
451
    buffer = PyString_AS_STRING((PyStringObject *) result);
 
452
 
 
453
    /* if anything left in the readline buffer */
 
454
    while ((self->rbuff_pos < self->rbuff_len) && (copied < len))
 
455
        buffer[copied++] = self->rbuff[self->rbuff_pos++];
 
456
    
 
457
    /* Free rbuff if we're done with it */
 
458
    if (self->rbuff_pos >= self->rbuff_len && self->rbuff != NULL) {
 
459
        free(self->rbuff);
 
460
        self->rbuff = NULL;
 
461
    }
 
462
 
 
463
    if (copied == len)
 
464
        return result;  /* we're done! */
 
465
 
 
466
    /* read it in */
 
467
    Py_BEGIN_ALLOW_THREADS
 
468
    chunk_len = ap_get_client_block(self->request_rec, buffer, len);
 
469
    Py_END_ALLOW_THREADS
 
470
    bytes_read = chunk_len;
 
471
 
 
472
    /* if this is a "short read", try reading more */
 
473
    while ((bytes_read < len) && (chunk_len != 0)) {
 
474
        Py_BEGIN_ALLOW_THREADS
 
475
        chunk_len = ap_get_client_block(self->request_rec, 
 
476
                                        buffer+bytes_read, len-bytes_read);
 
477
        Py_END_ALLOW_THREADS
 
478
        if (chunk_len == -1) {
 
479
            PyErr_SetObject(PyExc_IOError, 
 
480
                            PyString_FromString("Client read error (Timeout?)"));
 
481
            return NULL;
 
482
        }
 
483
        else
 
484
            bytes_read += chunk_len;
 
485
    }
 
486
 
 
487
    /* resize if necessary */
 
488
    if (bytes_read < len) 
 
489
        if(_PyString_Resize(&result, bytes_read))
 
490
            return NULL;
 
491
 
 
492
    return result;
 
493
}
 
494
 
 
495
/**
 
496
 ** request.readline(request self, int maxbytes)
 
497
 **
 
498
 *     Reads stuff like POST requests from the client
 
499
 *     (based on the old net_read) until EOL
 
500
 */
 
501
 
 
502
static PyObject * req_readline(requestobject *self, PyObject *args)
 
503
{
 
504
 
 
505
    int rc, chunk_len, bytes_read;
 
506
    char *buffer;
 
507
    PyObject *result;
 
508
    int copied = 0;
 
509
    long len = -1;
 
510
 
 
511
    if (! PyArg_ParseTuple(args, "|l", &len)) 
 
512
        return NULL;
 
513
 
 
514
    if (len == 0) {
 
515
        return PyString_FromString("");
 
516
    }
 
517
 
 
518
    /* is this the first read? */
 
519
    if (! self->request_rec->read_length) {
 
520
 
 
521
        /* then do some initial setting up */
 
522
        rc = ap_setup_client_block(self->request_rec, REQUEST_CHUNKED_ERROR);
 
523
 
 
524
        if(rc != OK) {
 
525
            PyObject *val = PyInt_FromLong(rc);
 
526
            if (val == NULL)
 
527
                return NULL;
 
528
            PyErr_SetObject(get_ServerReturn(), val);
 
529
            Py_DECREF(val);
 
530
            return NULL;
 
531
        }
 
532
 
 
533
        if (! ap_should_client_block(self->request_rec)) {
 
534
            /* client has nothing to send */
 
535
            return PyString_FromString("");
 
536
        }
 
537
    }
 
538
 
 
539
    if (len < 0)
 
540
        len = self->request_rec->remaining + 
 
541
            (self->rbuff_len - self->rbuff_pos);
 
542
 
 
543
    /* create the result buffer */
 
544
    result = PyString_FromStringAndSize(NULL, len);
 
545
 
 
546
    /* possibly no more memory */
 
547
    if (result == NULL) 
 
548
        return NULL;
 
549
 
 
550
    buffer = PyString_AS_STRING((PyStringObject *) result);
 
551
 
 
552
    /* is there anything left in the rbuff from previous reads? */
 
553
    if (self->rbuff_pos < self->rbuff_len) {
 
554
        
 
555
        /* if yes, process that first */
 
556
        while (self->rbuff_pos < self->rbuff_len) {
 
557
 
 
558
            buffer[copied++] = self->rbuff[self->rbuff_pos];
 
559
            if ((self->rbuff[self->rbuff_pos++] == '\n') || 
 
560
                (copied == len)) {
 
561
 
 
562
                /* our work is done */
 
563
 
 
564
                /* resize if necessary */
 
565
                if (copied < len) 
 
566
                    if(_PyString_Resize(&result, copied))
 
567
                        return NULL;
 
568
 
 
569
                return result;
 
570
            }
 
571
        }
 
572
    }
 
573
 
 
574
    /* Free old rbuff as the old contents have been copied over and
 
575
       we are about to allocate a new rbuff. Perhaps this could be reused
 
576
       somehow? */
 
577
    if (self->rbuff_pos >= self->rbuff_len && self->rbuff != NULL)
 
578
    {
 
579
        free(self->rbuff);
 
580
        self->rbuff = NULL;
 
581
    }
 
582
 
 
583
    /* if got this far, the buffer should be empty, we need to read more */
 
584
        
 
585
    /* create a read buffer */
 
586
    self->rbuff_len = len > HUGE_STRING_LEN ? len : HUGE_STRING_LEN;
 
587
    self->rbuff_pos = self->rbuff_len;
 
588
    self->rbuff = malloc(self->rbuff_len);
 
589
    if (! self->rbuff)
 
590
        return PyErr_NoMemory();
 
591
 
 
592
    /* read it in */
 
593
    Py_BEGIN_ALLOW_THREADS
 
594
        chunk_len = ap_get_client_block(self->request_rec, self->rbuff, 
 
595
                                        self->rbuff_len);
 
596
    Py_END_ALLOW_THREADS;
 
597
    bytes_read = chunk_len;
 
598
 
 
599
    /* if this is a "short read", try reading more */
 
600
    while ((chunk_len != 0 ) && (bytes_read + copied < len)) {
 
601
 
 
602
        Py_BEGIN_ALLOW_THREADS
 
603
            chunk_len = ap_get_client_block(self->request_rec, 
 
604
                                            self->rbuff + bytes_read, 
 
605
                                            self->rbuff_len - bytes_read);
 
606
        Py_END_ALLOW_THREADS
 
607
 
 
608
        if (chunk_len == -1) {
 
609
 
 
610
            /* Free rbuff since returning NULL here should end the request */
 
611
            free(self->rbuff);
 
612
            self->rbuff = NULL;
 
613
 
 
614
            PyErr_SetObject(PyExc_IOError, 
 
615
                            PyString_FromString("Client read error (Timeout?)"));
 
616
            return NULL;
 
617
        }
 
618
        else
 
619
            bytes_read += chunk_len;
 
620
    }
 
621
    self->rbuff_len = bytes_read;
 
622
    self->rbuff_pos = 0;
 
623
 
 
624
    /* now copy the remaining bytes */
 
625
    while (self->rbuff_pos < self->rbuff_len) {
 
626
 
 
627
        buffer[copied++] = self->rbuff[self->rbuff_pos];
 
628
        if ((self->rbuff[self->rbuff_pos++] == '\n') || 
 
629
            (copied == len)) 
 
630
            /* our work is done */
 
631
            break;
 
632
    }
 
633
 
 
634
    /* Free rbuff if we're done with it */
 
635
    if (self->rbuff_pos >= self->rbuff_len && self->rbuff != NULL)
 
636
    {
 
637
        free(self->rbuff);
 
638
        self->rbuff = NULL;
 
639
    }
 
640
 
 
641
    /* resize if necessary */
 
642
    if (copied < len) 
 
643
        if(_PyString_Resize(&result, copied))
 
644
            return NULL;
 
645
 
 
646
    return result;
 
647
}
 
648
 
 
649
/**
 
650
 ** request.readlines([long maxsize])
 
651
 **
 
652
 *    just like file.readlines()
 
653
 */
 
654
 
 
655
static PyObject *req_readlines(requestobject *self, PyObject *args)
 
656
{
 
657
 
 
658
    PyObject *result = PyList_New(0);
 
659
    PyObject *line, *rlargs;
 
660
    long sizehint = -1;
 
661
    long size = 0;
 
662
 
 
663
    if (! PyArg_ParseTuple(args, "|l", &sizehint)) 
 
664
        return NULL;
 
665
 
 
666
    if (result == NULL)
 
667
        return PyErr_NoMemory();
 
668
 
 
669
    rlargs = PyTuple_New(0);
 
670
    if (result == NULL)
 
671
        return PyErr_NoMemory();
 
672
 
 
673
    line = req_readline(self, rlargs);
 
674
    while (line && !(strcmp(PyString_AsString(line), "") == 0)) {
 
675
        PyList_Append(result, line);
 
676
        size += PyString_Size(line);
 
677
        if ((sizehint != -1) && (size >= size))
 
678
            break;
 
679
        line = req_readline(self, args);
 
680
    }
 
681
 
 
682
    if (!line)
 
683
        return NULL;
 
684
 
 
685
    return result;
 
686
}
 
687
 
 
688
/**
 
689
 ** request.register_cleanup(handler, data)
 
690
 **
 
691
 *    registers a cleanup at request pool destruction time. 
 
692
 *    optional data argument will be passed to the cleanup function.
 
693
 */
 
694
 
 
695
static PyObject *req_register_cleanup(requestobject *self, PyObject *args)
 
696
{
 
697
    cleanup_info *ci;
 
698
    PyObject *handler = NULL;
 
699
    PyObject *data = NULL;
 
700
 
 
701
    if (! PyArg_ParseTuple(args, "O|O", &handler, &data))
 
702
        return NULL;  /* bad args */
 
703
 
 
704
    ci = (cleanup_info *)malloc(sizeof(cleanup_info));
 
705
    ci->request_rec = self->request_rec;
 
706
    ci->server_rec = self->request_rec->server;
 
707
    if (PyCallable_Check(handler)) {
 
708
        Py_INCREF(handler);
 
709
        ci->handler = handler;
 
710
        ci->interpreter = self->interpreter;
 
711
        if (data) {
 
712
            Py_INCREF(data);
 
713
            ci->data = data;
 
714
        }
 
715
        else {
 
716
            Py_INCREF(Py_None);
 
717
            ci->data = Py_None;
 
718
        }
 
719
    }
 
720
    else {
 
721
        PyErr_SetString(PyExc_ValueError, 
 
722
                        "first argument must be a callable object");
 
723
        free(ci);
 
724
        return NULL;
 
725
    }
 
726
 
 
727
    apr_pool_cleanup_register(self->request_rec->pool, ci, python_cleanup, 
 
728
                              apr_pool_cleanup_null);
 
729
 
 
730
    Py_INCREF(Py_None);
 
731
    return Py_None;
 
732
 
 
733
}
 
734
 
 
735
/**
 
736
 ** request.requires(self)
 
737
 **
 
738
 *     Interface to ap_requires()
 
739
 */
 
740
 
 
741
static PyObject * req_requires(requestobject *self)
 
742
{
 
743
 
 
744
    /* This function returns everything specified after the "requires"
 
745
       as is, without any attempts to parse/organize because
 
746
       "requires" args only need to be grokable by mod_auth if it is
 
747
       authoritative. When AuthAuthoritative is off, anything can
 
748
       follow requires, e.g. "requires role terminator".
 
749
    */
 
750
 
 
751
    const apr_array_header_t *reqs_arr = ap_requires(self->request_rec);
 
752
    require_line *reqs;
 
753
    int i, ti = 0;
 
754
 
 
755
    PyObject *result;
 
756
 
 
757
    if (!reqs_arr) {
 
758
        return Py_BuildValue("()");
 
759
    }
 
760
 
 
761
    result = PyTuple_New(reqs_arr->nelts);
 
762
 
 
763
    reqs = (require_line *) reqs_arr->elts;
 
764
 
 
765
    for (i = 0; i < reqs_arr->nelts; ++i) {
 
766
        if (reqs[i].method_mask & (AP_METHOD_BIT << self->request_rec->method_number)) {
 
767
            PyTuple_SetItem(result, ti++, 
 
768
                            PyString_FromString(reqs[i].requirement));
 
769
        }
 
770
    }
 
771
 
 
772
    _PyTuple_Resize(&result, ti);
 
773
 
 
774
    return result;
 
775
}
 
776
 
 
777
/**
 
778
 ** request.send_http_header(request self)
 
779
 **
 
780
 *      this is a noop, just so we don't break old scripts
 
781
 */
 
782
 
 
783
static PyObject * req_send_http_header(requestobject *self)
 
784
{
 
785
    Py_INCREF(Py_None);
 
786
    return Py_None;
 
787
}
 
788
 
 
789
/**
 
790
 ** request.set_content_length(request self, long content_length)
 
791
 **
 
792
 *      write output to the client
 
793
 */
 
794
 
 
795
static PyObject * req_set_content_length(requestobject *self, PyObject *args)
 
796
{
 
797
    long len;
 
798
 
 
799
    if (! PyArg_ParseTuple(args, "l", &len))
 
800
        return NULL;  /* bad args */
 
801
 
 
802
    ap_set_content_length(self->request_rec, len);
 
803
 
 
804
    Py_INCREF(Py_None);
 
805
    return Py_None;
 
806
}
 
807
 
 
808
/**
 
809
 ** request.write(request self, string what, flush=1)
 
810
 **
 
811
 *      write output to the client
 
812
 */
 
813
 
 
814
static PyObject * req_write(requestobject *self, PyObject *args)
 
815
{
 
816
    int len;
 
817
    int rc;
 
818
    char *buff;
 
819
    int flush=1;
 
820
 
 
821
    if (! PyArg_ParseTuple(args, "s#|i", &buff, &len, &flush))
 
822
        return NULL;  /* bad args */
 
823
 
 
824
    if (len > 0 ) {
 
825
 
 
826
        Py_BEGIN_ALLOW_THREADS
 
827
        rc = ap_rwrite(buff, len, self->request_rec);
 
828
        if (flush && (rc != -1))
 
829
            rc = ap_rflush(self->request_rec);
 
830
        Py_END_ALLOW_THREADS
 
831
            if (rc == -1) {
 
832
                PyErr_SetString(PyExc_IOError, "Write failed, client closed connection.");
 
833
                return NULL;
 
834
            }
 
835
    }
 
836
 
 
837
    Py_INCREF(Py_None);
 
838
    return Py_None;
 
839
 
 
840
}
 
841
 
 
842
/**
 
843
 ** request.flush(request self)
 
844
 **
 
845
 *      flush output buffer
 
846
 */
 
847
 
 
848
static PyObject * req_flush(requestobject *self)
 
849
{
 
850
    int rc;
 
851
 
 
852
    Py_BEGIN_ALLOW_THREADS
 
853
    rc = ap_rflush(self->request_rec);
 
854
    Py_END_ALLOW_THREADS
 
855
    if (rc == -1) {
 
856
        PyErr_SetString(PyExc_IOError, "Flush failed, client closed connection.");
 
857
        return NULL;
 
858
    }
 
859
 
 
860
    Py_INCREF(Py_None);
 
861
    return Py_None;
 
862
}
 
863
 
 
864
/**
 
865
 ** request.sendfile
 
866
 **
 
867
 */
 
868
 
 
869
static PyObject * req_sendfile(requestobject *self, PyObject *args)
 
870
{
 
871
    char *fname;
 
872
    apr_file_t *fd;
 
873
    apr_size_t offset=0, len=-1, nbytes;
 
874
    apr_status_t status;
 
875
    PyObject * py_result = NULL;
 
876
    apr_finfo_t finfo;
 
877
    
 
878
    if (! PyArg_ParseTuple(args, "s|ll", &fname, &offset, &len))
 
879
        return NULL;  /* bad args */
 
880
 
 
881
    Py_BEGIN_ALLOW_THREADS
 
882
    status=apr_stat(&finfo, fname,
 
883
                    APR_READ, self->request_rec->pool);
 
884
    Py_END_ALLOW_THREADS
 
885
    if (status != APR_SUCCESS) {
 
886
        PyErr_SetString(PyExc_IOError, "Could not stat file for reading");
 
887
        return NULL;
 
888
    }
 
889
    
 
890
    Py_BEGIN_ALLOW_THREADS                         
 
891
    status=apr_file_open(&fd, fname,
 
892
                         APR_READ, finfo.protection,
 
893
                         self->request_rec->pool);
 
894
    Py_END_ALLOW_THREADS
 
895
    if (status != APR_SUCCESS) {
 
896
        PyErr_SetString(PyExc_IOError, "Could not open file for reading");
 
897
        return NULL;
 
898
    }                         
 
899
    
 
900
    if (len==-1) len=finfo.size;
 
901
        
 
902
    Py_BEGIN_ALLOW_THREADS                         
 
903
        status = ap_send_fd(fd, self->request_rec, offset, 
 
904
                            len, &nbytes);
 
905
    Py_END_ALLOW_THREADS
 
906
    
 
907
    if (status != APR_SUCCESS) {
 
908
        PyErr_SetString(PyExc_IOError, "Write failed, client closed connection.");
 
909
        return NULL;
 
910
    }
 
911
 
 
912
    py_result = PyLong_FromLong (nbytes);
 
913
    Py_INCREF(py_result);
 
914
    return py_result;
 
915
}
 
916
 
 
917
static PyMethodDef request_methods[] = {
 
918
    {"add_common_vars",       (PyCFunction) req_add_common_vars,       METH_NOARGS},
 
919
    {"add_handler",           (PyCFunction) req_add_handler,           METH_VARARGS},
 
920
    {"allow_methods",         (PyCFunction) req_allow_methods,         METH_VARARGS},
 
921
    {"document_root",         (PyCFunction) req_document_root,         METH_NOARGS},
 
922
    {"flush",                 (PyCFunction) req_flush,                 METH_NOARGS},
 
923
    {"get_basic_auth_pw",     (PyCFunction) req_get_basic_auth_pw,     METH_NOARGS},
 
924
    {"get_addhandler_exts",   (PyCFunction) req_get_addhandler_exts,   METH_NOARGS},
 
925
    {"get_config",            (PyCFunction) req_get_config,            METH_NOARGS},
 
926
    {"get_remote_host",       (PyCFunction) req_get_remote_host,       METH_VARARGS},
 
927
    {"get_options",           (PyCFunction) req_get_options,           METH_NOARGS},
 
928
    {"internal_redirect",     (PyCFunction) req_internal_redirect,     METH_VARARGS},
 
929
    {"log_error",             (PyCFunction) req_log_error,             METH_VARARGS},
 
930
    {"read",                  (PyCFunction) req_read,                  METH_VARARGS},
 
931
    {"readline",              (PyCFunction) req_readline,              METH_VARARGS},
 
932
    {"readlines",             (PyCFunction) req_readlines,             METH_VARARGS},
 
933
    {"register_cleanup",      (PyCFunction) req_register_cleanup,      METH_VARARGS},
 
934
    {"requires",              (PyCFunction) req_requires,              METH_NOARGS},
 
935
    {"send_http_header",      (PyCFunction) req_send_http_header,      METH_NOARGS},
 
936
    {"sendfile",              (PyCFunction) req_sendfile,              METH_VARARGS},
 
937
    {"set_content_length",    (PyCFunction) req_set_content_length,    METH_VARARGS},
 
938
    {"write",                 (PyCFunction) req_write,                 METH_VARARGS},
 
939
    { NULL, NULL } /* sentinel */
 
940
};
 
941
 
 
942
 
 
943
/* 
 
944
   These are offsets into the Apache request_rec structure.
 
945
   They are accessed via getset functions. Note that the types
 
946
   specified here are irrelevant if a function other than
 
947
   getreq_recmbr() is used. E.g. bytes_sent is a long long,
 
948
   and is retrieved via getreq_recmbr_off() which ignores what's
 
949
   here.
 
950
*/
 
951
 
 
952
#define OFF(x) offsetof(request_rec, x)
 
953
 
 
954
static struct PyMemberDef request_rec_mbrs[] = {
 
955
    {"the_request",        T_STRING,  OFF(the_request)},
 
956
    {"assbackwards",       T_INT,     OFF(assbackwards)},
 
957
    {"proxyreq",           T_INT,     OFF(proxyreq)},
 
958
    {"header_only",        T_INT,     OFF(header_only)},
 
959
    {"protocol",           T_STRING,  OFF(protocol)},
 
960
    {"proto_num",          T_INT,     OFF(proto_num)},
 
961
    {"hostname",           T_STRING,  OFF(hostname)},
 
962
    {"request_time",       T_LONG,    OFF(request_time)},
 
963
    {"status_line",        T_STRING,  OFF(status_line)},
 
964
    {"status",             T_INT,     OFF(status)},
 
965
    {"method",             T_STRING,  OFF(method)},
 
966
    {"method_number",      T_INT,     OFF(method_number)},
 
967
    {"allowed",            T_LONG,    OFF(allowed)},
 
968
    {"allowed_xmethods",   T_OBJECT,  OFF(allowed_xmethods)},
 
969
    {"allowed_methods",    T_OBJECT,  OFF(allowed_methods)},
 
970
    {"sent_bodyct",        T_LONG,    OFF(sent_bodyct)},
 
971
    {"bytes_sent",         T_LONG,    OFF(bytes_sent)},
 
972
    {"mtime",              T_LONG,    OFF(mtime)},
 
973
    {"chunked",            T_INT,     OFF(chunked)},
 
974
    {"range",              T_STRING,  OFF(range)},
 
975
    {"clength",            T_LONG,    OFF(clength)},
 
976
    {"remaining",          T_LONG,    OFF(remaining)},
 
977
    {"read_length",        T_LONG,    OFF(read_length)},
 
978
    {"read_body",          T_INT,     OFF(read_body)},
 
979
    {"read_chunked",       T_INT,     OFF(read_chunked)},
 
980
    {"expecting_100",      T_INT,     OFF(expecting_100)},
 
981
    {"content_type",       T_STRING,  OFF(content_type)},
 
982
    {"handler",            T_STRING,  OFF(handler)},
 
983
    {"content_encoding",   T_STRING,  OFF(content_encoding)},
 
984
    {"content_languages",  T_OBJECT,  OFF(content_languages)},
 
985
    {"vlist_validator",    T_STRING,  OFF(vlist_validator)},
 
986
    {"user",               T_STRING,  OFF(user)},
 
987
    {"ap_auth_type",       T_STRING,  OFF(ap_auth_type)},
 
988
    {"no_cache",           T_INT,     OFF(no_cache)},
 
989
    {"no_local_copy",      T_INT,     OFF(no_local_copy)},
 
990
    {"unparsed_uri",       T_STRING,  OFF(unparsed_uri)},
 
991
    {"uri",                T_STRING,  OFF(uri)},
 
992
    {"filename",           T_STRING,  OFF(filename)},
 
993
    {"canonical_filename", T_STRING,  OFF(canonical_filename)},
 
994
    {"path_info",          T_STRING,  OFF(path_info)},
 
995
    {"args",               T_STRING,  OFF(args)},
 
996
    {"finfo",              T_OBJECT,  OFF(finfo)},
 
997
    {"parsed_uri",         T_OBJECT,  OFF(parsed_uri)},
 
998
    {"used_path_info",     T_INT,     OFF(used_path_info)},
 
999
    {"eos_sent",           T_INT,     OFF(eos_sent)},
 
1000
    {NULL}  /* Sentinel */
 
1001
};
 
1002
 
 
1003
/**
 
1004
 ** getreq_recmbr
 
1005
 **
 
1006
 *    Retrieves request_rec structure members
 
1007
 */
 
1008
 
 
1009
static PyObject *getreq_recmbr(requestobject *self, void *name) 
 
1010
{
 
1011
    /* 
 
1012
     * apparently at least ap_internal_fast_redirect blatently
 
1013
     * substitute request members, and so we always have to make
 
1014
     * sure that various apr_tables referenced haven't been
 
1015
     * replaced in between handlers and we're left with a stale.
 
1016
     */
 
1017
 
 
1018
    if (strcmp(name, "headers_in") == 0) {
 
1019
        if (((tableobject*)self->headers_in)->table != self->request_rec->headers_in) 
 
1020
            ((tableobject*)self->headers_in)->table = self->request_rec->headers_in;
 
1021
        Py_INCREF(self->headers_in);
 
1022
        return self->headers_in;
 
1023
    }
 
1024
    else if (strcmp(name, "headers_out") == 0) {
 
1025
        if (((tableobject*)self->headers_out)->table != self->request_rec->headers_out) 
 
1026
            ((tableobject*)self->headers_out)->table = self->request_rec->headers_out;
 
1027
        Py_INCREF(self->headers_out);
 
1028
        return self->headers_out;
 
1029
    }
 
1030
    else if (strcmp(name, "err_headers_out") == 0) {
 
1031
        if (((tableobject*)self->err_headers_out)->table != self->request_rec->err_headers_out) 
 
1032
            ((tableobject*)self->err_headers_out)->table = self->request_rec->err_headers_out;
 
1033
        Py_INCREF(self->err_headers_out);
 
1034
        return self->err_headers_out;
 
1035
    }
 
1036
    else if (strcmp(name, "subprocess_env") == 0) {
 
1037
        if (((tableobject*)self->subprocess_env)->table != self->request_rec->subprocess_env) 
 
1038
            ((tableobject*)self->subprocess_env)->table = self->request_rec->subprocess_env;
 
1039
        Py_INCREF(self->subprocess_env);
 
1040
        return self->subprocess_env;
 
1041
    }
 
1042
    else if (strcmp(name, "notes") == 0) {
 
1043
        if (((tableobject*)self->notes)->table != self->request_rec->notes) 
 
1044
            ((tableobject*)self->notes)->table = self->request_rec->notes;
 
1045
        Py_INCREF(self->notes);
 
1046
        return self->notes;
 
1047
    }
 
1048
    else
 
1049
        return PyMember_GetOne((char*)self->request_rec,
 
1050
                               find_memberdef(request_rec_mbrs, name));
 
1051
}
 
1052
 
 
1053
/**
 
1054
 ** setreq_recmbr
 
1055
 **
 
1056
 *    Sets request_rec structure members
 
1057
 */
 
1058
 
 
1059
static int setreq_recmbr(requestobject *self, PyObject *val, void *name) 
 
1060
{
 
1061
 
 
1062
    if (strcmp(name, "content_type") == 0) {
 
1063
        if (! PyString_Check(val)) {
 
1064
            PyErr_SetString(PyExc_TypeError, "content_type must be a string");
 
1065
            return -1;
 
1066
        }
 
1067
        ap_set_content_type(self->request_rec, 
 
1068
                            apr_pstrdup(self->request_rec->pool,
 
1069
                                        PyString_AsString(val)));
 
1070
        self->content_type_set = 1;
 
1071
        return 0;
 
1072
    } 
 
1073
    else if (strcmp(name, "user") == 0) {
 
1074
        if (! PyString_Check(val)) {
 
1075
            PyErr_SetString(PyExc_TypeError, "user must be a string");
 
1076
            return -1;
 
1077
        }
 
1078
        self->request_rec->user = 
 
1079
            apr_pstrdup(self->request_rec->pool, PyString_AsString(val));
 
1080
        return 0;
 
1081
    }
 
1082
    else if (strcmp(name, "filename") == 0) {
 
1083
        if (! PyString_Check(val)) {
 
1084
            PyErr_SetString(PyExc_TypeError, "filename must be a string");
 
1085
            return -1;
 
1086
        }
 
1087
        self->request_rec->filename = 
 
1088
            apr_pstrdup(self->request_rec->pool, PyString_AsString(val));
 
1089
        return 0;
 
1090
    }
 
1091
    
 
1092
    return PyMember_SetOne((char*)self->request_rec, 
 
1093
                           find_memberdef(request_rec_mbrs, (char*)name),
 
1094
                           val);
 
1095
}
 
1096
 
 
1097
/**
 
1098
 ** getreq_recmbr_time
 
1099
 **
 
1100
 *    Retrieves apr_time_t request_rec members
 
1101
 */
 
1102
 
 
1103
static PyObject *getreq_recmbr_time(requestobject *self, void *name) 
 
1104
{
 
1105
    PyMemberDef *md = find_memberdef(request_rec_mbrs, name);
 
1106
    char *addr = (char *)self->request_rec + md->offset;
 
1107
    apr_time_t time = *(apr_time_t*)addr;
 
1108
    return PyFloat_FromDouble(time*0.000001);
 
1109
}
 
1110
 
 
1111
/**
 
1112
 ** getreq_recmbr_off
 
1113
 **
 
1114
 *    Retrieves apr_off_t request_rec members
 
1115
 */
 
1116
 
 
1117
static PyObject *getreq_recmbr_off(requestobject *self, void *name) 
 
1118
{
 
1119
    PyMemberDef *md = find_memberdef(request_rec_mbrs, name);
 
1120
    char *addr = (char *)self->request_rec + md->offset;
 
1121
    if (sizeof(apr_off_t) == sizeof(LONG_LONG)) {
 
1122
        LONG_LONG l = *(LONG_LONG*)addr;
 
1123
        return PyLong_FromLongLong(l);
 
1124
    }
 
1125
    else {
 
1126
        /* assume it's long */
 
1127
        long l = *(long*)addr;
 
1128
        return PyLong_FromLong(l);
 
1129
    }
 
1130
}
 
1131
 
 
1132
/**
 
1133
 ** getreq_rec_ah
 
1134
 **
 
1135
 *    For array headers that will get converted to tuple
 
1136
 */
 
1137
 
 
1138
static PyObject *getreq_rec_ah(requestobject *self, void *name) 
 
1139
{
 
1140
    const PyMemberDef *md = find_memberdef(request_rec_mbrs, name);
 
1141
    apr_array_header_t *ah = 
 
1142
        (apr_array_header_t *)((char *)self->request_rec + md->offset);
 
1143
 
 
1144
    return tuple_from_array_header(ah);
 
1145
}
 
1146
 
 
1147
/**
 
1148
 ** getreq_rec_ml
 
1149
 **
 
1150
 *    For method lists that will get converted to tuple
 
1151
 */
 
1152
 
 
1153
static PyObject *getreq_rec_ml(requestobject *self, void *name) 
 
1154
{
 
1155
    const PyMemberDef *md = find_memberdef(request_rec_mbrs, (char*)name);
 
1156
    ap_method_list_t *ml = 
 
1157
        (ap_method_list_t *)((char *)self->request_rec + md->offset);
 
1158
 
 
1159
    return tuple_from_method_list(ml);
 
1160
}
 
1161
 
 
1162
/**
 
1163
 ** getreq_rec_fi
 
1164
 **
 
1165
 *    For file info that will get converted to tuple
 
1166
 */
 
1167
 
 
1168
static PyObject *getreq_rec_fi(requestobject *self, void *name) 
 
1169
{
 
1170
    const PyMemberDef *md = find_memberdef(request_rec_mbrs, (char*)name);
 
1171
    apr_finfo_t *fi = 
 
1172
        (apr_finfo_t *)((char *)self->request_rec + md->offset);
 
1173
 
 
1174
    return tuple_from_finfo(fi);
 
1175
}
 
1176
 
 
1177
/**
 
1178
 ** getreq_rec_uri
 
1179
 **
 
1180
 *    For parsed uri that will get converted to tuple
 
1181
 */
 
1182
 
 
1183
static PyObject *getreq_rec_uri(requestobject *self, void *name) 
 
1184
{
 
1185
    const PyMemberDef *md = find_memberdef(request_rec_mbrs, (char*)name);
 
1186
    apr_uri_t *uri = (apr_uri_t *)((char *)self->request_rec + md->offset);
 
1187
 
 
1188
    return tuple_from_apr_uri(uri);
 
1189
}
 
1190
 
 
1191
/**
 
1192
 ** getmakeobj
 
1193
 **
 
1194
 *    A getter func that creates an object as needed.
 
1195
 */
 
1196
 
 
1197
static PyObject *getmakeobj(requestobject* self, void *objname) 
 
1198
{
 
1199
    char *name = (char *)objname;
 
1200
    PyObject *result = NULL;
 
1201
 
 
1202
    if (strcmp(name, "connection") == 0) {
 
1203
        if (!self->connection && self->request_rec->connection)
 
1204
            self->connection = MpConn_FromConn(self->request_rec->connection);
 
1205
        result = self->connection;
 
1206
    }
 
1207
    else if (strcmp(name, "server") == 0) {
 
1208
        if (!self->server && self->request_rec->server) 
 
1209
            self->server = MpServer_FromServer(self->request_rec->server);
 
1210
        result = self->server;
 
1211
    }
 
1212
    else if (strcmp(name, "next") == 0) {
 
1213
        if (!self->next && self->request_rec->next)
 
1214
            self->next = MpRequest_FromRequest(self->request_rec->next);
 
1215
        result = self->next;
 
1216
    }
 
1217
    else if (strcmp(name, "prev") == 0) {
 
1218
        if (!self->prev && self->request_rec->prev)
 
1219
            self->prev = MpRequest_FromRequest(self->request_rec->prev);
 
1220
        result = self->prev;
 
1221
    }
 
1222
    else if (strcmp(name, "main") == 0) {
 
1223
        if (!self->main && self->request_rec->main)
 
1224
            self->main = MpRequest_FromRequest(self->request_rec->main);
 
1225
        result = self->main;
 
1226
    }
 
1227
 
 
1228
    if (!result)
 
1229
        result = Py_None;
 
1230
 
 
1231
    Py_INCREF(result);
 
1232
    return result;
 
1233
 
 
1234
}
 
1235
 
 
1236
static PyGetSetDef request_getsets[] = {
 
1237
    {"connection", (getter)getmakeobj, NULL, "Connection object", "connection"},
 
1238
    {"server",     (getter)getmakeobj, NULL, "Server object", "server"},
 
1239
    {"next",       (getter)getmakeobj, NULL, "If redirected, pointer to the to request", "next"},
 
1240
    {"prev",       (getter)getmakeobj, NULL, "If redirected, pointer to the from request", "prev"},
 
1241
    {"main",       (getter)getmakeobj, NULL, "If subrequest, pointer to the main request", "main"},
 
1242
    {"the_request", (getter)getreq_recmbr, NULL, "First line of request", "the_request"},
 
1243
    {"assbackwards", (getter)getreq_recmbr, (setter)setreq_recmbr, "HTTP/0.9 \"simple\" request", "assbackwards"},
 
1244
    {"proxyreq",     (getter)getreq_recmbr, NULL, "A proxy request: one of apache.PROXYREQ_* values", "proxyreq"},
 
1245
    {"header_only",  (getter)getreq_recmbr, NULL, "HEAD request, as oppsed to GET", "header_only"},
 
1246
    {"protocol",     (getter)getreq_recmbr, NULL, "Protocol as given to us, or HTTP/0.9", "protocol"},
 
1247
    {"proto_num",    (getter)getreq_recmbr, NULL, "Protocol version. 1.1 = 1001", "proto_num"},
 
1248
    {"hostname",     (getter)getreq_recmbr, NULL, "Host, as set by full URI or Host:", "hostname"},
 
1249
    {"request_time", (getter)getreq_recmbr_time, NULL, "When request started", "request_time"},
 
1250
    {"status_line",  (getter)getreq_recmbr, NULL, "Status line, if set by script", "status_line"},
 
1251
    {"status",       (getter)getreq_recmbr, (setter)setreq_recmbr, "Status", "status"},
 
1252
    {"method",       (getter)getreq_recmbr, NULL, "Request method", "method"},
 
1253
    {"method_number", (getter)getreq_recmbr, NULL, "Request method number, one of apache.M_*", "method_number"},
 
1254
    {"allowed",      (getter)getreq_recmbr, NULL, "Status", "allowed"},
 
1255
    {"allowed_xmethods", (getter)getreq_rec_ah, NULL, "Allowed extension methods", "allowed_xmethods"},
 
1256
    {"allowed_methods", (getter)getreq_rec_ml, NULL, "Allowed methods", "allowed_methods"},
 
1257
    {"sent_bodyct",  (getter)getreq_recmbr_off, NULL, "Byte count in stream for body", "sent_bodyct"},
 
1258
    {"bytes_sent",   (getter)getreq_recmbr_off, NULL, "Bytes sent", "bytes_sent"},
 
1259
    {"mtime",        (getter)getreq_recmbr_time, NULL, "Time resource was last modified", "mtime"},
 
1260
    {"chunked",      (getter)getreq_recmbr, NULL, "Sending chunked transfer-coding", "chunked"},
 
1261
    {"boundary",     (getter)getreq_recmbr, NULL, "Multipart/byteranges boundary", "boundary"},
 
1262
    {"range",        (getter)getreq_recmbr, NULL, "The Range: header", "range"},
 
1263
    {"clength",      (getter)getreq_recmbr_off, NULL, "The \"real\" contenct length", "clength"},
 
1264
    {"remaining",    (getter)getreq_recmbr_off, NULL, "Bytes left to read", "remaining"},
 
1265
    {"read_length",  (getter)getreq_recmbr_off, NULL, "Bytes that have been read", "read_length"},
 
1266
    {"read_body",    (getter)getreq_recmbr, NULL, "How the request body should be read", "read_body"},
 
1267
    {"read_chunked", (getter)getreq_recmbr, NULL, "Reading chunked transfer-coding", "read_chunked"},
 
1268
    {"expecting_100", (getter)getreq_recmbr, NULL, "Is client waitin for a 100 response?", "expecting_100"},
 
1269
    {"content_type",  (getter)getreq_recmbr, (setter)setreq_recmbr, "Content type", "content_type"},
 
1270
    {"handler",       (getter)getreq_recmbr, NULL, "The handler string", "handler"},
 
1271
    {"content_encoding", (getter)getreq_recmbr, NULL, "How to encode the data", "content_encoding"},
 
1272
    {"content_languages", (getter)getreq_rec_ah, NULL, "Content languages", "content_languages"},
 
1273
    {"vlist_validator", (getter)getreq_recmbr, NULL, "Variant list validator (if negotiated)", "vlist_validator"},
 
1274
    {"user",          (getter)getreq_recmbr, (setter)setreq_recmbr, "If authentication check was made, the user name", "user"},
 
1275
    {"ap_auth_type",  (getter)getreq_recmbr, NULL, "If authentication check was made, auth type", "ap_auth_type"},
 
1276
    {"no_cache",      (getter)getreq_recmbr, NULL, "This response in non-cacheable", "no_cache"},
 
1277
    {"no_local_copy", (getter)getreq_recmbr, NULL, "There is no local copy of the response", "no_local_copy"},
 
1278
    {"unparsed_uri",  (getter)getreq_recmbr, NULL, "The URI without any parsing performed", "unparsed_uri"},
 
1279
    {"uri",           (getter)getreq_recmbr, NULL, "The path portion of URI", "uri"},
 
1280
    {"filename",      (getter)getreq_recmbr, (setter)setreq_recmbr, "The file name on disk that this request corresponds to", "filename"},
 
1281
    {"canonical_filename", (getter)getreq_recmbr, NULL, "The true filename (req.filename is canonicalized if they dont match)", "canonical_filename"},
 
1282
    {"path_info",     (getter)getreq_recmbr, NULL, "Path_info, if any", "path_info"},
 
1283
    {"args",          (getter)getreq_recmbr, NULL, "QUERY_ARGS, if any", "args"},
 
1284
    {"finfo",         (getter)getreq_rec_fi, NULL, "File information", "finfo"},
 
1285
    {"parsed_uri",    (getter)getreq_rec_uri, NULL, "Components of URI", "parsed_uri"},
 
1286
    {"used_path_info", (getter)getreq_recmbr, NULL, "Flag to accept or reject path_info on current request", "used_path_info"},
 
1287
    {"headers_in", (getter)getreq_recmbr, NULL, "Incoming headers", "headers_in"},
 
1288
    {"headers_out", (getter)getreq_recmbr, NULL, "Outgoing headers", "headers_out"},
 
1289
    {"err_headers_out", (getter)getreq_recmbr, NULL, "Outgoing headers for errors", "err_headers_out"},
 
1290
    {"subprocess_env", (getter)getreq_recmbr, NULL, "Subprocess environment", "subprocess_env"},
 
1291
    {"notes", (getter)getreq_recmbr, NULL, "Notes", "notes"},
 
1292
    /* XXX per_dir_config */
 
1293
    /* XXX request_config */
 
1294
    /* XXX htaccess */
 
1295
    /* XXX filters and eos */
 
1296
    {"eos_sent", (getter)getreq_recmbr, NULL, "EOS bucket sent", "eos_sent"},
 
1297
    {NULL}  /* Sentinel */
 
1298
};
 
1299
 
 
1300
#undef OFF
 
1301
#define OFF(x) offsetof(requestobject, x)
 
1302
 
 
1303
static struct PyMemberDef request_members[] = {
 
1304
    {"_content_type_set",  T_INT,       OFF(content_type_set),  RO},
 
1305
    {"phase",              T_OBJECT,    OFF(phase),             RO},
 
1306
    {"extension",          T_STRING,    OFF(extension),         RO},
 
1307
    {"interpreter",        T_STRING,    OFF(interpreter),       RO},
 
1308
    {"hlist",              T_OBJECT,    OFF(hlo),               RO},
 
1309
    {NULL}  /* Sentinel */
 
1310
};
 
1311
 
 
1312
/**
 
1313
 ** request_dealloc
 
1314
 **
 
1315
 *
 
1316
 */
 
1317
 
 
1318
static void request_dealloc(requestobject *self)
 
1319
{  
 
1320
    Py_XDECREF(self->dict);
 
1321
    Py_XDECREF(self->connection);
 
1322
    Py_XDECREF(self->server);
 
1323
    Py_XDECREF(self->next);
 
1324
    Py_XDECREF(self->prev);
 
1325
    Py_XDECREF(self->main);
 
1326
    Py_XDECREF(self->headers_in);
 
1327
    Py_XDECREF(self->headers_out);
 
1328
    Py_XDECREF(self->err_headers_out);
 
1329
    Py_XDECREF(self->subprocess_env);
 
1330
    Py_XDECREF(self->notes);
 
1331
    Py_XDECREF(self->phase);
 
1332
    Py_XDECREF(self->hlo);
 
1333
 
 
1334
    PyObject_Del(self);
 
1335
}
 
1336
 
 
1337
static char request_doc[] =
 
1338
"Apache request_rec structure\n";
 
1339
 
 
1340
PyTypeObject MpRequest_Type = {
 
1341
    PyObject_HEAD_INIT(NULL)
 
1342
    0,
 
1343
    "mp_request",
 
1344
    sizeof(requestobject),
 
1345
    0,
 
1346
    (destructor) request_dealloc,    /*tp_dealloc*/
 
1347
    0,                               /*tp_print*/
 
1348
    0,                               /*tp_getattr*/
 
1349
    0,                               /*tp_setattr*/
 
1350
    0,                               /*tp_compare*/
 
1351
    0,                               /*tp_repr*/
 
1352
    0,                               /*tp_as_number*/
 
1353
    0,                               /*tp_as_sequence*/
 
1354
    0,                               /*tp_as_mapping*/
 
1355
    0,                               /*tp_hash*/
 
1356
    0,                               /* tp_call */
 
1357
    0,                               /* tp_str */
 
1358
    PyObject_GenericGetAttr,         /* tp_getattro */
 
1359
    PyObject_GenericSetAttr,         /* tp_setattro */
 
1360
    0,                               /* tp_as_buffer */
 
1361
    Py_TPFLAGS_DEFAULT |
 
1362
    Py_TPFLAGS_BASETYPE,             /* tp_flags */
 
1363
    request_doc,                     /* tp_doc */
 
1364
    0,                               /* tp_traverse */
 
1365
    0,                               /* tp_clear */
 
1366
    0,                               /* tp_richcompare */
 
1367
    0,                               /* tp_weaklistoffset */
 
1368
    0,                               /* tp_iter */
 
1369
    0,                               /* tp_iternext */
 
1370
    request_methods,                 /* tp_methods */
 
1371
    request_members,                 /* tp_members */
 
1372
    request_getsets,                 /* tp_getset */
 
1373
    0,                               /* tp_base */
 
1374
    0,                               /* tp_dict */
 
1375
    0,                               /* tp_descr_get */
 
1376
    0,                               /* tp_descr_set */
 
1377
    offsetof(requestobject, dict),   /* tp_dictoffset */
 
1378
    0,                               /* tp_init */
 
1379
    0,                               /* tp_alloc */
 
1380
    0,                               /* tp_new */
 
1381
    (destructor)request_dealloc,     /* tp_free */
 
1382
};
 
1383
 
 
1384
 
 
1385
 
 
1386
 
 
1387
 
 
1388