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

« back to all changes in this revision

Viewing changes to src/requestobject.c

  • Committer: Bazaar Package Importer
  • Author(s): Martin Pitt
  • Date: 2006-07-07 13:18:35 UTC
  • mfrom: (1.2.2 upstream)
  • Revision ID: james.westby@ubuntu.com-20060707131835-zfp1vupanjj2e77y
Tags: 3.2.8-1ubuntu1
* Merge to Debian unstable.
* Remaining Ubuntu change: debian/{control,rules}: Drop python 2.3 package.

Show diffs side-by-side

added added

removed removed

Lines of Context:
18
18
 *
19
19
 * requestobject.c 
20
20
 *
21
 
 * $Id: requestobject.c 102649 2004-02-16 19:47:28Z grisha $
 
21
 * $Id: requestobject.c 367839 2006-01-11 00:03:06Z jgallacher $
22
22
 *
23
23
 */
24
24
 
36
36
{
37
37
    requestobject *result;
38
38
 
39
 
    result = PyObject_New(requestobject, &MpRequest_Type);
 
39
    result = PyObject_GC_New(requestobject, &MpRequest_Type);
40
40
    if (! result)
41
41
        return PyErr_NoMemory();
42
42
 
62
62
    result->rbuff = NULL;
63
63
    result->rbuff_pos = 0;
64
64
    result->rbuff_len = 0;
 
65
    result->session = NULL;
 
66
 
 
67
    // we make sure that the object dictionary is there
 
68
    // before registering the object with the GC
 
69
    PyObject_GC_Track(result);
65
70
 
66
71
    return (PyObject *) result;
67
72
}
68
73
 
 
74
 
69
75
/* Methods */
70
76
 
71
77
/**
141
147
 
142
148
        /* then just append to hlist */
143
149
        hlist_append(self->request_rec->pool, self->hlo->head,
144
 
                     handler, dir, 0);
 
150
                     handler, dir, NOTSILENT);
145
151
    }
146
152
    else {
147
153
        /* this is a phase that we're not in */
157
163
        hle = apr_hash_get(req_config->dynhls, phase, APR_HASH_KEY_STRING);
158
164
 
159
165
        if (! hle) {
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);
162
168
        }
163
169
        else {
164
 
            hlist_append(self->request_rec->pool, hle, handler, dir, 0);
 
170
            hlist_append(self->request_rec->pool, hle, handler, dir, NOTSILENT);
165
171
        }
166
172
    }
167
173
    
346
352
    py_config *conf =
347
353
        (py_config *) ap_get_module_config(self->request_rec->per_dir_config, 
348
354
                                           &python_module);
349
 
    return MpTable_FromTable(conf->options);
 
355
    apr_table_t* table = conf->options;
 
356
 
 
357
    int i;
 
358
    apr_array_header_t* ah = apr_table_elts(table);
 
359
    apr_table_entry_t* elts = ah->elts;
 
360
 
 
361
    /*
 
362
     * We remove the empty values, since they cannot have been defined
 
363
     * by the directive.
 
364
     */
 
365
    for(i=0;i<ah->nelts;i++,elts++) {
 
366
        if(strlen(elts->val)==0) {
 
367
            apr_table_unset(table,elts->key);
 
368
        }
 
369
    }
 
370
 
 
371
    /* XXX shouldn't we free the apr_array_header_t* ah ? */
 
372
 
 
373
    return MpTable_FromTable(table);
 
374
}
 
375
 
 
376
/**
 
377
 ** request.get_session() 
 
378
 **
 
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.
 
383
 */ 
 
384
 
 
385
static PyObject *req_get_session(requestobject *self, PyObject *args)
 
386
{
 
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
 
390
     */
 
391
    PyObject *m;
 
392
    PyObject *sid;
 
393
    PyObject *req;
 
394
    PyObject *result;
 
395
 
 
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.
 
405
         */ 
 
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);
 
410
        Py_DECREF(m);
 
411
        Py_DECREF(sid);
 
412
 
 
413
        /* TODO
 
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
 
421
         */ 
 
422
        Py_DECREF(req);
 
423
        if (self->session == NULL)
 
424
            return NULL;
 
425
    }
 
426
    result = self->session;
 
427
    Py_INCREF(result);
 
428
    return result;
 
429
#else
 
430
    PyErr_SetString(PyExc_NotImplementedError,
 
431
                    "get_session is not implemented");
 
