ajp-wsgi

changeset 49:ffa257a88246

Minor code cleanup.
author Allan Saddi <allan@saddi.com>
date Sun, 24 Dec 2006 17:25:00 +0000
parents c719a6d917c0
children ecb586935c77 6eb96bc18250
files ChangeLog Makefile.in ajp-glue.c input.c version.h wrapper.c wsgi-int.h wsgi.c wsgiinput.c wsgiwrapper.c
diffstat 10 files changed, 651 insertions(+), 651 deletions(-) [+]
line diff
     1.1 --- a/ChangeLog	Fri Dec 22 19:42:02 2006 +0000
     1.2 +++ b/ChangeLog	Sun Dec 24 17:25:00 2006 +0000
     1.3 @@ -1,3 +1,7 @@
     1.4 +2006-12-24  Allan Saddi  <allan@saddi.com>
     1.5 +
     1.6 +	* Minor code cleanup.
     1.7 +
     1.8  2006-12-22  Allan Saddi  <allan@saddi.com>
     1.9  
    1.10  	* Release version 0.5
     2.1 --- a/Makefile.in	Fri Dec 22 19:42:02 2006 +0000
     2.2 +++ b/Makefile.in	Sun Dec 24 17:25:00 2006 +0000
     2.3 @@ -10,7 +10,8 @@
     2.4  SYSLIBS=	@@SYSLIBS@@
     2.5  VERSION=	@@VERSION@@
     2.6  
     2.7 -OBJS=		main.o ajp.o wsgi.o input.o wrapper.o ajp-glue.o threadpool.o
     2.8 +OBJS=		main.o ajp.o wsgi.o wsgiinput.o wsgiwrapper.o ajp-glue.o \
     2.9 +		threadpool.o
    2.10  
    2.11  all: ajp-wsgi
    2.12  
    2.13 @@ -23,9 +24,9 @@
    2.14  
    2.15  wsgi.o: wsgi.c wsgi-int.h wsgi.h
    2.16  
    2.17 -input.o: input.c wsgi-int.h wsgi.h
    2.18 +wsgiinput.o: wsgiinput.c wsgi-int.h wsgi.h
    2.19  
    2.20 -wrapper.o: wrapper.c wsgi-int.h wsgi.h
    2.21 +wsgiwrapper.o: wsgiwrapper.c wsgi-int.h wsgi.h
    2.22  
    2.23  ajp-glue.o: ajp-glue.c ajp.h wsgi-int.h wsgi.h
    2.24  
     3.1 --- a/ajp-glue.c	Fri Dec 22 19:42:02 2006 +0000
     3.2 +++ b/ajp-glue.c	Sun Dec 24 17:25:00 2006 +0000
     3.3 @@ -131,7 +131,7 @@
     3.4      goto bad;
     3.5  
     3.6    /* wsgi.errors */
     3.7 -  if (PyDict_SetItemString(environ, "wsgi.errors", self->pStderr))
     3.8 +  if (PyDict_SetItemString(environ, "wsgi.errors", wsgiStderr))
     3.9      goto bad;
    3.10  
    3.11    /* wsgi.multithread */
    3.12 @@ -156,9 +156,9 @@
    3.13  
    3.14    /* SCRIPT_NAME/PATH_INFO */
    3.15    pathInfo = req_uri ? req_uri : req->uri;
    3.16 -  if (self->scriptNameLen) {
    3.17 -    if (!strncmp(pathInfo, self->scriptName, self->scriptNameLen))
    3.18 -      pathInfo = &pathInfo[self->scriptNameLen];
    3.19 +  if (wsgiScriptNameLen) {
    3.20 +    if (!strncmp(pathInfo, wsgiScriptName, wsgiScriptNameLen))
    3.21 +      pathInfo = &pathInfo[wsgiScriptNameLen];
    3.22      else
    3.23        fprintf (stderr, "WARNING: SCRIPT_NAME does not match REQUEST_URI\n");
    3.24    }
    3.25 @@ -166,7 +166,7 @@
    3.26    if (wsgiPutEnv(self, "PATH_INFO", pathInfo))
    3.27      goto bad;
    3.28  
    3.29 -  if (wsgiPutEnv(self, "SCRIPT_NAME", self->scriptName))
    3.30 +  if (wsgiPutEnv(self, "SCRIPT_NAME", wsgiScriptName))
    3.31      goto bad;
    3.32  
    3.33    /* Ensure QUERY_STRING is set */
     4.1 --- a/input.c	Fri Dec 22 19:42:02 2006 +0000
     4.2 +++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
     4.3 @@ -1,434 +0,0 @@
     4.4 -/*-
     4.5 - * Copyright (c) 2006 Allan Saddi <allan@saddi.com>
     4.6 - * All rights reserved.
     4.7 - *
     4.8 - * Redistribution and use in source and binary forms, with or without
     4.9 - * modification, are permitted provided that the following conditions
    4.10 - * are met:
    4.11 - * 1. Redistributions of source code must retain the above copyright
    4.12 - *    notice, this list of conditions and the following disclaimer.
    4.13 - * 2. Redistributions in binary form must reproduce the above copyright
    4.14 - *    notice, this list of conditions and the following disclaimer in the
    4.15 - *    documentation and/or other materials provided with the distribution.
    4.16 - *
    4.17 - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
    4.18 - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
    4.19 - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
    4.20 - * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
    4.21 - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
    4.22 - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
    4.23 - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
    4.24 - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
    4.25 - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
    4.26 - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
    4.27 - * SUCH DAMAGE.
    4.28 - *
    4.29 - * $Id$
    4.30 - */
    4.31 -
    4.32 -#include <Python.h>
    4.33 -
    4.34 -#include <assert.h>
    4.35 -
    4.36 -#include "wsgi-int.h"
    4.37 -
    4.38 -/* Add data as a new chunk at the tail of our chunk list */
    4.39 -int
    4.40 -wsgiBodyHandler(void *ctxt, uint8_t *data, size_t len)
    4.41 -{
    4.42 -  InputStream *self = (InputStream *)((Request *)wsgiGetRequestData(ctxt))->input;
    4.43 -  struct InputStream_chunk *chunk;
    4.44 -
    4.45 -  if (!len) return 0;
    4.46 -
    4.47 -  if ((chunk = PyMem_Malloc(sizeof(*chunk) + len)) == NULL)
    4.48 -    return -1;
    4.49 -
    4.50 -  chunk->next = NULL;
    4.51 -  chunk->size = len;
    4.52 -  memcpy(InputStream_chunk_DATA(chunk), data, len);
    4.53 -
    4.54 -  if (self->chunks) {
    4.55 -    self->tail->next = chunk;
    4.56 -    self->tail = chunk;
    4.57 -  }
    4.58 -  else {
    4.59 -    self->chunks = self->tail = chunk;
    4.60 -  }
    4.61 -
    4.62 -  self->avail += len;
    4.63 -
    4.64 -  return 0;
    4.65 -}
    4.66 -
    4.67 -/* Find occurrence of a character within our buffers */
    4.68 -static int
    4.69 -InputStream_findChar(InputStream *self, int start, int c)
    4.70 -{
    4.71 -  struct InputStream_chunk *chunk = self->chunks;
    4.72 -  int index = 0;
    4.73 -
    4.74 -  /* Find starting chunk */
    4.75 -  while (chunk != NULL) {
    4.76 -    if (chunk->size > start)
    4.77 -      break;
    4.78 -
    4.79 -    index += chunk->size;
    4.80 -    start -= chunk->size;
    4.81 -    chunk = chunk->next;
    4.82 -  }
    4.83 -
    4.84 -  while (chunk != NULL) {
    4.85 -    char *data = InputStream_chunk_DATA(chunk);
    4.86 -    char *found = memchr(&data[start], c, chunk->size - start);
    4.87 -    if (found != NULL) {
    4.88 -      return index + (found - data);
    4.89 -    }
    4.90 -    else {
    4.91 -      index += chunk->size;
    4.92 -      chunk = chunk->next;
    4.93 -      start = 0;
    4.94 -    }
    4.95 -  }
    4.96 -
    4.97 -  return -1;
    4.98 -}
    4.99 -
   4.100 -/* Consume characters between self->pos and newPos, returning it as a
   4.101 -   new Python string. */
   4.102 -static PyObject *
   4.103 -InputStream_consume(InputStream *self, int newPos)
   4.104 -{
   4.105 -  PyObject *result;
   4.106 -  int origSize = newPos - self->pos, size;
   4.107 -  char *data;
   4.108 -  struct InputStream_chunk *chunk = self->chunks, *next;
   4.109 -  int start = self->pos, index;
   4.110 -
   4.111 -  assert(chunk != NULL);
   4.112 -  assert(self->pos <= chunk->size);
   4.113 -
   4.114 -  if (!origSize)
   4.115 -    return PyString_FromString("");
   4.116 -
   4.117 -  result = PyString_FromStringAndSize(NULL, origSize);
   4.118 -  if (result == NULL)
   4.119 -    return NULL;
   4.120 -
   4.121 -  data = PyString_AS_STRING(result);
   4.122 -  index = 0;
   4.123 -
   4.124 -  /* Copy chunks into string */
   4.125 -  while (self->pos < newPos) {
   4.126 -    char *cdata = InputStream_chunk_DATA(chunk);
   4.127 -
   4.128 -    /* Constrain copy operations to chunk boundaries */
   4.129 -    size = newPos - self->pos;
   4.130 -    if (size > (chunk->size - start))
   4.131 -      size = chunk->size - start;
   4.132 -
   4.133 -    memcpy(&data[index], &cdata[start], size);
   4.134 -
   4.135 -    self->pos += size;
   4.136 -    index += size;
   4.137 -
   4.138 -    /* Advance to next chunk */
   4.139 -    chunk = chunk->next;
   4.140 -    start = 0;
   4.141 -  }
   4.142 -
   4.143 -  assert(index == origSize);
   4.144 -  data[index] = '\0';
   4.145 -
   4.146 -  /* Free fully-consumed chunks */
   4.147 -  chunk = self->chunks;
   4.148 -  while (self->pos > chunk->size) {
   4.149 -    next = chunk->next;
   4.150 -    self->pos -= chunk->size;
   4.151 -    self->size -= chunk->size;
   4.152 -    self->avail -= chunk->size;
   4.153 -    PyMem_Free(chunk);
   4.154 -    chunk = next;
   4.155 -  }
   4.156 -  self->chunks = chunk;
   4.157 -
   4.158 -  assert(self->chunks != NULL);
   4.159 -  assert(self->pos >= 0);
   4.160 -  assert(self->size > 0);
   4.161 -  assert(self->avail > 0);
   4.162 -
   4.163 -  return result;
   4.164 -}
   4.165 -
   4.166 -static void
   4.167 -InputStream_dealloc(InputStream *self)
   4.168 -{
   4.169 -  struct InputStream_chunk *chunk, *next;
   4.170 -  PyObject *tmp;
   4.171 -
   4.172 -  chunk = self->chunks;
   4.173 -  while (chunk != NULL) {
   4.174 -    next = chunk->next;
   4.175 -    PyMem_Free(chunk);
   4.176 -    chunk = next;
   4.177 -  }
   4.178 -  self->chunks = NULL;
   4.179 -
   4.180 -  tmp = (PyObject *)self->request;
   4.181 -  self->request = NULL;
   4.182 -  Py_XDECREF(tmp);
   4.183 -
   4.184 -  self->ob_type->tp_free((PyObject *)self);
   4.185 -}
   4.186 -
   4.187 -static PyObject *
   4.188 -InputStream_new(PyTypeObject *type, PyObject *args, PyObject *kwds)
   4.189 -{
   4.190 -  InputStream *self;
   4.191 -
   4.192 -  self = (InputStream *)type->tp_alloc(type, 0);
   4.193 -  if (self != NULL) {
   4.194 -    self->request = NULL;
   4.195 -    self->pos = 0;
   4.196 -    self->size = 0;
   4.197 -    self->avail = 0;
   4.198 -    self->chunks = NULL;
   4.199 -    self->tail = NULL;
   4.200 -  }
   4.201 -
   4.202 -  return (PyObject *)self;
   4.203 -}
   4.204 -
   4.205 -/* InputStream constructor. Expects to be passed the parent Request and
   4.206 -   the received Content-Length. */
   4.207 -static int
   4.208 -InputStream_init(InputStream *self, PyObject *args, PyObject *kwds)
   4.209 -{
   4.210 -  Request *request;
   4.211 -  int size;
   4.212 -
   4.213 -  if (!PyArg_ParseTuple(args, "O!i", &Request_Type, &request, &size))
   4.214 -    return -1;
   4.215 -
   4.216 -  Py_INCREF(request);
   4.217 -  self->request = request;
   4.218 -  self->size = size;
   4.219 -
   4.220 -  return 0;
   4.221 -}
   4.222 -
   4.223 -/* read() implementation */
   4.224 -static PyObject *
   4.225 -InputStream_read(InputStream *self, PyObject *args)
   4.226 -{
   4.227 -  int size = -1, newPos;
   4.228 -
   4.229 -  if (!PyArg_ParseTuple(args, "|i:read", &size))
   4.230 -    return NULL;
   4.231 -
   4.232 -  if (self->pos == self->size)
   4.233 -    return PyString_FromString("");
   4.234 -
   4.235 -  for (;;) {
   4.236 -    if (size < 0 || (self->avail - self->pos) < size) {
   4.237 -      /* Not enough data available */
   4.238 -      if (self->avail == self->size) {
   4.239 -	/* No more coming */
   4.240 -	newPos = self->avail;
   4.241 -	break;
   4.242 -      }
   4.243 -      else {
   4.244 -	/* Ask for more data */
   4.245 -	if (wsgiGetBody(self->request->context))
   4.246 -	  return NULL;
   4.247 -	continue;
   4.248 -      }
   4.249 -    }
   4.250 -    else {
   4.251 -      newPos = self->pos + size;
   4.252 -      break;
   4.253 -    }
   4.254 -  }
   4.255 -
   4.256 -  return InputStream_consume(self, newPos);
   4.257 -}
   4.258 -
   4.259 -/* readline() implementation. Supports "size" argument not required by
   4.260 -   WSGI spec (but now required by Python 2.5's cgi module) */
   4.261 -static PyObject *
   4.262 -InputStream_readline(InputStream *self, PyObject *args)
   4.263 -{
   4.264 -  int size = -1, start, i, newPos;
   4.265 -
   4.266 -  if (!PyArg_ParseTuple(args, "|i:readline", &size))
   4.267 -    return NULL;
   4.268 -
   4.269 -  if (self->pos == self->size)
   4.270 -    return PyString_FromString("");
   4.271 -
   4.272 -  start = self->pos;
   4.273 -
   4.274 -  for (;;) {
   4.275 -    /* Find newline */
   4.276 -    i = InputStream_findChar(self, start, '\n');
   4.277 -    if (i < 0) {
   4.278 -      /* Not found? */
   4.279 -      if (self->avail == self->size) {
   4.280 -	/* No more data coming */
   4.281 -	newPos = self->avail;
   4.282 -	break;
   4.283 -      }
   4.284 -      else {
   4.285 -	if (size < 0 || (self->avail - self->pos) < size) {
   4.286 -	  /* Wait for more to come */
   4.287 -	  start = self->avail; /* Search new chunk only */
   4.288 -	  if (wsgiGetBody(self->request->context))
   4.289 -	    return NULL;
   4.290 -	  continue;
   4.291 -	}
   4.292 -	else {
   4.293 -	  /* Already have at least size bytes available */
   4.294 -	  newPos = self->pos + size;
   4.295 -	  break;
   4.296 -	}
   4.297 -      }
   4.298 -    }
   4.299 -    else {
   4.300 -      newPos = i + 1;
   4.301 -
   4.302 -      /* Trim line, if necessary */
   4.303 -      if (size >= 0 && (self->pos + size) < newPos)
   4.304 -	newPos = self->pos + size;
   4.305 -      break;
   4.306 -    }
   4.307 -  }
   4.308 -
   4.309 -  return InputStream_consume(self, newPos);
   4.310 -}
   4.311 -
   4.312 -/* readlines() implementation. Supports "hint" argument. */
   4.313 -static PyObject *
   4.314 -InputStream_readlines(InputStream *self, PyObject *args)
   4.315 -{
   4.316 -  int hint = 0, total = 0;
   4.317 -  PyObject *lines = NULL, *args2 = NULL, *line;
   4.318 -  int len, ret;
   4.319 -
   4.320 -  if (!PyArg_ParseTuple(args, "|i:readlines", &hint))
   4.321 -    return NULL;
   4.322 -
   4.323 -  if ((lines = PyList_New(0)) == NULL)
   4.324 -    return NULL;
   4.325 -
   4.326 -  if ((args2 = PyTuple_New(0)) == NULL)
   4.327 -    goto bad;
   4.328 -
   4.329 -  if ((line = InputStream_readline(self, args2)) == NULL)
   4.330 -    goto bad;
   4.331 -
   4.332 -  while ((len = PyString_GET_SIZE(line)) > 0) {
   4.333 -    ret = PyList_Append(lines, line);
   4.334 -    Py_DECREF(line);
   4.335 -    if (ret)
   4.336 -      goto bad;
   4.337 -    total += len;
   4.338 -    if (hint > 0 && total >= hint)
   4.339 -      break;
   4.340 -
   4.341 -    if ((line = InputStream_readline(self, args2)) == NULL)
   4.342 -      goto bad;
   4.343 -  }
   4.344 -
   4.345 -  Py_DECREF(line);
   4.346 -  Py_DECREF(args2);
   4.347 -
   4.348 -  return lines;
   4.349 -
   4.350 - bad:
   4.351 -  Py_XDECREF(args2);
   4.352 -  Py_XDECREF(lines);
   4.353 -  return NULL;
   4.354 -}
   4.355 -
   4.356 -/* __iter__() implementation. Simply returns self. */
   4.357 -static PyObject *
   4.358 -InputStream_iter(InputStream *self)
   4.359 -{
   4.360 -  Py_INCREF(self);
   4.361 -  return (PyObject *)self;
   4.362 -}
   4.363 -
   4.364 -/* next() implementation for iteration protocol support */
   4.365 -static PyObject *
   4.366 -InputStream_iternext(InputStream *self)
   4.367 -{
   4.368 -  PyObject *line, *args;
   4.369 -
   4.370 -  if ((args = PyTuple_New(0)) == NULL)
   4.371 -    return NULL;
   4.372 -
   4.373 -  line = InputStream_readline(self, args);
   4.374 -  Py_DECREF(args);
   4.375 -  if (line == NULL)
   4.376 -    return NULL;
   4.377 -
   4.378 -  if (PyString_GET_SIZE(line) == 0) {
   4.379 -    Py_DECREF(line);
   4.380 -    PyErr_Clear();
   4.381 -    return NULL;
   4.382 -  }
   4.383 -
   4.384 -  return line;
   4.385 -}
   4.386 -
   4.387 -static PyMethodDef InputStream_methods[] = {
   4.388 -  { "read", (PyCFunction)InputStream_read, METH_VARARGS,
   4.389 -    "Read from this input stream" },
   4.390 -  { "readline", (PyCFunction)InputStream_readline, METH_VARARGS,
   4.391 -    "Read a line from this input stream" },
   4.392 -  { "readlines", (PyCFunction)InputStream_readlines, METH_VARARGS,
   4.393 -    "Read lines from this input stream" },
   4.394 -  { NULL }
   4.395 -};
   4.396 -
   4.397 -PyTypeObject InputStream_Type = {
   4.398 -  PyObject_HEAD_INIT(NULL)
   4.399 -  0,                         /*ob_size*/
   4.400 -  "_wsgisup.InputStream",    /*tp_name*/
   4.401 -  sizeof(InputStream),       /*tp_basicsize*/
   4.402 -  0,                         /*tp_itemsize*/
   4.403 -  (destructor)InputStream_dealloc, /*tp_dealloc*/
   4.404 -  0,                         /*tp_print*/
   4.405 -  0,                         /*tp_getattr*/
   4.406 -  0,                         /*tp_setattr*/
   4.407 -  0,                         /*tp_compare*/
   4.408 -  0,                         /*tp_repr*/
   4.409 -  0,                         /*tp_as_number*/
   4.410 -  0,                         /*tp_as_sequence*/
   4.411 -  0,                         /*tp_as_mapping*/
   4.412 -  0,                         /*tp_hash */
   4.413 -  0,                         /*tp_call*/
   4.414 -  0,                         /*tp_str*/
   4.415 -  0,                         /*tp_getattro*/
   4.416 -  0,                         /*tp_setattro*/
   4.417 -  0,                         /*tp_as_buffer*/
   4.418 -  Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_ITER, /*tp_flags*/
   4.419 -  "wsgi.input implementation", /* tp_doc */
   4.420 -  0,		             /* tp_traverse */
   4.421 -  0,		             /* tp_clear */
   4.422 -  0,		             /* tp_richcompare */
   4.423 -  0,		             /* tp_weaklistoffset */
   4.424 -  (getiterfunc)InputStream_iter, /* tp_iter */
   4.425 -  (iternextfunc)InputStream_iternext, /* tp_iternext */
   4.426 -  InputStream_methods,       /* tp_methods */
   4.427 -  0,                         /* tp_members */
   4.428 -  0,                         /* tp_getset */
   4.429 -  0,                         /* tp_base */
   4.430 -  0,                         /* tp_dict */
   4.431 -  0,                         /* tp_descr_get */
   4.432 -  0,                         /* tp_descr_set */
   4.433 -  0,                         /* tp_dictoffset */
   4.434 -  (initproc)InputStream_init, /* tp_init */
   4.435 -  0,                         /* tp_alloc */
   4.436 -  InputStream_new,           /* tp_new */
   4.437 -};
     5.1 --- a/version.h	Fri Dec 22 19:42:02 2006 +0000
     5.2 +++ b/version.h	Sun Dec 24 17:25:00 2006 +0000
     5.3 @@ -1,5 +1,5 @@
     5.4  #define VERSION_MAJOR 0
     5.5 -#define VERSION_MINOR 5
     5.6 +#define VERSION_MINOR 6
     5.7  #define VERSION_PATCHLEVEL 0
     5.8 -#define VERSION_STRING "0.5"
     5.9 -#define VERSION_DATE "2006-Dec-22"
    5.10 +#define VERSION_STRING "0.6"
    5.11 +#define VERSION_DATE "2006-Dec-24"
     6.1 --- a/wrapper.c	Fri Dec 22 19:42:02 2006 +0000
     6.2 +++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
     6.3 @@ -1,187 +0,0 @@
     6.4 -/*-
     6.5 - * Copyright (c) 2006 Allan Saddi <allan@saddi.com>
     6.6 - * All rights reserved.
     6.7 - *
     6.8 - * Redistribution and use in source and binary forms, with or without
     6.9 - * modification, are permitted provided that the following conditions
    6.10 - * are met:
    6.11 - * 1. Redistributions of source code must retain the above copyright
    6.12 - *    notice, this list of conditions and the following disclaimer.
    6.13 - * 2. Redistributions in binary form must reproduce the above copyright
    6.14 - *    notice, this list of conditions and the following disclaimer in the
    6.15 - *    documentation and/or other materials provided with the distribution.
    6.16 - *
    6.17 - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
    6.18 - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
    6.19 - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
    6.20 - * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
    6.21 - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
    6.22 - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
    6.23 - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
    6.24 - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
    6.25 - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
    6.26 - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
    6.27 - * SUCH DAMAGE.
    6.28 - *
    6.29 - * $Id$
    6.30 - */
    6.31 -
    6.32 -#include <Python.h>
    6.33 -
    6.34 -#include "wsgi-int.h"
    6.35 -
    6.36 -static void
    6.37 -FileWrapper_dealloc(FileWrapper *self)
    6.38 -{
    6.39 -  PyObject *tmp;
    6.40 -
    6.41 -  tmp = (PyObject *)self->filelike;
    6.42 -  self->filelike = NULL;
    6.43 -  Py_XDECREF(tmp);
    6.44 -
    6.45 -  self->ob_type->tp_free((PyObject *)self);
    6.46 -}
    6.47 -
    6.48 -static PyObject *
    6.49 -FileWrapper_new(PyTypeObject *type, PyObject *args, PyObject *kwds)
    6.50 -{
    6.51 -  FileWrapper *self;
    6.52 -
    6.53 -  self = (FileWrapper *)type->tp_alloc(type, 0);
    6.54 -  if (self != NULL) {
    6.55 -    self->filelike = NULL;
    6.56 -  }
    6.57 -
    6.58 -  return (PyObject *)self;
    6.59 -}
    6.60 -
    6.61 -static int
    6.62 -FileWrapper_init(FileWrapper *self, PyObject *args, PyObject *kwds)
    6.63 -{
    6.64 -  PyObject *filelike;
    6.65 -  int blocksize = 4096;
    6.66 -
    6.67 -  if (!PyArg_ParseTuple(args, "O|i", &filelike, &blocksize))
    6.68 -    return -1;
    6.69 -
    6.70 -  Py_INCREF(filelike);
    6.71 -  self->filelike = filelike;
    6.72 -  self->blocksize = blocksize;
    6.73 -
    6.74 -  return 0;
    6.75 -}
    6.76 -
    6.77 -static PyObject *
    6.78 -FileWrapper_iter(FileWrapper *self)
    6.79 -{
    6.80 -  Py_INCREF(self);
    6.81 -  return (PyObject *)self;
    6.82 -}
    6.83 -
    6.84 -static PyObject *
    6.85 -FileWrapper_iternext(FileWrapper *self)
    6.86 -{
    6.87 -  PyObject *pRead, *args, *data;
    6.88 -  int len;
    6.89 -
    6.90 -  if ((pRead = PyObject_GetAttrString(self->filelike, "read")) == NULL)
    6.91 -    return NULL;
    6.92 -
    6.93 -  if ((args = Py_BuildValue("(i)", self->blocksize)) == NULL) {
    6.94 -    Py_DECREF(pRead);
    6.95 -    return NULL;
    6.96 -  }
    6.97 -
    6.98 -  data = PyObject_CallObject(pRead, args);
    6.99 -  Py_DECREF(args);
   6.100 -  Py_DECREF(pRead);
   6.101 -  if (data == NULL)
   6.102 -    return NULL;
   6.103 -
   6.104 -  len = PyString_Size(data);
   6.105 -  if (PyErr_Occurred()) {
   6.106 -    Py_DECREF(data);
   6.107 -    return NULL;
   6.108 -  }
   6.109 -
   6.110 -  if (len == 0) {
   6.111 -    Py_DECREF(data);
   6.112 -    PyErr_Clear();
   6.113 -    return NULL;
   6.114 -  }
   6.115 -
   6.116 -  return data;
   6.117 -}
   6.118 -
   6.119 -static PyObject *
   6.120 -FileWrapper_close(FileWrapper *self, PyObject *args)
   6.121 -{
   6.122 -  PyObject *pClose, *args2, *result;
   6.123 -
   6.124 -  if (PyObject_HasAttrString(self->filelike, "close")) {
   6.125 -    if ((pClose = PyObject_GetAttrString(self->filelike, "close")) == NULL)
   6.126 -      return NULL;
   6.127 -
   6.128 -    if ((args2 = PyTuple_New(0)) == NULL) {
   6.129 -      Py_DECREF(pClose);
   6.130 -      return NULL;
   6.131 -    }
   6.132 -
   6.133 -    result = PyObject_CallObject(pClose, args2);
   6.134 -    Py_DECREF(args2);
   6.135 -    Py_DECREF(pClose);
   6.136 -    if (result == NULL)
   6.137 -      return NULL;
   6.138 -  }
   6.139 -
   6.140 -  Py_INCREF(Py_None);
   6.141 -  return Py_None;
   6.142 -}
   6.143 -
   6.144 -static PyMethodDef FileWrapper_methods[] = {
   6.145 -  { "close", (PyCFunction)FileWrapper_close, METH_VARARGS,
   6.146 -    "Calls the file-like object's close method" },
   6.147 -  { NULL }
   6.148 -};
   6.149 -
   6.150 -PyTypeObject FileWrapper_Type = {
   6.151 -  PyObject_HEAD_INIT(NULL)
   6.152 -  0,                         /*ob_size*/
   6.153 -  "_wsgisup.FileWrapper",    /*tp_name*/
   6.154 -  sizeof(FileWrapper),       /*tp_basicsize*/
   6.155 -  0,                         /*tp_itemsize*/
   6.156 -  (destructor)FileWrapper_dealloc, /*tp_dealloc*/
   6.157 -  0,                         /*tp_print*/
   6.158 -  0,                         /*tp_getattr*/
   6.159 -  0,                         /*tp_setattr*/
   6.160 -  0,                         /*tp_compare*/
   6.161 -  0,                         /*tp_repr*/
   6.162 -  0,                         /*tp_as_number*/
   6.163 -  0,                         /*tp_as_sequence*/
   6.164 -  0,                         /*tp_as_mapping*/
   6.165 -  0,                         /*tp_hash */
   6.166 -  0,                         /*tp_call*/
   6.167 -  0,                         /*tp_str*/
   6.168 -  0,                         /*tp_getattro*/
   6.169 -  0,                         /*tp_setattro*/
   6.170 -  0,                         /*tp_as_buffer*/
   6.171 -  Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_ITER, /*tp_flags*/
   6.172 -  "wsgi.file_wrapper implementation", /* tp_doc */
   6.173 -  0,		             /* tp_traverse */
   6.174 -  0,		             /* tp_clear */
   6.175 -  0,		             /* tp_richcompare */
   6.176 -  0,		             /* tp_weaklistoffset */
   6.177 -  (getiterfunc)FileWrapper_iter, /* tp_iter */
   6.178 -  (iternextfunc)FileWrapper_iternext, /* tp_iternext */
   6.179 -  FileWrapper_methods,       /* tp_methods */
   6.180 -  0,                         /* tp_members */
   6.181 -  0,                         /* tp_getset */
   6.182 -  0,                         /* tp_base */
   6.183 -  0,                         /* tp_dict */
   6.184 -  0,                         /* tp_descr_get */
   6.185 -  0,                         /* tp_descr_set */
   6.186 -  0,                         /* tp_dictoffset */
   6.187 -  (initproc)FileWrapper_init, /* tp_init */
   6.188 -  0,                         /* tp_alloc */
   6.189 -  FileWrapper_new,           /* tp_new */
   6.190 -};
     7.1 --- a/wsgi-int.h	Fri Dec 22 19:42:02 2006 +0000
     7.2 +++ b/wsgi-int.h	Sun Dec 24 17:25:00 2006 +0000
     7.3 @@ -45,11 +45,6 @@
     7.4    PyObject *headers;
     7.5    PyObject *result;
     7.6    int headers_sent;
     7.7 -
     7.8 -  /* Convenience */
     7.9 -  PyObject *pStderr; /* owned by module */
    7.10 -  const char *scriptName;
    7.11 -  int scriptNameLen;
    7.12  } Request;
    7.13  
    7.14  struct InputStream_chunk {
    7.15 @@ -104,4 +99,9 @@
    7.16  int wsgiPutEnv(Request *req, const char *key, const char *value);
    7.17  const char *wsgiUnquote(const char *s);
    7.18  
    7.19 +/* Externs available to glue */
    7.20 +extern PyObject *wsgiStderr;
    7.21 +extern const char *wsgiScriptName;
    7.22 +extern int wsgiScriptNameLen;
    7.23 +
    7.24  #endif /* APS_WSGI_INT_H */
     8.1 --- a/wsgi.c	Fri Dec 22 19:42:02 2006 +0000
     8.2 +++ b/wsgi.c	Sun Dec 24 17:25:00 2006 +0000
     8.3 @@ -33,10 +33,10 @@
     8.4  
     8.5  #include "wsgi-int.h"
     8.6  
     8.7 -static const char *scriptName = "";
     8.8 -static int scriptNameLen = 0;
     8.9 +PyObject *wsgiStderr;
    8.10 +const char *wsgiScriptName = "";
    8.11 +int wsgiScriptNameLen = 0;
    8.12  
    8.13 -static PyObject *pStderr;
    8.14  static PyObject *pApp;
    8.15  static PyThreadState *_main;
    8.16  
    8.17 @@ -167,11 +167,6 @@
    8.18      self->headers = NULL;
    8.19      self->result = NULL;
    8.20      self->headers_sent = 0;
    8.21 -
    8.22 -    /* So we don't have to extern these... */
    8.23 -    self->pStderr = pStderr;
    8.24 -    self->scriptName = scriptName;
    8.25 -    self->scriptNameLen = scriptNameLen;
    8.26    }
    8.27  
    8.28    return (PyObject *)self;
    8.29 @@ -599,19 +594,19 @@
    8.30  {
    8.31    PyEval_RestoreThread(_main);
    8.32    Py_DECREF(pApp);
    8.33 -  Py_DECREF(pStderr);
    8.34 +  Py_DECREF(wsgiStderr);
    8.35    Py_Finalize();
    8.36  }
    8.37  
    8.38  int
    8.39 -wsgiInit(const char *moduleName, const char *appName, const char *_scriptName,
    8.40 +wsgiInit(const char *moduleName, const char *appName, const char *scriptName,
    8.41  	 const char *progName)
    8.42  {
    8.43    PyObject *pName, *pModule;
    8.44    char *argv[1];
    8.45  
    8.46 -  scriptName = _scriptName;
    8.47 -  scriptNameLen = strlen(_scriptName);
    8.48 +  wsgiScriptName = scriptName;
    8.49 +  wsgiScriptNameLen = strlen(scriptName);
    8.50  
    8.51    PyEval_InitThreads();
    8.52    Py_Initialize();
    8.53 @@ -629,9 +624,9 @@
    8.54    if (pModule == NULL)
    8.55      goto err;
    8.56  
    8.57 -  pStderr = PyObject_GetAttrString(pModule, "stderr");
    8.58 +  wsgiStderr = PyObject_GetAttrString(pModule, "stderr");
    8.59    Py_DECREF(pModule);
    8.60 -  if (pStderr == NULL)
    8.61 +  if (wsgiStderr == NULL)
    8.62      goto err;
    8.63  
    8.64    pName = PyString_FromString(moduleName);
     9.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     9.2 +++ b/wsgiinput.c	Sun Dec 24 17:25:00 2006 +0000
     9.3 @@ -0,0 +1,434 @@
     9.4 +/*-
     9.5 + * Copyright (c) 2006 Allan Saddi <allan@saddi.com>
     9.6 + * All rights reserved.
     9.7 + *
     9.8 + * Redistribution and use in source and binary forms, with or without
     9.9 + * modification, are permitted provided that the following conditions
    9.10 + * are met:
    9.11 + * 1. Redistributions of source code must retain the above copyright
    9.12 + *    notice, this list of conditions and the following disclaimer.
    9.13 + * 2. Redistributions in binary form must reproduce the above copyright
    9.14 + *    notice, this list of conditions and the following disclaimer in the
    9.15 + *    documentation and/or other materials provided with the distribution.
    9.16 + *
    9.17 + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
    9.18 + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
    9.19 + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
    9.20 + * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
    9.21 + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
    9.22 + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
    9.23 + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
    9.24 + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
    9.25 + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
    9.26 + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
    9.27 + * SUCH DAMAGE.
    9.28 + *
    9.29 + * $Id$
    9.30 + */
    9.31 +
    9.32 +#include <Python.h>
    9.33 +
    9.34 +#include <assert.h>
    9.35 +
    9.36 +#include "wsgi-int.h"
    9.37 +
    9.38 +/* Add data as a new chunk at the tail of our chunk list */
    9.39 +int
    9.40 +wsgiBodyHandler(void *ctxt, uint8_t *data, size_t len)
    9.41 +{
    9.42 +  InputStream *self = (InputStream *)((Request *)wsgiGetRequestData(ctxt))->input;
    9.43 +  struct InputStream_chunk *chunk;
    9.44 +
    9.45 +  if (!len) return 0;
    9.46 +
    9.47 +  if ((chunk = PyMem_Malloc(sizeof(*chunk) + len)) == NULL)
    9.48 +    return -1;
    9.49 +
    9.50 +  chunk->next = NULL;
    9.51 +  chunk->size = len;
    9.52 +  memcpy(InputStream_chunk_DATA(chunk), data, len);
    9.53 +
    9.54 +  if (self->chunks) {
    9.55 +    self->tail->next = chunk;
    9.56 +    self->tail = chunk;
    9.57 +  }
    9.58 +  else {
    9.59 +    self->chunks = self->tail = chunk;
    9.60 +  }
    9.61 +
    9.62 +  self->avail += len;
    9.63 +
    9.64 +  return 0;
    9.65 +}
    9.66 +
    9.67 +/* Find occurrence of a character within our buffers */
    9.68 +static int
    9.69 +InputStream_findChar(InputStream *self, int start, int c)
    9.70 +{
    9.71 +  struct InputStream_chunk *chunk = self->chunks;
    9.72 +  int index = 0;
    9.73 +
    9.74 +  /* Find starting chunk */
    9.75 +  while (chunk != NULL) {
    9.76 +    if (chunk->size > start)
    9.77 +      break;
    9.78 +
    9.79 +    index += chunk->size;
    9.80 +    start -= chunk->size;
    9.81 +    chunk = chunk->next;
    9.82 +  }
    9.83 +
    9.84 +  while (chunk != NULL) {
    9.85 +    char *data = InputStream_chunk_DATA(chunk);
    9.86 +    char *found = memchr(&data[start], c, chunk->size - start);
    9.87 +    if (found != NULL) {
    9.88 +      return index + (found - data);
    9.89 +    }
    9.90 +    else {
    9.91 +      index += chunk->size;
    9.92 +      chunk = chunk->next;
    9.93 +      start = 0;
    9.94 +    }
    9.95 +  }
    9.96 +
    9.97 +  return -1;
    9.98 +}
    9.99 +
   9.100 +/* Consume characters between self->pos and newPos, returning it as a
   9.101 +   new Python string. */
   9.102 +static PyObject *
   9.103 +InputStream_consume(InputStream *self, int newPos)
   9.104 +{
   9.105 +  PyObject *result;
   9.106 +  int origSize = newPos - self->pos, size;
   9.107 +  char *data;
   9.108 +  struct InputStream_chunk *chunk = self->chunks, *next;
   9.109 +  int start = self->pos, index;
   9.110 +
   9.111 +  assert(chunk != NULL);
   9.112 +  assert(self->pos <= chunk->size);
   9.113 +
   9.114 +  if (!origSize)
   9.115 +    return PyString_FromString("");
   9.116 +
   9.117 +  result = PyString_FromStringAndSize(NULL, origSize);
   9.118 +  if (result == NULL)
   9.119 +    return NULL;
   9.120 +
   9.121 +  data = PyString_AS_STRING(result);
   9.122 +  index = 0;
   9.123 +
   9.124 +  /* Copy chunks into string */
   9.125 +  while (self->pos < newPos) {
   9.126 +    char *cdata = InputStream_chunk_DATA(chunk);
   9.127 +
   9.128 +    /* Constrain copy operations to chunk boundaries */
   9.129 +    size = newPos - self->pos;
   9.130 +    if (size > (chunk->size - start))
   9.131 +      size = chunk->size - start;
   9.132 +
   9.133 +    memcpy(&data[index], &cdata[start], size);
   9.134 +
   9.135 +    self->pos += size;
   9.136 +    index += size;
   9.137 +
   9.138 +    /* Advance to next chunk */
   9.139 +    chunk = chunk->next;
   9.140 +    start = 0;
   9.141 +  }
   9.142 +
   9.143 +  assert(index == origSize);
   9.144 +  data[index] = '\0';
   9.145 +
   9.146 +  /* Free fully-consumed chunks */
   9.147 +  chunk = self->chunks;
   9.148 +  while (self->pos > chunk->size) {
   9.149 +    next = chunk->next;
   9.150 +    self->pos -= chunk->size;
   9.151 +    self->size -= chunk->size;
   9.152 +    self->avail -= chunk->size;
   9.153 +    PyMem_Free(chunk);
   9.154 +    chunk = next;
   9.155 +  }
   9.156 +  self->chunks = chunk;
   9.157 +
   9.158 +  assert(self->chunks != NULL);
   9.159 +  assert(self->pos >= 0);
   9.160 +  assert(self->size > 0);
   9.161 +  assert(self->avail > 0);
   9.162 +
   9.163 +  return result;
   9.164 +}
   9.165 +
   9.166 +static void
   9.167 +InputStream_dealloc(InputStream *self)
   9.168 +{
   9.169 +  struct InputStream_chunk *chunk, *next;
   9.170 +  PyObject *tmp;
   9.171 +
   9.172 +  chunk = self->chunks;
   9.173 +  while (chunk != NULL) {
   9.174 +    next = chunk->next;
   9.175 +    PyMem_Free(chunk);
   9.176 +    chunk = next;
   9.177 +  }
   9.178 +  self->chunks = NULL;
   9.179 +
   9.180 +  tmp = (PyObject *)self->request;
   9.181 +  self->request = NULL;
   9.182 +  Py_XDECREF(tmp);
   9.183 +
   9.184 +  self->ob_type->tp_free((PyObject *)self);
   9.185 +}
   9.186 +
   9.187 +static PyObject *
   9.188 +InputStream_new(PyTypeObject *type, PyObject *args, PyObject *kwds)
   9.189 +{
   9.190 +  InputStream *self;
   9.191 +
   9.192 +  self = (InputStream *)type->tp_alloc(type, 0);
   9.193 +  if (self != NULL) {
   9.194 +    self->request = NULL;
   9.195 +    self->pos = 0;
   9.196 +    self->size = 0;
   9.197 +    self->avail = 0;
   9.198 +    self->chunks = NULL;
   9.199 +    self->tail = NULL;
   9.200 +  }
   9.201 +
   9.202 +  return (PyObject *)self;
   9.203 +}
   9.204 +
   9.205 +/* InputStream constructor. Expects to be passed the parent Request and
   9.206 +   the received Content-Length. */
   9.207 +static int
   9.208 +InputStream_init(InputStream *self, PyObject *args, PyObject *kwds)
   9.209 +{
   9.210 +  Request *request;
   9.211 +  int size;
   9.212 +
   9.213 +  if (!PyArg_ParseTuple(args, "O!i", &Request_Type, &request, &size))
   9.214 +    return -1;
   9.215 +
   9.216 +  Py_INCREF(request);
   9.217 +  self->request = request;
   9.218 +  self->size = size;
   9.219 +
   9.220 +  return 0;
   9.221 +}
   9.222 +
   9.223 +/* read() implementation */
   9.224 +static PyObject *
   9.225 +InputStream_read(InputStream *self, PyObject *args)
   9.226 +{
   9.227 +  int size = -1, newPos;
   9.228 +
   9.229 +  if (!PyArg_ParseTuple(args, "|i:read", &size))
   9.230 +    return NULL;
   9.231 +
   9.232 +  if (self->pos == self->size)
   9.233 +    return PyString_FromString("");
   9.234 +
   9.235 +  for (;;) {
   9.236 +    if (size < 0 || (self->avail - self->pos) < size) {
   9.237 +      /* Not enough data available */
   9.238 +      if (self->avail == self->size) {
   9.239 +	/* No more coming */
   9.240 +	newPos = self->avail;
   9.241 +	break;
   9.242 +      }
   9.243 +      else {
   9.244 +	/* Ask for more data */
   9.245 +	if (wsgiGetBody(self->request->context))
   9.246 +	  return NULL;
   9.247 +	continue;
   9.248 +      }
   9.249 +    }
   9.250 +    else {
   9.251 +      newPos = self->pos + size;
   9.252 +      break;
   9.253 +    }
   9.254 +  }
   9.255 +
   9.256 +  return InputStream_consume(self, newPos);
   9.257 +}
   9.258 +
   9.259 +/* readline() implementation. Supports "size" argument not required by
   9.260 +   WSGI spec (but now required by Python 2.5's cgi module) */
   9.261 +static PyObject *
   9.262 +InputStream_readline(InputStream *self, PyObject *args)
   9.263 +{
   9.264 +  int size = -1, start, i, newPos;
   9.265 +
   9.266 +  if (!PyArg_ParseTuple(args, "|i:readline", &size))
   9.267 +    return NULL;
   9.268 +
   9.269 +  if (self->pos == self->size)
   9.270 +    return PyString_FromString("");
   9.271 +
   9.272 +  start = self->pos;
   9.273 +
   9.274 +  for (;;) {
   9.275 +    /* Find newline */
   9.276 +    i = InputStream_findChar(self, start, '\n');
   9.277 +    if (i < 0) {
   9.278 +      /* Not found? */
   9.279 +      if (self->avail == self->size) {
   9.280 +	/* No more data coming */
   9.281 +	newPos = self->avail;
   9.282 +	break;
   9.283 +      }
   9.284 +      else {
   9.285 +	if (size < 0 || (self->avail - self->pos) < size) {
   9.286 +	  /* Wait for more to come */
   9.287 +	  start = self->avail; /* Search new chunk only */
   9.288 +	  if (wsgiGetBody(self->request->context))
   9.289 +	    return NULL;
   9.290 +	  continue;
   9.291 +	}
   9.292 +	else {
   9.293 +	  /* Already have at least size bytes available */
   9.294 +	  newPos = self->pos + size;
   9.295 +	  break;
   9.296 +	}
   9.297 +      }
   9.298 +    }
   9.299 +    else {
   9.300 +      newPos = i + 1;
   9.301 +
   9.302 +      /* Trim line, if necessary */
   9.303 +      if (size >= 0 && (self->pos + size) < newPos)
   9.304 +	newPos = self->pos + size;
   9.305 +      break;
   9.306 +    }
   9.307 +  }
   9.308 +
   9.309 +  return InputStream_consume(self, newPos);
   9.310 +}
   9.311 +
   9.312 +/* readlines() implementation. Supports "hint" argument. */
   9.313 +static PyObject *
   9.314 +InputStream_readlines(InputStream *self, PyObject *args)
   9.315 +{
   9.316 +  int hint = 0, total = 0;
   9.317 +  PyObject *lines = NULL, *args2 = NULL, *line;
   9.318 +  int len, ret;
   9.319 +
   9.320 +  if (!PyArg_ParseTuple(args, "|i:readlines", &hint))
   9.321 +    return NULL;
   9.322 +
   9.323 +  if ((lines = PyList_New(0)) == NULL)
   9.324 +    return NULL;
   9.325 +
   9.326 +  if ((args2 = PyTuple_New(0)) == NULL)
   9.327 +    goto bad;
   9.328 +
   9.329 +  if ((line = InputStream_readline(self, args2)) == NULL)
   9.330 +    goto bad;
   9.331 +
   9.332 +  while ((len = PyString_GET_SIZE(line)) > 0) {
   9.333 +    ret = PyList_Append(lines, line);
   9.334 +    Py_DECREF(line);
   9.335 +    if (ret)
   9.336 +      goto bad;
   9.337 +    total += len;
   9.338 +    if (hint > 0 && total >= hint)
   9.339 +      break;
   9.340 +
   9.341 +    if ((line = InputStream_readline(self, args2)) == NULL)
   9.342 +      goto bad;
   9.343 +  }
   9.344 +
   9.345 +  Py_DECREF(line);
   9.346 +  Py_DECREF(args2);
   9.347 +
   9.348 +  return lines;
   9.349 +
   9.350 + bad:
   9.351 +  Py_XDECREF(args2);
   9.352 +  Py_XDECREF(lines);
   9.353 +  return NULL;
   9.354 +}
   9.355 +
   9.356 +/* __iter__() implementation. Simply returns self. */
   9.357 +static PyObject *
   9.358 +InputStream_iter(InputStream *self)
   9.359 +{
   9.360 +  Py_INCREF(self);
   9.361 +  return (PyObject *)self;
   9.362 +}
   9.363 +
   9.364 +/* next() implementation for iteration protocol support */
   9.365 +static PyObject *
   9.366 +InputStream_iternext(InputStream *self)
   9.367 +{
   9.368 +  PyObject *line, *args;
   9.369 +
   9.370 +  if ((args = PyTuple_New(0)) == NULL)
   9.371 +    return NULL;
   9.372 +
   9.373 +  line = InputStream_readline(self, args);
   9.374 +  Py_DECREF(args);
   9.375 +  if (line == NULL)
   9.376 +    return NULL;
   9.377 +
   9.378 +  if (PyString_GET_SIZE(line) == 0) {
   9.379 +    Py_DECREF(line);
   9.380 +    PyErr_Clear();
   9.381 +    return NULL;
   9.382 +  }
   9.383 +
   9.384 +  return line;
   9.385 +}
   9.386 +
   9.387 +static PyMethodDef InputStream_methods[] = {
   9.388 +  { "read", (PyCFunction)InputStream_read, METH_VARARGS,
   9.389 +    "Read from this input stream" },
   9.390 +  { "readline", (PyCFunction)InputStream_readline, METH_VARARGS,
   9.391 +    "Read a line from this input stream" },
   9.392 +  { "readlines", (PyCFunction)InputStream_readlines, METH_VARARGS,
   9.393 +    "Read lines from this input stream" },
   9.394 +  { NULL }
   9.395 +};
   9.396 +
   9.397 +PyTypeObject InputStream_Type = {
   9.398 +  PyObject_HEAD_INIT(NULL)
   9.399 +  0,                         /*ob_size*/
   9.400 +  "_wsgisup.InputStream",    /*tp_name*/
   9.401 +  sizeof(InputStream),       /*tp_basicsize*/
   9.402 +  0,                         /*tp_itemsize*/
   9.403 +  (destructor)InputStream_dealloc, /*tp_dealloc*/
   9.404 +  0,                         /*tp_print*/
   9.405 +  0,                         /*tp_getattr*/
   9.406 +  0,                         /*tp_setattr*/
   9.407 +  0,                         /*tp_compare*/
   9.408 +  0,                         /*tp_repr*/
   9.409 +  0,                         /*tp_as_number*/
   9.410 +  0,                         /*tp_as_sequence*/
   9.411 +  0,                         /*tp_as_mapping*/
   9.412 +  0,                         /*tp_hash */
   9.413 +  0,                         /*tp_call*/
   9.414 +  0,                         /*tp_str*/
   9.415 +  0,                         /*tp_getattro*/
   9.416 +  0,                         /*tp_setattro*/
   9.417 +  0,                         /*tp_as_buffer*/
   9.418 +  Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_ITER, /*tp_flags*/
   9.419 +  "wsgi.input implementation", /* tp_doc */
   9.420 +  0,		             /* tp_traverse */
   9.421 +  0,		             /* tp_clear */
   9.422 +  0,		             /* tp_richcompare */
   9.423 +  0,		             /* tp_weaklistoffset */
   9.424 +  (getiterfunc)InputStream_iter, /* tp_iter */
   9.425 +  (iternextfunc)InputStream_iternext, /* tp_iternext */
   9.426 +  InputStream_methods,       /* tp_methods */
   9.427 +  0,                         /* tp_members */
   9.428 +  0,                         /* tp_getset */
   9.429 +  0,                         /* tp_base */
   9.430 +  0,                         /* tp_dict */
   9.431 +  0,                         /* tp_descr_get */
   9.432 +  0,                         /* tp_descr_set */
   9.433 +  0,                         /* tp_dictoffset */
   9.434 +  (initproc)InputStream_init, /* tp_init */
   9.435 +  0,                         /* tp_alloc */
   9.436 +  InputStream_new,           /* tp_new */
   9.437 +};
    10.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    10.2 +++ b/wsgiwrapper.c	Sun Dec 24 17:25:00 2006 +0000
    10.3 @@ -0,0 +1,187 @@
    10.4 +/*-
    10.5 + * Copyright (c) 2006 Allan Saddi <allan@saddi.com>
    10.6 + * All rights reserved.
    10.7 + *
    10.8 + * Redistribution and use in source and binary forms, with or without
    10.9 + * modification, are permitted provided that the following conditions
   10.10 + * are met:
   10.11 + * 1. Redistributions of source code must retain the above copyright
   10.12 + *    notice, this list of conditions and the following disclaimer.
   10.13 + * 2. Redistributions in binary form must reproduce the above copyright
   10.14 + *    notice, this list of conditions and the following disclaimer in the
   10.15 + *    documentation and/or other materials provided with the distribution.
   10.16 + *
   10.17 + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
   10.18 + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
   10.19 + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
   10.20 + * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
   10.21 + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
   10.22 + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
   10.23 + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
   10.24 + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
   10.25 + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
   10.26 + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
   10.27 + * SUCH DAMAGE.
   10.28 + *
   10.29 + * $Id$
   10.30 + */
   10.31 +
   10.32 +#include <Python.h>
   10.33 +
   10.34 +#include "wsgi-int.h"
   10.35 +
   10.36 +static void
   10.37 +FileWrapper_dealloc(FileWrapper *self)
   10.38 +{
   10.39 +  PyObject *tmp;
   10.40 +
   10.41 +  tmp = (PyObject *)self->filelike;
   10.42 +  self->filelike = NULL;
   10.43 +  Py_XDECREF(tmp);
   10.44 +
   10.45 +  self->ob_type->tp_free((PyObject *)self);
   10.46 +}
   10.47 +
   10.48 +static PyObject *
   10.49 +FileWrapper_new(PyTypeObject *type, PyObject *args, PyObject *kwds)
   10.50 +{
   10.51 +  FileWrapper *self;
   10.52 +
   10.53 +  self = (FileWrapper *)type->tp_alloc(type, 0);
   10.54 +  if (self != NULL) {
   10.55 +    self->filelike = NULL;
   10.56 +  }
   10.57 +
   10.58 +  return (PyObject *)self;
   10.59 +}
   10.60 +
   10.61 +static int
   10.62 +FileWrapper_init(FileWrapper *self, PyObject *args, PyObject *kwds)
   10.63 +{
   10.64 +  PyObject *filelike;
   10.65 +  int blocksize = 4096;
   10.66 +
   10.67 +  if (!PyArg_ParseTuple(args, "O|i", &filelike, &blocksize))
   10.68 +    return -1;
   10.69 +
   10.70 +  Py_INCREF(filelike);
   10.71 +  self->filelike = filelike;
   10.72 +  self->blocksize = blocksize;
   10.73 +
   10.74 +  return 0;
   10.75 +}
   10.76 +
   10.77 +static PyObject *
   10.78 +FileWrapper_iter(FileWrapper *self)
   10.79 +{
   10.80 +  Py_INCREF(self);
   10.81 +  return (PyObject *)self;
   10.82 +}
   10.83 +
   10.84 +static PyObject *
   10.85 +FileWrapper_iternext(FileWrapper *self)
   10.86 +{
   10.87 +  PyObject *pRead, *args, *data;
   10.88 +  int len;
   10.89 +
   10.90 +  if ((pRead = PyObject_GetAttrString(self->filelike, "read")) == NULL)
   10.91 +    return NULL;
   10.92 +
   10.93 +  if ((args = Py_BuildValue("(i)", self->blocksize)) == NULL) {
   10.94 +    Py_DECREF(pRead);
   10.95 +    return NULL;
   10.96 +  }
   10.97 +
   10.98 +  data = PyObject_CallObject(pRead, args);
   10.99 +  Py_DECREF(args);
  10.100 +  Py_DECREF(pRead);
  10.101 +  if (data == NULL)
  10.102 +    return NULL;
  10.103 +
  10.104 +  len = PyString_Size(data);
  10.105 +  if (PyErr_Occurred()) {
  10.106 +    Py_DECREF(data);
  10.107 +    return NULL;
  10.108 +  }
  10.109 +
  10.110 +  if (len == 0) {
  10.111 +    Py_DECREF(data);
  10.112 +    PyErr_Clear();
  10.113 +    return NULL;
  10.114 +  }
  10.115 +
  10.116 +  return data;
  10.117 +}
  10.118 +
  10.119 +static PyObject *
  10.120 +FileWrapper_close(FileWrapper *self, PyObject *args)
  10.121 +{
  10.122 +  PyObject *pClose, *args2, *result;
  10.123 +
  10.124 +  if (PyObject_HasAttrString(self->filelike, "close")) {
  10.125 +    if ((pClose = PyObject_GetAttrString(self->filelike, "close")) == NULL)
  10.126 +      return NULL;
  10.127 +
  10.128 +    if ((args2 = PyTuple_New(0)) == NULL) {
  10.129 +      Py_DECREF(pClose);
  10.130 +      return NULL;
  10.131 +    }
  10.132 +
  10.133 +    result = PyObject_CallObject(pClose, args2);
  10.134 +    Py_DECREF(args2);
  10.135 +    Py_DECREF(pClose);
  10.136 +    if (result == NULL)
  10.137 +      return NULL;
  10.138 +  }
  10.139 +
  10.140 +  Py_INCREF(Py_None);
  10.141 +  return Py_None;
  10.142 +}
  10.143 +
  10.144 +static PyMethodDef FileWrapper_methods[] = {
  10.145 +  { "close", (PyCFunction)FileWrapper_close, METH_VARARGS,
  10.146 +    "Calls the file-like object's close method" },
  10.147 +  { NULL }
  10.148 +};
  10.149 +
  10.150 +PyTypeObject FileWrapper_Type = {
  10.151 +  PyObject_HEAD_INIT(NULL)
  10.152 +  0,                         /*ob_size*/
  10.153 +  "_wsgisup.FileWrapper",    /*tp_name*/
  10.154 +  sizeof(FileWrapper),       /*tp_basicsize*/
  10.155 +  0,                         /*tp_itemsize*/
  10.156 +  (destructor)FileWrapper_dealloc, /*tp_dealloc*/
  10.157 +  0,                         /*tp_print*/
  10.158 +  0,                         /*tp_getattr*/
  10.159 +  0,                         /*tp_setattr*/
  10.160 +  0,                         /*tp_compare*/
  10.161 +  0,                         /*tp_repr*/
  10.162 +  0,                         /*tp_as_number*/
  10.163 +  0,                         /*tp_as_sequence*/
  10.164 +  0,                         /*tp_as_mapping*/
  10.165 +  0,                         /*tp_hash */
  10.166 +  0,                         /*tp_call*/
  10.167 +  0,                         /*tp_str*/
  10.168 +  0,                         /*tp_getattro*/
  10.169 +  0,                         /*tp_setattro*/
  10.170 +  0,                         /*tp_as_buffer*/
  10.171 +  Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_ITER, /*tp_flags*/
  10.172 +  "wsgi.file_wrapper implementation", /* tp_doc */
  10.173 +  0,		             /* tp_traverse */
  10.174 +  0,		             /* tp_clear */
  10.175 +  0,		             /* tp_richcompare */
  10.176 +  0,		             /* tp_weaklistoffset */
  10.177 +  (getiterfunc)FileWrapper_iter, /* tp_iter */
  10.178 +  (iternextfunc)FileWrapper_iternext, /* tp_iternext */
  10.179 +  FileWrapper_methods,       /* tp_methods */
  10.180 +  0,                         /* tp_members */
  10.181 +  0,                         /* tp_getset */
  10.182 +  0,                         /* tp_base */
  10.183 +  0,                         /* tp_dict */
  10.184 +  0,                         /* tp_descr_get */
  10.185 +  0,                         /* tp_descr_set */
  10.186 +  0,                         /* tp_dictoffset */
  10.187 +  (initproc)FileWrapper_init, /* tp_init */
  10.188 +  0,                         /* tp_alloc */
  10.189 +  FileWrapper_new,           /* tp_new */
  10.190 +};