@@ -204,7 +204,7 @@ static int set_wsgi_path_info(requestobject *self)
204204}
205205
206206/**
207- ** request.build_wsgi_env(reqeust self)
207+ ** request.build_wsgi_env(request self)
208208 **
209209 * Build a WSGI environment dictionary.
210210 *
@@ -289,6 +289,96 @@ static PyObject *req_build_wsgi_env(requestobject *self)
289289 return env ;
290290}
291291
292+ /**
293+ ** request.wsgi_start_response(self, args)
294+ **
295+ * The WSGI start_response()
296+ *
297+ */
298+ static PyObject * req_wsgi_start_response (requestobject * self , PyObject * args )
299+ {
300+
301+ char * status_line = NULL ;
302+ PyObject * headers = NULL ;
303+ PyObject * exc_info = NULL ;
304+ int status , i ;
305+
306+ if (! PyArg_ParseTuple (args , "sO|O:wsgi_start_response" , & status_line , & headers , & exc_info ))
307+ return NULL ;
308+
309+ if (!PyList_Check (headers )) {
310+ PyErr_Format (PyExc_TypeError , "headers argument must be a list, not a '%.200s'" ,
311+ headers -> ob_type -> tp_name );
312+ return NULL ;
313+ }
314+
315+ /* I don't understand what PEP3333 wants us to do with the
316+ * exception, we just re-raise it like other WSGI tools do */
317+ if (exc_info ) {
318+ PyObject * exc , * value , * tb ;
319+ if (PyArg_UnpackTuple (exc_info , "wsgi_start_response" , 3 , 3 , & exc , & value , & tb )) {
320+ Py_INCREF (exc );
321+ Py_INCREF (value );
322+ Py_INCREF (tb );
323+ PyErr_Restore (exc , value , tb );
324+ }
325+ return NULL ;
326+ }
327+
328+ /* add the headers */
329+ for (i = 0 ; i < PyList_Size (headers ); i ++ ) {
330+ PyObject * key = NULL , * val = NULL ;
331+ char * k , * v ;
332+ PyObject * item = PyList_GetItem (headers , i );
333+
334+ if (!PyTuple_CheckExact (item )) {
335+ PyErr_Format (PyExc_TypeError , "each header must be a tuple, not a '%.200s'" ,
336+ item -> ob_type -> tp_name );
337+ return NULL ;
338+ }
339+
340+ if (! PyArg_ParseTuple (item , "OO" , & key , & val ))
341+ return NULL ;
342+
343+ if (!((PyUnicode_CheckExact (key ) || PyBytes_CheckExact (key )))) {
344+ PyErr_Format (PyExc_TypeError , "header names must be strings, not '%.200s'" ,
345+ key -> ob_type -> tp_name );
346+ return NULL ;
347+ }
348+
349+ if (!((PyUnicode_CheckExact (val ) || PyBytes_CheckExact (val )))) {
350+ PyErr_Format (PyExc_TypeError , "header values must be strings, not '%.200s'" ,
351+ val -> ob_type -> tp_name );
352+ return NULL ;
353+ }
354+
355+ MP_ANYSTR_AS_STR (k , key , 1 );
356+ MP_ANYSTR_AS_STR (v , val , 1 );
357+ if ((!k ) || (!v )) {
358+ Py_DECREF (key ); /* MP_ANYSTR_AS_STR */
359+ Py_DECREF (val ); /* MP_ANYSTR_AS_STR */
360+ return NULL ;
361+ }
362+
363+ apr_table_add (self -> request_rec -> headers_out , k , v );
364+
365+ Py_DECREF (key ); /* MP_ANYSTR_AS_STR */
366+ Py_DECREF (val ); /* MP_ANYSTR_AS_STR */
367+ }
368+
369+ status = atoi (status_line );
370+ if (!ap_is_HTTP_VALID_RESPONSE (status )) {
371+ PyErr_SetString (PyExc_ValueError ,
372+ apr_psprintf (self -> request_rec -> pool ,
373+ "Invalid status line: %s" , status_line ));
374+ return NULL ;
375+ }
376+
377+ self -> request_rec -> status_line = apr_pstrdup (self -> request_rec -> pool , status_line );
378+
379+ return PyObject_GetAttrString ((PyObject * )self , "write" );
380+ }
381+
292382/**
293383 ** valid_phase()
294384 **
@@ -1591,6 +1681,7 @@ static PyMethodDef request_methods[] = {
15911681 {"write" , (PyCFunction ) req_write , METH_VARARGS },
15921682 {"get_config" , (PyCFunction ) req_get_config , METH_NOARGS },
15931683 {"build_wsgi_env" , (PyCFunction ) req_build_wsgi_env , METH_NOARGS },
1684+ {"wsgi_start_response" , (PyCFunction ) req_wsgi_start_response , METH_VARARGS },
15941685 {"add_cgi_vars" , (PyCFunction ) req_add_cgi_vars , METH_NOARGS },
15951686 {"add_common_vars" , (PyCFunction ) req_add_common_vars , METH_NOARGS },
15961687 {"add_handler" , (PyCFunction ) req_add_handler , METH_VARARGS },
0 commit comments