432
    return NULL;
 
433
#endif
350
434
}
351
435
 
352
436
/**
357
441
static PyObject * req_internal_redirect(requestobject *self, PyObject *args)
358
442
{
359
443
    char *new_uri;
 
444
#ifdef ENABLE_GET_SESSION
 
445
    PyObject *sid;
 
446
    PyObject *rc;
 
447
#endif
360
448
 
361
449
    if (! PyArg_ParseTuple(args, "z", &new_uri))
362
450
        return NULL; /* error */
363
451
 
 
452
#ifdef ENABLE_GET_SESSION
 
453
    if (self->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
 
463
         * session class.
 
464
         */
 
465
 
 
466
        if (!(sid = PyObject_CallMethod(self->session, "id", NULL))) {
 
467
            sid = PyString_FromString("");
 
468
        }
 
469
 
 
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 
 
472
         * processed.
 
473
         */
 
474
        if ((rc = PyObject_CallMethod(self->subprocess_env, "setdefault", "(sS)","PYSID", sid))) {
 
475
            Py_DECREF(rc);
 
476
        }
 
477
        
 
478
        Py_DECREF(sid);
 
479
 
 
480
        /* Save the session instance so any session data can be restored when
 
481
         * the redirected request is processed.
 
482
         */
 
483
        if (!(rc = PyObject_CallMethod(self->session, "save", NULL))) {
 
484
            Py_DECREF(rc);
 
485
        }
 
486
 
 
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.
 
490
         */
 
491
        if (!(rc = PyObject_CallMethod(self->session, "unlock", NULL))) {
 
492
            Py_DECREF(rc);
 
493
        }
 
494
    }
 
495
#endif
 
496
    
364
497
    Py_BEGIN_ALLOW_THREADS
365
498
    ap_internal_redirect(new_uri, self->request_rec);
366
499
    Py_END_ALLOW_THREADS
395
528
    return Py_None;
396
529
}
397
530
 
 
531
 /**
 
532
 ** request.meets_conditions(req self)
 
533
 **
 
534
 *  ap_meets_conditions wrapper
 
535
 */
 
536
 
 
537
static PyObject * req_meets_conditions(requestobject *self) {
 
538
    return PyInt_FromLong(ap_meets_conditions(self->request_rec));
 
539
}
 
540
 
 
541
 
398
542
/**
399
543
 ** request.read(request self, int bytes)
400
544
 **
671
815
        return PyErr_NoMemory();
672
816
 
673
817
    line = req_readline(self, rlargs);
674
 
    while (line && !(strcmp(PyString_AsString(line), "") == 0)) {
 
818
    while (line && (PyString_Size(line)>0)) {
675
819
        PyList_Append(result, line);
676
820
        size += PyString_Size(line);
677
821
        if ((sizehint != -1) && (size >= size))
880
1024
 
881
1025
    Py_BEGIN_ALLOW_THREADS
882
1026
    status=apr_stat(&finfo, fname,
883
 
                    APR_READ, self->request_rec->pool);
 
1027
                    APR_FINFO_NORM, self->request_rec->pool);
884
1028
    Py_END_ALLOW_THREADS
885
1029
    if (status != APR_SUCCESS) {
886
1030
        PyErr_SetString(PyExc_IOError, "Could not stat file for reading");
903
1047
        status = ap_send_fd(fd, self->request_rec, offset, 
904
1048
                            len, &nbytes);
905
1049
    Py_END_ALLOW_THREADS
 
1050
    apr_file_close(fd);
906
1051
    
907
1052
    if (status != APR_SUCCESS) {
908
1053
        PyErr_SetString(PyExc_IOError, "Write failed, client closed connection.");
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));
1089
1237
        return 0;
1090
1238
    }
 
1239
    else if (strcmp(name, "path_info") == 0) {
 
1240
        if (! PyString_Check(val)) {
 
1241
            PyErr_SetString(PyExc_TypeError, "path_info must be a string");
 
1242
            return -1;
 
1243
        }
 
1244
        self->request_rec->path_info = 
 
1245
            apr_pstrdup(self->request_rec->pool, PyString_AsString(val));
 
1246
        return 0;
 
1247
    }
1091
1248
    
1092
1249
    return PyMember_SetOne((char*)self->request_rec, 
1093
1250
                           find_memberdef(request_rec_mbrs, (char*)name),
1139
1296
{
1140
1297
    const PyMemberDef *md = find_memberdef(request_rec_mbrs, name);
1141
1298
    apr_array_header_t *ah = 
1142
 
        (apr_array_header_t *)((char *)self->request_rec + md->offset);
 
1299
        *(apr_array_header_t **)((char *)self->request_rec + md->offset);
1143
1300
 
1144
1301
    return tuple_from_array_header(ah);
1145
1302
}
1154
1311
{
1155
1312
    const PyMemberDef *md = find_memberdef(request_rec_mbrs, (char*)name);
1156
1313
    ap_method_list_t *ml = 
1157
 
        (ap_method_list_t *)((char *)self->request_rec + md->offset);
 
1314
        *(ap_method_list_t **)((char *)self->request_rec + md->offset);
1158
1315
 
1159
1316
    return tuple_from_method_list(ml);
1160
1317
}
1200
1357
    PyObject *result = NULL;
1201
1358
 
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);
 
1362
        }
1205
1363
        result = self->connection;
1206
1364
    }
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);
 
1368
        }
1210
1369
        result = self->server;
1211
1370
    }
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;
 
1375
        }
1215
1376
        result = self->next;
1216
1377
    }
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;
 
1382
        }
1220
1383
        result = self->prev;
1221
1384
    }
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);
 
1388
        }
1225
1389
        result = self->main;
1226
1390
    }
1227
1391
 
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"},
1310
1473
};
1311
1474
 
1312
1475
/**
 
1476
 ** request_tp_clear
 
1477
 **
 
1478
 *    
 
1479
 */
 
