~ubuntu-branches/ubuntu/jaunty/libapache2-mod-python/jaunty

« back to all changes in this revision

Viewing changes to src/filterobject.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
 * filterobject.c 
 
20
 *
 
21
 * $Id: filterobject.c,v 1.27 2004/02/16 19:47:27 grisha Exp $
 
22
 *
 
23
 * See accompanying documentation and source code comments 
 
24
 * for details.
 
25
 *
 
26
 */
 
27
 
 
28
#include "mod_python.h"
 
29
 
 
30
/*** Some explanation of what is going on here:
 
31
 *
 
32
 * In Apache terminology, an "input" filter filters data flowing from
 
33
 * network to application (aka "up"), an "output" filter filters data
 
34
 * flowing from application to network (aka "down").
 
35
 *
 
36
 * An output filter is invoked as a result of ap_pass_brigade()
 
37
 * call. It is given a populated brigade, which it then gives in the
 
38
 * same fashion to the next filter via ap_pass_brigade(). (The filter
 
39
 * may chose to create a new brigade and pass it instead).
 
40
 *
 
41
 * An input filter is invoked as a result of ap_get_brigade() call. It
 
42
 * is given an empty brigade, which it is expected to populate, which
 
43
 * may in turn require the filter to invoke the next filter in the
 
44
 * same fashion (via ap_get_brigade()).
 
45
 *
 
46
 * In mod_python Output filters: 
 
47
 *
 
48
 * filter.read() - copies data from *given* bucket brigade (saved in
 
49
 * self->bb_in) into a Python string.
 
50
 *
 
51
 * filter.write() - copies data from a Python string into a *new*
 
52
 * bucket brigade (saved in self->bb_out).
 
53
 *
 
54
 * filter.close() - appends an EOS and passes the self->bb_out brigade
 
55
 * to the next filter via ap_pass_brigade()
 
56
 *
 
57
 * In mod_python Input filters:
 
58
 *
 
59
 * filter.read() - copies data from a *new* and *populated via
 
60
 * ap_get_brigade* (saved as self->bb_in) into a Python string.
 
61
 *
 
62
 * filter.write() - copies data from a Python string into a *given*
 
63
 * brigade (saved as self->bb_out).
 
64
 *
 
65
 * filter.close() - appends an EOS to *given* brigade.
 
66
 *
 
67
 */
 
68
 
 
69
/**
 
70
 **     MpFilter_FromFilter
 
71
 **
 
72
 *      This routine creates a Python filerobject.
 
73
 *
 
74
 */
 
75
 
 
76
PyObject *MpFilter_FromFilter(ap_filter_t *f, apr_bucket_brigade *bb, int is_input,
 
77
                              ap_input_mode_t mode, apr_size_t readbytes,
 
78
                              char * handler, char *dir)
 
79
{
 
80
    filterobject *result;
 
81
 
 
82
    result = PyObject_New(filterobject, &MpFilter_Type);
 
83
    if (! result)
 
84
        return PyErr_NoMemory();
 
85
 
 
86
    result->f = f;
 
87
    result->is_input = is_input;
 
88
 
 
89
    result->rc = APR_SUCCESS;
 
90
 
 
91
    if (is_input) {
 
92
        result->bb_in = NULL;
 
93
        result->bb_out = bb;
 
94
        result->mode = mode;
 
95
        result->readbytes = readbytes;
 
96
    }
 
97
    else {
 
98
        result->bb_in = bb;
 
99
        result->bb_out = NULL;
 
100
        result->mode = 0;
 
101
        result->readbytes = 0;
 
102
    }
 
103
 
 
104
    result->closed = 0;
 
105
    result->softspace = 0;
 
106
 
 
107
    result->handler = handler;
 
108
    result->dir = dir;
 
109
 
 
110
    result->request_obj = NULL; 
 
111
 
 
112
    apr_pool_cleanup_register(f->r->pool, (PyObject *)result, python_decref, 
 
113
                              apr_pool_cleanup_null);
 
114
 
 
115
    return (PyObject *)result;
 
116
}
 
117
 
 
118
/**
 
119
 ** filter_pass_on
 
120
 **
 
121
 *     just passes everything on
 
122
 */
 
123
 
 
124
static PyObject *filter_pass_on(filterobject *self)
 
