wsgi/__init__.py
changeset 0 b97547f5f1fa
child 1802 d628defebc17
equal deleted inserted replaced
-1:000000000000 0:b97547f5f1fa
       
     1 """This package contains all WSGI specific code for cubicweb
       
     2 
       
     3 NOTE: this package borrows a lot of code to Django
       
     4       (http://www.djangoproject.com) and to the wsgiref module
       
     5       of the python2.5's stdlib.
       
     6 
       
     7 WSGI corresponding PEP: http://www.python.org/dev/peps/pep-0333/
       
     8 
       
     9 :organization: Logilab
       
    10 :copyright: 2008 LOGILAB S.A. (Paris, FRANCE), all rights reserved.
       
    11 :contact: http://www.logilab.fr/ -- mailto:contact@logilab.fr
       
    12 """
       
    13 __docformat__ = "restructuredtext en"
       
    14 
       
    15 from email import message, message_from_string
       
    16 from Cookie import SimpleCookie
       
    17 from StringIO import StringIO
       
    18 from cgi import parse_header, parse_qsl
       
    19 from pprint import pformat as _pformat
       
    20 
       
    21 
       
    22 def pformat(obj):
       
    23     """pretty prints `obj` if possible"""
       
    24     try:
       
    25         return _pformat(obj)
       
    26     except:
       
    27         return u'<could not parse>'
       
    28     
       
    29 def qs2dict(qs):
       
    30     """transforms a query string into a regular python dict"""
       
    31     result = {}
       
    32     for key, value in parse_qsl(qs, True):
       
    33         result.setdefault(key, []).append(value)
       
    34     return result
       
    35 
       
    36 def normalize_header(header):
       
    37     """returns a normalized header name
       
    38     
       
    39     >>> normalize_header('User_Agent')
       
    40     'User-agent'
       
    41     """
       
    42     return header.replace('_', '-').capitalize()
       
    43 
       
    44 def safe_copyfileobj(fsrc, fdst, length=16*1024, size=0):
       
    45     """
       
    46     THIS COMES FROM DJANGO
       
    47     A version of shutil.copyfileobj that will not read more than 'size' bytes.
       
    48     This makes it safe from clients sending more than CONTENT_LENGTH bytes of
       
    49     data in the body.
       
    50     """
       
    51     if not size:
       
    52         return
       
    53     while size > 0:
       
    54         buf = fsrc.read(min(length, size))
       
    55         if not buf:
       
    56             break
       
    57         fdst.write(buf)
       
    58         size -= len(buf)
       
    59 
       
    60 def parse_file_upload(header_dict, post_data):
       
    61     """This is adapted FROM DJANGO"""
       
    62     raw_message = '\r\n'.join('%s:%s' % pair for pair in header_dict.iteritems())
       
    63     raw_message += '\r\n\r\n' + post_data
       
    64     msg = message_from_string(raw_message)
       
    65     post, files = {}, {}
       
    66     for submessage in msg.get_payload():
       
    67         name_dict = parse_header(submessage['Content-Disposition'])[1]
       
    68         key = name_dict['name']
       
    69         # name_dict is something like {'name': 'file', 'filename': 'test.txt'} for file uploads
       
    70         # or {'name': 'blah'} for POST fields
       
    71         # We assume all uploaded files have a 'filename' set.
       
    72         if 'filename' in name_dict:
       
    73             assert type([]) != type(submessage.get_payload()), "Nested MIME messages are not supported"
       
    74             if not name_dict['filename'].strip():
       
    75                 continue
       
    76             # IE submits the full path, so trim everything but the basename.
       
    77             # (We can't use os.path.basename because that uses the server's
       
    78             # directory separator, which may not be the same as the
       
    79             # client's one.)
       
    80             filename = name_dict['filename'][name_dict['filename'].rfind("\\")+1:]
       
    81             mimetype = 'Content-Type' in submessage and submessage['Content-Type'] or None
       
    82             content = StringIO(submessage.get_payload())
       
    83             files[key] = [filename, mimetype, content]
       
    84         else:
       
    85             post.setdefault(key, []).append(submessage.get_payload())
       
    86     return post, files
       
    87