1480
static int request_tp_clear(requestobject *self)
 
1481
{   
 
1482
    PyObject* tmp;
 
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);
 
1498
    
 
1499
    return 0;
 
1500
}
 
1501
 
 
1502
 
 
1503
/**
1313
1504
 ** request_dealloc
1314
1505
 **
1315
1506
 *
1316
1507
 */
1317
1508
 
1318
 
static void request_dealloc(requestobject *self)
 
1509
static void request_tp_dealloc(requestobject *self)
1319
1510
{  
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
 
 
 
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);
 
1515
    
 
1516
    request_tp_clear(self);
 
1517
 
 
1518
    PyObject_GC_Del(self);
 
1519
}
 
1520
 
 
1521
/**
 
1522
 ** request_tp_traverse
 
1523
 **
 
1524
 *    Traversal of the request object
 
1525
 */
 
1526
static int request_tp_traverse(requestobject* self, visitproc visit, void *arg) {
 
1527
    int result;
 
1528
 
 
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;}
 
1542
    
 
1543
    // no need to Py_DECREF(dict) since the reference is borrowed
 
1544
    return 0;
 
1545
}
1337
1546
static char request_doc[] =
1338
1547
"Apache request_rec structure\n";
1339
1548
 
1343
1552
    "mp_request",
1344
1553
    sizeof(requestobject),
1345
1554
    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 */
 
1555
    (destructor)request_tp_dealloc,       /*tp_dealloc*/
 
1556
    0,                                 /*tp_print*/
 
1557
    0,                                 /*tp_getattr*/
 
1558
    0,                                 /*tp_setattr*/
 
1559
    0,                                 /*tp_compare*/
 
1560
    0,                                 /*tp_repr*/
 
1561
    0,                                 /*tp_as_number*/
 
1562
    0,                                 /*tp_as_sequence*/
 
1563
    0,                                 /*tp_as_mapping*/
 
1564
    0,                                 /*tp_hash*/
 
1565
    0,                                 /* tp_call */
 
1566
    0,                                 /* tp_str */
 
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 */
 
1578
    0,                                 /* tp_iter */
 
1579
    0,                                 /* tp_iternext */
 
1580
    request_methods,                   /* tp_methods */
 
1581
    request_members,                   /* tp_members */
 
1582
    request_getsets,                   /* tp_getset */
 
1583
    0,                                 /* tp_base */
 
1584
    0,                                 /* tp_dict */
 
1585
    0,                                 /* tp_descr_get */
 
1586
    0,                                 /* tp_descr_set */
 
1587
    offsetof(requestobject, dict),     /* tp_dictoffset */
 
1588
    0,                                 /* tp_init */
 
1589
    0,                                 /* tp_alloc */
 
1590
    0,                                 /* tp_new */
 
1591
    0,                                 /* tp_free */
1382
1592
};
1383
1593
 
1384
1594