125
{
 
126
 
 
127
    Py_BEGIN_ALLOW_THREADS;
 
128
 
 
129
    if (self->is_input) 
 
130
        self->rc = ap_get_brigade(self->f->next, self->bb_out, 
 
131
                                  self->mode, APR_BLOCK_READ, 
 
132
                                  self->readbytes);
 
133
    else
 
134
        self->rc = ap_pass_brigade(self->f->next, self->bb_in);
 
135
 
 
136
    Py_END_ALLOW_THREADS;
 
137
 
 
138
    Py_INCREF(Py_None);
 
139
    return Py_None;
 
140
}
 
141
 
 
142
/**
 
143
 ** _filter_read
 
144
 **
 
145
 *     read from filter - works for both read() and readline()
 
146
 */
 
147
 
 
148
static PyObject *_filter_read(filterobject *self, PyObject *args, int readline)
 
149
{
 
150
 
 
151
    apr_bucket *b;
 
152
    long bytes_read;
 
153
    PyObject *result;
 
154
    char *buffer;
 
155
    long bufsize;
 
156
    int newline = 0;
 
157
    long len = -1;
 
158
    conn_rec *c = self->request_obj->request_rec->connection;
 
159
 
 
160
    if (! PyArg_ParseTuple(args, "|l", &len)) 
 
161
        return NULL;
 
162
 
 
163
    if (self->closed) {
 
164
        PyErr_SetString(PyExc_ValueError, "I/O operation on closed filter");
 
165
        return NULL;
 
166
    }
 
167
 
 
168
    if (self->is_input) {
 
169
 
 
170
        /* does the output brigade exist? */
 
171
        if (!self->bb_in) {
 
172
            self->bb_in = apr_brigade_create(self->f->r->pool, 
 
173
                                             c->bucket_alloc);
 
174
        }
 
175
 
 
176
        Py_BEGIN_ALLOW_THREADS;
 
177
        self->rc = ap_get_brigade(self->f->next, self->bb_in, self->mode, 
 
178
                                  APR_BLOCK_READ, self->readbytes);
 
179
        Py_END_ALLOW_THREADS;
 
180
 
 
181
        if (!APR_STATUS_IS_EAGAIN(self->rc) && !APR_STATUS_IS_SUCCESS(self->rc)) {
 
182
            PyErr_SetObject(PyExc_IOError, 
 
183
                            PyString_FromString("Input filter read error"));
 
184
            return NULL;
 
185
        }
 
186
    }
 
187
 
 
188
    /* 
 
189
     * loop through the brigade reading buckets into the string 
 
190
     */
 
191
 
 
192
    b = APR_BRIGADE_FIRST(self->bb_in);
 
193
 
 
194
    if (b == APR_BRIGADE_SENTINEL(self->bb_in))
 
195
        return PyString_FromString("");
 
196
 
 
197
    /* reached eos ? */
 
198
    if (APR_BUCKET_IS_EOS(b)) {
 
199
        apr_bucket_delete(b);
 
200
        Py_INCREF(Py_None);
 
201
        return Py_None;
 
202
    }
 
203
 
 
204
    bufsize = len < 0 ? HUGE_STRING_LEN : len;
 
205
    result = PyString_FromStringAndSize(NULL, bufsize);
 
206
 
 
207
    /* possibly no more memory */
 
208
    if (result == NULL) 
 
209
        return PyErr_NoMemory();
 
210
    
 
211
    buffer = PyString_AS_STRING((PyStringObject *) result);
 
212
 
 
213
    bytes_read = 0;
 
214
 
 
215
    while ((bytes_read < len || len == -1) && 
 
216
           !(APR_BUCKET_IS_EOS(b) || APR_BUCKET_IS_FLUSH(b) ||
 
217
             b == APR_BRIGADE_SENTINEL(self->bb_in))) {
 
218
 
 
219
        const char *data;
 
220
        apr_size_t size;
 
221
        apr_bucket *old;
 
222
        int i;
 
223
 
 
224
        if (apr_bucket_read(b, &data, &size, APR_BLOCK_READ) != APR_SUCCESS) {
 
225
            PyErr_SetObject(PyExc_IOError, 
 
226
                            PyString_FromString("Filter read error"));
 
227
            return NULL;
 
228
        }
 
229
 
 
230
        if (bytes_read + size > bufsize) {
 
231
            apr_bucket_split(b, bufsize - bytes_read);
 
232
            size = bufsize - bytes_read;
 
233
            /* now the bucket is the exact size we need */
 
234
        }
 
235
 
 
236
        if (readline) {
 
237
 
 
238
            /* scan for newline */
 
239
            for (i=0; i<size; i++) {
 
240
                if (data[i] == '\n') {
 
241
                    if (i+1 != size) {   /* (no need to split if we're at end of bucket) */
 
242
                        
 
243
                        /* split after newline */
 
244
                        apr_bucket_split(b, i+1);   
 
245
                        size = i + 1;
 
246
                    }
 
247
                    newline = 1;
 
248
                    break;
 
249
                }
 
250
            }
 
251
        }
 
252
 
 
253
        memcpy(buffer, data, size);
 
254
        buffer += size;
 
255
        bytes_read += size;
 
256
 
 
257
        /* time to grow destination string? */
 
258
        if (newline == 0 && len < 0 && bytes_read == bufsize) {
 
259
 
 
260
            _PyString_Resize(&result, bufsize + HUGE_STRING_LEN);
 
261
            buffer = PyString_AS_STRING((PyStringObject *) result);
 
262
            buffer += HUGE_STRING_LEN;
 
263
 
 
264
            bufsize += HUGE_STRING_LEN;
 
265
        }
 
266
 
 
267
        if (readline && newline) {
 
268
            apr_bucket_delete(b);
 
269
            break;
 
270
        }
 
271
 
 
272
        old = b;
 
273
        b = APR_BUCKET_NEXT(b);
 
274
        apr_bucket_delete(old);
 
275
        
 
276
/*         if (self->is_input) { */
 
277
 
 
278
/*             if (b == APR_BRIGADE_SENTINEL(self->bb_in)) { */
 
279
/*                 /\* brigade ended, but no EOS - get another */
 
280
/*                    brigade *\/ */
 
281
 
 
282
/*                 Py_BEGIN_ALLOW_THREADS; */
 
283
/*                 self->rc = ap_get_brigade(self->f->next, self->bb_in, self->mode,  */
 
284
/*                                           APR_BLOCK_READ, self->readbytes); */
 
285
/*                 Py_END_ALLOW_THREADS; */
 
286
 
 
287
/*                 if (! APR_STATUS_IS_SUCCESS(self->rc)) { */
 
288
/*                     PyErr_SetObject(PyExc_IOError,  */
 
289
/*                                     PyString_FromString("Input filter read error")); */
 
290
/*                     return NULL; */
 
291
/*                 } */
 
292
/*                 b = APR_BRIGADE_FIRST(self->bb_in); */
 
293
/*             } */
 
294
/*         }  */
 
295
    }
 
296
 
 
297
    /* resize if necessary */
 
298
    if (bytes_read < len || len < 0) 
 
299
        if(_PyString_Resize(&result, bytes_read))
 
300
            return NULL;
 
301
 
 
302
    return result;
 
303
}
 
