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: filterobject.c,v 1.27 2004/02/16 19:47:27 grisha Exp $
23
* See accompanying documentation and source code comments
28
#include "mod_python.h"
30
/*** Some explanation of what is going on here:
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").
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).
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()).
46
* In mod_python Output filters:
48
* filter.read() - copies data from *given* bucket brigade (saved in
49
* self->bb_in) into a Python string.
51
* filter.write() - copies data from a Python string into a *new*
52
* bucket brigade (saved in self->bb_out).
54
* filter.close() - appends an EOS and passes the self->bb_out brigade
55
* to the next filter via ap_pass_brigade()
57
* In mod_python Input filters:
59
* filter.read() - copies data from a *new* and *populated via
60
* ap_get_brigade* (saved as self->bb_in) into a Python string.
62
* filter.write() - copies data from a Python string into a *given*
63
* brigade (saved as self->bb_out).
65
* filter.close() - appends an EOS to *given* brigade.
70
** MpFilter_FromFilter
72
* This routine creates a Python filerobject.
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)
82
result = PyObject_New(filterobject, &MpFilter_Type);
84
return PyErr_NoMemory();
87
result->is_input = is_input;
89
result->rc = APR_SUCCESS;
95
result->readbytes = readbytes;
99
result->bb_out = NULL;
101
result->readbytes = 0;
105
result->softspace = 0;
107
result->handler = handler;
110
result->request_obj = NULL;
112
apr_pool_cleanup_register(f->r->pool, (PyObject *)result, python_decref,
113
apr_pool_cleanup_null);
115
return (PyObject *)result;
121
* just passes everything on
124
static PyObject *filter_pass_on(filterobject *self)
127
Py_BEGIN_ALLOW_THREADS;
130
self->rc = ap_get_brigade(self->f->next, self->bb_out,
131
self->mode, APR_BLOCK_READ,
134
self->rc = ap_pass_brigade(self->f->next, self->bb_in);
136
Py_END_ALLOW_THREADS;
145
* read from filter - works for both read() and readline()
148
static PyObject *_filter_read(filterobject *self, PyObject *args, int readline)
158
conn_rec *c = self->request_obj->request_rec->connection;
160
if (! PyArg_ParseTuple(args, "|l", &len))
164
PyErr_SetString(PyExc_ValueError, "I/O operation on closed filter");
168
if (self->is_input) {
170
/* does the output brigade exist? */
172
self->bb_in = apr_brigade_create(self->f->r->pool,
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;
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"));
189
* loop through the brigade reading buckets into the string
192
b = APR_BRIGADE_FIRST(self->bb_in);
194
if (b == APR_BRIGADE_SENTINEL(self->bb_in))
195
return PyString_FromString("");
198
if (APR_BUCKET_IS_EOS(b)) {
199
apr_bucket_delete(b);
204
bufsize = len < 0 ? HUGE_STRING_LEN : len;
205
result = PyString_FromStringAndSize(NULL, bufsize);
207
/* possibly no more memory */
209
return PyErr_NoMemory();
211
buffer = PyString_AS_STRING((PyStringObject *) result);
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))) {
224
if (apr_bucket_read(b, &data, &size, APR_BLOCK_READ) != APR_SUCCESS) {
225
PyErr_SetObject(PyExc_IOError,
226
PyString_FromString("Filter read error"));
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 */
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) */
243
/* split after newline */
244
apr_bucket_split(b, i+1);
253
memcpy(buffer, data, size);
257
/* time to grow destination string? */
258
if (newline == 0 && len < 0 && bytes_read == bufsize) {
260
_PyString_Resize(&result, bufsize + HUGE_STRING_LEN);
261
buffer = PyString_AS_STRING((PyStringObject *) result);
262
buffer += HUGE_STRING_LEN;
264
bufsize += HUGE_STRING_LEN;
267
if (readline && newline) {
268
apr_bucket_delete(b);
273
b = APR_BUCKET_NEXT(b);
274
apr_bucket_delete(old);
276
/* if (self->is_input) { */
278
/* if (b == APR_BRIGADE_SENTINEL(self->bb_in)) { */
279
/* /\* brigade ended, but no EOS - get another */
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; */
287
/* if (! APR_STATUS_IS_SUCCESS(self->rc)) { */
288
/* PyErr_SetObject(PyExc_IOError, */
289
/* PyString_FromString("Input filter read error")); */
292
/* b = APR_BRIGADE_FIRST(self->bb_in); */
297
/* resize if necessary */
298
if (bytes_read < len || len < 0)
299
if(_PyString_Resize(&result, bytes_read))
306
** filter.read(filter self, int bytes)
308
* Reads from previous filter
311
static PyObject *filter_read(filterobject *self, PyObject *args)
313
return _filter_read(self, args, 0);
317
** filter.readline(filter self, int bytes)
319
* Reads a line from previous filter
322
static PyObject *filter_readline(filterobject *self, PyObject *args)
324
return _filter_read(self, args, 1);
329
** filter.write(filter self)
331
* Write to next filter
334
static PyObject *filter_write(filterobject *self, PyObject *args)
341
conn_rec *c = self->request_obj->request_rec->connection;
343
if (! PyArg_ParseTuple(args, "O", &s))
346
if (! PyString_Check(s)) {
347
PyErr_SetString(PyExc_TypeError, "Argument to write() must be a string");
352
PyErr_SetString(PyExc_ValueError, "I/O operation on closed filter");
356
len = PyString_Size(s);
360
/* does the output brigade exist? */
362
self->bb_out = apr_brigade_create(self->f->r->pool,
366
buff = apr_bucket_alloc(len, c->bucket_alloc);
367
memcpy(buff, PyString_AS_STRING(s), len);
369
b = apr_bucket_heap_create(buff, len, apr_bucket_free,
372
APR_BRIGADE_INSERT_TAIL(self->bb_out, b);
380
** filter.flush(filter self)
382
* Flush output (i.e. pass brigade)
385
static PyObject *filter_flush(filterobject *self, PyObject *args)
388
conn_rec *c = self->request_obj->request_rec->connection;
390
/* does the output brigade exist? */
392
self->bb_out = apr_brigade_create(self->f->r->pool,
396
APR_BRIGADE_INSERT_TAIL(self->bb_out,
397
apr_bucket_flush_create(c->bucket_alloc));
399
if (!self->is_input) {
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;
406
if(self->rc != APR_SUCCESS) {
407
PyErr_SetString(PyExc_IOError, "Flush failed.");
418
** filter.close(filter self)
423
static PyObject *filter_close(filterobject *self, PyObject *args)
426
conn_rec *c = self->request_obj->request_rec->connection;
428
if (! self->closed) {
430
/* does the output brigade exist? */
432
self->bb_out = apr_brigade_create(self->f->r->pool,
436
APR_BRIGADE_INSERT_TAIL(self->bb_out,
437
apr_bucket_eos_create(c->bucket_alloc));
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;
456
** filter.disable(filter self)
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.
463
static PyObject *filter_disable(filterobject *self, PyObject *args)
466
python_filter_ctx *ctx;
468
ctx = (python_filter_ctx *) self->f->ctx;
469
ctx->transparent = 1;
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},
487
#define OFF(x) offsetof(filterobject, x)
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 */
506
static void filter_dealloc(filterobject *self)
508
Py_XDECREF(self->request_obj);
516
* Get filter object attributes
521
static PyObject * filter_getattr(filterobject *self, char *name)
526
res = Py_FindMethod(filterobjectmethods, (PyObject *)self, name);
532
if (strcmp(name, "name") == 0) {
533
if (! self->f->frec->name) {
538
return PyString_FromString(self->f->frec->name);
541
else if (strcmp(name, "req") == 0) {
542
if (! self->request_obj) {
547
Py_INCREF(self->request_obj);
548
return (PyObject *)self->request_obj;
552
return PyMember_Get((char *)self, filter_memberlist, name);
558
* Set filter object attributes
562
static int filter_setattr(filterobject *self, char *name, PyObject *v)
565
PyErr_SetString(PyExc_AttributeError,
566
"can't delete filter attributes");
569
return PyMember_Set((char *)self, filter_memberlist, name, v);
572
PyTypeObject MpFilter_Type = {
573
PyObject_HEAD_INIT(NULL)
576
sizeof(filterobject),
578
(destructor) filter_dealloc, /*tp_dealloc*/
580
(getattrfunc) filter_getattr, /*tp_getattr*/
581
(setattrfunc) filter_setattr, /*tp_setattr*/
585
0, /*tp_as_sequence*/