157
163
hle = apr_hash_get(req_config->dynhls, phase, APR_HASH_KEY_STRING);
160
hle = hlist_new(self->request_rec->pool, handler, dir, 0);
166
hle = hlist_new(self->request_rec->pool, handler, dir, NOTSILENT);
161
167
apr_hash_set(req_config->dynhls, phase, APR_HASH_KEY_STRING, hle);
164
hlist_append(self->request_rec->pool, hle, handler, dir, 0);
170
hlist_append(self->request_rec->pool, hle, handler, dir, NOTSILENT);
346
352
py_config *conf =
347
353
(py_config *) ap_get_module_config(self->request_rec->per_dir_config,
349
return MpTable_FromTable(conf->options);
355
apr_table_t* table = conf->options;
358
apr_array_header_t* ah = apr_table_elts(table);
359
apr_table_entry_t* elts = ah->elts;
362
* We remove the empty values, since they cannot have been defined
365
for(i=0;i<ah->nelts;i++,elts++) {
366
if(strlen(elts->val)==0) {
367
apr_table_unset(table,elts->key);
371
/* XXX shouldn't we free the apr_array_header_t* ah ? */
373
return MpTable_FromTable(table);
377
** request.get_session()
379
* Get the session instance, or create a new one.
380
* This method just calls the python function
381
* create_session() in mod_python/Session.py to actually create
382
* the session instance.
385
static PyObject *req_get_session(requestobject *self, PyObject *args)
387
#ifdef ENABLE_GET_SESSION
388
/* get_session is not ready for mod_python 3.2 release
389
* We'll leave the code intact but raise an error
396
if (!self->session) {
397
/* Get the session id from the subprocess_env table if possible.
398
* If a session instance exists at the time of a req_internal_redirect()
399
* call, the session id will be added to the subprocess_env table with
400
* the key PYSID. req_internal_redirect() calls ap_internal_redirect(),
401
* which prepends all keys in subprocess_env with "REDIRECT_", so the key
402
* we want is REDIRECT_PYSID.
403
* req_internal_redirect() should have unlocked the session, so we do not
404
* need to worry about session deadlocking as a result of the redirect.
406
req = (PyObject *)self;
407
m = PyImport_ImportModule("mod_python.Session");
408
sid = PyObject_CallMethod(self->subprocess_env, "get", "(ss)","REDIRECT_PYSID", "");
409
self->session = PyObject_CallMethod(m, "create_session", "(OO)", req, sid);
414
* Failure to DECREF req results in a serious memory leak.
415
* On the other hand, if the session created does not save
416
* a reference to the request, we'll get a segfault.
417
* This should be documented for developers subclassing BaseSession.
418
* Maybe we should check self->session for the _req attribute
419
* and only do the decref if it exists? Or is there a better
420
* way to handle this? - Jim
423
if (self->session == NULL)
426
result = self->session;
430
PyErr_SetString(PyExc_NotImplementedError,
431
"get_session is not implemented");
357
441
static PyObject * req_internal_redirect(requestobject *self, PyObject *args)
444
#ifdef ENABLE_GET_SESSION
361
449
if (! PyArg_ParseTuple(args, "z", &new_uri))
362
450
return NULL; /* error */
452
#ifdef ENABLE_GET_SESSION
454
/* A session exists, so save and unlock it before the redirect.
455
* The session instance is not preserved across the ap_internal_direct()
456
* call, so all we can do is save a reference to session id as a string
457
* and recreate the session instance when the redirected request
458
* is processed. This is handled by req_get_session().
459
* Note that ap_internal_redirect() makes a copy of the subprocess_env table,
460
* pre-pending all the keys in the table with "REDIRECT_".
461
* Each internal_redirect results in a save and a read, which may impact
462
* performance, depending on the type of persistent store used by the
466
if (!(sid = PyObject_CallMethod(self->session, "id", NULL))) {
467
sid = PyString_FromString("");
470
/* Save the session id in the subprocess_env table. This id will be used
471
* to recreate the session instance when the redirected request is
474
if ((rc = PyObject_CallMethod(self->subprocess_env, "setdefault", "(sS)","PYSID", sid))) {
480
/* Save the session instance so any session data can be restored when
481
* the redirected request is processed.
483
if (!(rc = PyObject_CallMethod(self->session, "save", NULL))) {
487
/* Unlock the session. The session instance will be recreated when
488
* the redirected request is processed. Failure to unlock the session
489
* here will result in a deadlock.
491
if (!(rc = PyObject_CallMethod(self->session, "unlock", NULL))) {
364
497
Py_BEGIN_ALLOW_THREADS
365
498
ap_internal_redirect(new_uri, self->request_rec);
366
499
Py_END_ALLOW_THREADS
925
1070
{"get_config", (PyCFunction) req_get_config, METH_NOARGS},
926
1071
{"get_remote_host", (PyCFunction) req_get_remote_host, METH_VARARGS},
927
1072
{"get_options", (PyCFunction) req_get_options, METH_NOARGS},
1073
{"get_session", (PyCFunction) req_get_session, METH_VARARGS},
1074
{"write", (PyCFunction) req_write, METH_VARARGS},
928
1075
{"internal_redirect", (PyCFunction) req_internal_redirect, METH_VARARGS},
929
1076
{"log_error", (PyCFunction) req_log_error, METH_VARARGS},
1077
{"meets_conditions", (PyCFunction) req_meets_conditions, METH_NOARGS},
930
1078
{"read", (PyCFunction) req_read, METH_VARARGS},
931
1079
{"readline", (PyCFunction) req_readline, METH_VARARGS},
932
1080
{"readlines", (PyCFunction) req_readlines, METH_VARARGS},
1088
1236
apr_pstrdup(self->request_rec->pool, PyString_AsString(val));
1239
else if (strcmp(name, "path_info") == 0) {
1240
if (! PyString_Check(val)) {
1241
PyErr_SetString(PyExc_TypeError, "path_info must be a string");
1244
self->request_rec->path_info =
1245
apr_pstrdup(self->request_rec->pool, PyString_AsString(val));
1092
1249
return PyMember_SetOne((char*)self->request_rec,
1093
1250
find_memberdef(request_rec_mbrs, (char*)name),
1200
1357
PyObject *result = NULL;
1202
1359
if (strcmp(name, "connection") == 0) {
1203
if (!self->connection && self->request_rec->connection)
1360
if (!self->connection && self->request_rec->connection) {
1204
1361
self->connection = MpConn_FromConn(self->request_rec->connection);
1205
1363
result = self->connection;
1207
1365
else if (strcmp(name, "server") == 0) {
1208
if (!self->server && self->request_rec->server)
1366
if (!self->server && self->request_rec->server) {
1209
1367
self->server = MpServer_FromServer(self->request_rec->server);
1210
1369
result = self->server;
1212
1371
else if (strcmp(name, "next") == 0) {
1213
if (!self->next && self->request_rec->next)
1372
if (!self->next && self->request_rec->next) {
1214
1373
self->next = MpRequest_FromRequest(self->request_rec->next);
1374
((requestobject*)self->next)->prev = self;
1215
1376
result = self->next;
1217
1378
else if (strcmp(name, "prev") == 0) {
1218
if (!self->prev && self->request_rec->prev)
1379
if (!self->prev && self->request_rec->prev) {
1219
1380
self->prev = MpRequest_FromRequest(self->request_rec->prev);
1381
((requestobject*)self->prev)->next = self;
1220
1383
result = self->prev;
1222
1385
else if (strcmp(name, "main") == 0) {
1223
if (!self->main && self->request_rec->main)
1386
if (!self->main && self->request_rec->main) {
1224
1387
self->main = MpRequest_FromRequest(self->request_rec->main);
1225
1389
result = self->main;
1258
1422
{"bytes_sent", (getter)getreq_recmbr_off, NULL, "Bytes sent", "bytes_sent"},
1259
1423
{"mtime", (getter)getreq_recmbr_time, NULL, "Time resource was last modified", "mtime"},
1260
1424
{"chunked", (getter)getreq_recmbr, NULL, "Sending chunked transfer-coding", "chunked"},
1261
{"boundary", (getter)getreq_recmbr, NULL, "Multipart/byteranges boundary", "boundary"},
1262
1425
{"range", (getter)getreq_recmbr, NULL, "The Range: header", "range"},
1263
1426
{"clength", (getter)getreq_recmbr_off, NULL, "The \"real\" contenct length", "clength"},
1264
1427
{"remaining", (getter)getreq_recmbr_off, NULL, "Bytes left to read", "remaining"},
1279
1442
{"uri", (getter)getreq_recmbr, NULL, "The path portion of URI", "uri"},
1280
1443
{"filename", (getter)getreq_recmbr, (setter)setreq_recmbr, "The file name on disk that this request corresponds to", "filename"},
1281
1444
{"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"},
1445
{"path_info", (getter)getreq_recmbr, (setter)setreq_recmbr, "Path_info, if any", "path_info"},
1283
1446
{"args", (getter)getreq_recmbr, NULL, "QUERY_ARGS, if any", "args"},
1284
1447
{"finfo", (getter)getreq_rec_fi, NULL, "File information", "finfo"},
1285
1448
{"parsed_uri", (getter)getreq_rec_uri, NULL, "Components of URI", "parsed_uri"},
1480
static int request_tp_clear(requestobject *self)
1483
/* TODO: create a macro for the following repetitive code */
1484
tmp=self->dict; self->dict=NULL; Py_XDECREF(tmp);
1485
tmp=self->connection; self->connection=NULL; Py_XDECREF(tmp);
1486
tmp=self->server; self->server=NULL; Py_XDECREF(tmp);
1487
tmp=self->next; self->next=NULL; Py_XDECREF(tmp);
1488
tmp=self->prev; self->prev=NULL; Py_XDECREF(tmp);
1489
tmp=self->main; self->main=NULL; Py_XDECREF(tmp);
1490
tmp=self->headers_in; self->headers_in=NULL; Py_XDECREF(tmp);
1491
tmp=self->headers_out; self->headers_out=NULL; Py_XDECREF(tmp);
1492
tmp=self->err_headers_out; self->err_headers_out=NULL; Py_XDECREF(tmp);
1493
tmp=self->subprocess_env; self->subprocess_env=NULL; Py_XDECREF(tmp);
1494
tmp=self->notes; self->notes=NULL; Py_XDECREF(tmp);
1495
tmp=self->phase; self->phase=NULL; Py_XDECREF(tmp);
1496
tmp=self->hlo; self->hlo=NULL; Py_XDECREF(tmp);
1497
tmp=self->session; self->session=NULL; Py_XDECREF(tmp);
1313
1504
** request_dealloc
1318
static void request_dealloc(requestobject *self)
1509
static void request_tp_dealloc(requestobject *self)
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);
1511
// de-register the object from the GC
1512
// before its deallocation, to prevent the
1513
// GC to run on a partially de-allocated object
1514
PyObject_GC_UnTrack(self);
1516
request_tp_clear(self);
1518
PyObject_GC_Del(self);
1522
** request_tp_traverse
1524
* Traversal of the request object
1526
static int request_tp_traverse(requestobject* self, visitproc visit, void *arg) {
1529
if(self->dict) {result = visit(self->dict,arg); if(result) return result;}
1530
if(self->connection) {result = visit(self->connection,arg); if(result) return result;}
1531
if(self->server) {result = visit(self->server,arg); if(result) return result;}
1532
if(self->next) {result = visit(self->next,arg); if(result) return result;}
1533
if(self->prev) {result = visit(self->prev,arg); if(result) return result;}
1534
if(self->main) {result = visit(self->main,arg); if(result) return result;}
1535
if(self->headers_in) {result = visit(self->headers_in,arg); if(result) return result;}
1536
if(self->headers_out) {result = visit(self->headers_out,arg); if(result) return result;}
1537
if(self->err_headers_out) {result = visit(self->err_headers_out,arg); if(result) return result;}
1538
if(self->subprocess_env) {result = visit(self->subprocess_env,arg); if(result) return result;}
1539
if(self->notes) {result = visit(self->notes,arg); if(result) return result;}
1540
if(self->phase) {result = visit(self->phase,arg); if(result) return result;}
1541
if(self->session) {result = visit(self->session,arg); if(result) return result;}
1543
// no need to Py_DECREF(dict) since the reference is borrowed
1337
1546
static char request_doc[] =
1338
1547
"Apache request_rec structure\n";
1344
1553
sizeof(requestobject),
1346
(destructor) request_dealloc, /*tp_dealloc*/
1353
0, /*tp_as_sequence*/
1354
0, /*tp_as_mapping*/
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 */
1366
0, /* tp_richcompare */
1367
0, /* tp_weaklistoffset */
1369
0, /* tp_iternext */
1370
request_methods, /* tp_methods */
1371
request_members, /* tp_members */
1372
request_getsets, /* tp_getset */
1375
0, /* tp_descr_get */
1376
0, /* tp_descr_set */
1377
offsetof(requestobject, dict), /* tp_dictoffset */
1381
(destructor)request_dealloc, /* tp_free */
1555
(destructor)request_tp_dealloc, /*tp_dealloc*/
1562
0, /*tp_as_sequence*/
1563
0, /*tp_as_mapping*/
1567
PyObject_GenericGetAttr, /* tp_getattro */
1568
PyObject_GenericSetAttr, /* tp_setattro */
1569
0, /* tp_as_buffer */
1570
Py_TPFLAGS_DEFAULT |
1571
Py_TPFLAGS_BASETYPE|
1572
Py_TPFLAGS_HAVE_GC , /* tp_flags */
1573
request_doc, /* tp_doc */
1574
(traverseproc)request_tp_traverse, /* tp_traverse */
1575
(inquiry)request_tp_clear, /* tp_clear */
1576
0, /* tp_richcompare */
1577
0, /* tp_weaklistoffset */
1579
0, /* tp_iternext */
1580
request_methods, /* tp_methods */
1581
request_members, /* tp_members */
1582
request_getsets, /* tp_getset */
1585
0, /* tp_descr_get */
1586
0, /* tp_descr_set */
1587
offsetof(requestobject, dict), /* tp_dictoffset */