304
 
 
305
/**
 
306
 ** filter.read(filter self, int bytes)
 
307
 **
 
308
 *     Reads from previous filter
 
309
 */
 
310
 
 
311
static PyObject *filter_read(filterobject *self, PyObject *args)
 
312
{
 
313
    return _filter_read(self, args, 0);
 
314
}
 
315
 
 
316
/**
 
317
 ** filter.readline(filter self, int bytes)
 
318
 **
 
319
 *     Reads a line from previous filter
 
320
 */
 
321
 
 
322
static PyObject *filter_readline(filterobject *self, PyObject *args)
 
323
{
 
324
    return _filter_read(self, args, 1);
 
325
}
 
326
 
 
327
 
 
328
/**
 
329
 ** filter.write(filter self)
 
330
 **
 
331
 *     Write to next filter
 
332
 */
 
333
 
 
334
static PyObject *filter_write(filterobject *self, PyObject *args)
 
335
{
 
336
 
 
337
    char *buff;
 
338
    int len;
 
339
    apr_bucket *b;
 
340
    PyObject *s;
 
341
    conn_rec *c = self->request_obj->request_rec->connection;
 
342
 
 
343
    if (! PyArg_ParseTuple(args, "O", &s)) 
 
344
        return NULL;
 
345
 
 
346
    if (! PyString_Check(s)) {
 
347
        PyErr_SetString(PyExc_TypeError, "Argument to write() must be a string");
 
348
        return NULL;
 
349
    }
 
350
 
 
351
    if (self->closed) {
 
352
        PyErr_SetString(PyExc_ValueError, "I/O operation on closed filter");
 
353
        return NULL;
 
354
    }
 
355
 
 
356
    len = PyString_Size(s);
 
357
 
 
358
    if (len) {
 
359
 
 
360
        /* does the output brigade exist? */
 
361
        if (!self->bb_out) {
 
362
            self->bb_out = apr_brigade_create(self->f->r->pool, 
 
363
                                              c->bucket_alloc);
 
364
        }
 
365
        
 
366
        buff = apr_bucket_alloc(len, c->bucket_alloc);
 
367
        memcpy(buff, PyString_AS_STRING(s), len);
 
368
 
 
369
        b = apr_bucket_heap_create(buff, len, apr_bucket_free,
 
370
                                   c->bucket_alloc);
 
371
 
 
372
        APR_BRIGADE_INSERT_TAIL(self->bb_out, b);
 
373
    }
 
374
 
 
375
    Py_INCREF(Py_None);
 
376
    return Py_None;
 
377
}
 
378
 
 
379
/**
 
380
 ** filter.flush(filter self)
 
381
 **
 
382
 *     Flush output (i.e. pass brigade)
 
383
 */
 
384
 
 
385
static PyObject *filter_flush(filterobject *self, PyObject *args)
 
386
{
 
387
 
 
388
    conn_rec *c = self->request_obj->request_rec->connection;
 
389
 
 
390
    /* does the output brigade exist? */
 
391
    if (!self->bb_out) {
 
392
        self->bb_out = apr_brigade_create(self->f->r->pool,
 
393
                                          c->bucket_alloc);
 
394
    }
 
395
 
 
396
    APR_BRIGADE_INSERT_TAIL(self->bb_out, 
 
397
                            apr_bucket_flush_create(c->bucket_alloc));
 
398
 
 
399
    if (!self->is_input) {
 
400
 
 
401
        Py_BEGIN_ALLOW_THREADS;
 
402
        self->rc = ap_pass_brigade(self->f->next, self->bb_out);
 
403
        apr_brigade_destroy(self->bb_out);
 
404
        Py_END_ALLOW_THREADS;
 
405
 
 
406
        if(self->rc != APR_SUCCESS) { 
 
407
            PyErr_SetString(PyExc_IOError, "Flush failed.");
 
408
            return NULL;
 
409
        }
 
410
    }
 
411
 
 
412
    Py_INCREF(Py_None);
 
413
    return Py_None;
 
414
 
 
415
}
 
416
 
 
417
/**
 
418
 ** filter.close(filter self)
 
419
 **
 
420
 *     passes EOS 
 
421
 */
 
422
 
 
423
static PyObject *filter_close(filterobject *self, PyObject *args)
 
424
{
 
425
 
 
426
    conn_rec *c = self->request_obj->request_rec->connection;
 
427
 
 
428
    if (! self->closed) {
 
429
 
 
430
        /* does the output brigade exist? */
 
431
        if (!self->bb_out) {
 
432
            self->bb_out = apr_brigade_create(self->f->r->pool,
 
433
                                              c->bucket_alloc);
 
434
        }
 
435
 
 
436
        APR_BRIGADE_INSERT_TAIL(self->bb_out, 
 
437
                                apr_bucket_eos_create(c->bucket_alloc));
 
438
 
 
439
        if (! self->is_input) {
 
440
            Py_BEGIN_ALLOW_THREADS;
 
441
            self->rc = ap_pass_brigade(self->f->next, self->bb_out);
 
442
            apr_brigade_destroy(self->bb_out);
 
443
            Py_END_ALLOW_THREADS;
 
444
            self->bb_out = NULL;
 
445
        }
 
446
 
 
447
        self->closed = 1;
 
448
    }
 
449
 
 
450
    Py_INCREF(Py_None);
 
451
    return Py_None;
 
452
    
 
453
}
 
454
 
 
455
/**
 
456
 ** filter.disable(filter self)
 
457
 **
 
458
 *     Sets the transparent flag on causeing the filter_handler to
 
459
 *     just pass the data through without envoking Python at all.
 
460
 *     This is used during filter error output. 
 
461
 */
 
462
 
 
463
static PyObject *filter_disable(filterobject *self, PyObject *args)
 
464
{
 
465
 
 
466
    python_filter_ctx *ctx;
 
467
 
 
468
    ctx = (python_filter_ctx *) self->f->ctx;
 
469
    ctx->transparent = 1;
 
470
 
 
471
    Py_INCREF(Py_None);
 
472
    return Py_None;
 
473
 
 
474
}
 
475
 
 
476
static PyMethodDef filterobjectmethods[] = {
 
477
    {"pass_on",   (PyCFunction) filter_pass_on,   METH_NOARGS},
 
478
    {"read",      (PyCFunction) filter_read,      METH_VARARGS},
 
479
    {"readline",  (PyCFunction) filter_readline,  METH_VARARGS},
 
480
    {"write",     (PyCFunction) filter_write,     METH_VARARGS},
 
481
    {"flush",     (PyCFunction) filter_flush,     METH_VARARGS},
 
482
    {"close",     (PyCFunction) filter_close,     METH_VARARGS},
 
483
    {"disable",   (PyCFunction) filter_disable,   METH_VARARGS},
 
484
    {NULL, NULL}
 
485
};
 
486
 
 
487
#define OFF(x) offsetof(filterobject, x)
 
488
 
 
489
static struct memberlist filter_memberlist[] = {
 
490
    {"softspace",          T_INT,       OFF(softspace),            },
 
491
    {"closed",             T_INT,       OFF(closed),             RO},
 
492
    {"name",               T_OBJECT,    0,                       RO},
 
493
    {"req",                T_OBJECT,    OFF(request_obj),          },
 
494
    {"is_input",           T_INT,       OFF(is_input),           RO},
 
495
    {"handler",            T_STRING,    OFF(handler),            RO},
 
496
    {"dir",                T_STRING,    OFF(dir),                RO},
 
497
    {NULL}  /* Sentinel */
 
498
};
 
499
 
 
500
/**
 
501
 ** filter_dealloc
 
502
 **
 
503
 *
 
504
 */
 
505
 
 
506
static void filter_dealloc(filterobject *self)
 
507
{  
 
508
    Py_XDECREF(self->request_obj);
 
509
    PyObject_Del(self);
 
510
}
 
511
 
 
512
 
 
513
/**
 
514
 ** filter_getattr
 
515
 **
 
516
 *  Get filter object attributes
 
517
 *
 
518
 *
 
519
 */
 
520
 
 
521
static PyObject * filter_getattr(filterobject *self, char *name)
 
522
{
 
523
 
 
524
    PyObject *res;
 
525
 
 
526
    res = Py_FindMethod(filterobjectmethods, (PyObject *)self, name);
 
527
    if (res != NULL)
 
528
        return res;
 
529
    
 
530
    PyErr_Clear();
 
531
 
 
532
    if (strcmp(name, "name") == 0) {
 
533
        if (! self->f->frec->name) {
 
534
            Py_INCREF(Py_None);
 
535
            return Py_None;
 
536
        }
 
537
        else {
 
538
            return PyString_FromString(self->f->frec->name);
 
539
        }
 
540
    } 
 
541
    else if (strcmp(name, "req") == 0) {
 
542
        if (! self->request_obj) {
 
543
            Py_INCREF(Py_None);
 
544
            return Py_None;
 
545
        }
 
546
        else {
 
547
            Py_INCREF(self->request_obj);
 
548
            return (PyObject *)self->request_obj;
 
549
        }
 
550
    }
 
551
    else
 
552
        return PyMember_Get((char *)self, filter_memberlist, name);
 
553
}
 
554
 
 
555
/**
 
556
 ** filter_setattr
 
557
 **
 
558
 *  Set filter object attributes
 
559
 *
 
560
 */
 
561
 
 
562
static int filter_setattr(filterobject *self, char *name, PyObject *v)
 
563
{
 
564
    if (v == NULL) {
 
565
        PyErr_SetString(PyExc_AttributeError,
 
566
                        "can't delete filter attributes");
 
567
        return -1;
 
568
    }
 
569
    return PyMember_Set((char *)self, filter_memberlist, name, v);
 
570
}
 
571
 
 
572
PyTypeObject MpFilter_Type = {
 
573
    PyObject_HEAD_INIT(NULL)
 
574
    0,
 
575
    "mp_filter",
 
576
    sizeof(filterobject),
 
577
    0,
 
578
    (destructor) filter_dealloc,    /*tp_dealloc*/
 
579
    0,                              /*tp_print*/
 
580
    (getattrfunc) filter_getattr,   /*tp_getattr*/
 
581
    (setattrfunc) filter_setattr,   /*tp_setattr*/
 
582
    0,                              /*tp_compare*/
 
583
    0,                              /*tp_repr*/
 
584
    0,                              /*tp_as_number*/
 
585
    0,                              /*tp_as_sequence*/
 
586
    0,                              /*tp_as_mapping*/
 
587
    0,                              /*tp_hash*/
 
588
};
 
589