Package couchdbkit :: Package wsgi :: Module handler
[hide private]
[frames] | no frames]

Source Code for Module couchdbkit.wsgi.handler

  1  # -*- coding: utf-8 - 
  2  # 
  3  # This file is part of couchdbkit released under the MIT license.  
  4  # See the NOTICE for more information. 
  5   
  6  import re 
  7  import sys 
  8  import StringIO 
  9  import traceback 
 10  from urllib import unquote 
 11   
 12  from restkit.util import url_encode 
 13   
 14  from .. import __version__ 
 15  from ..external import External 
 16   
17 -def _normalize_name(name):
18 return "-".join([w.lower().capitalize() for w in name.split("-")])
19
20 -class WSGIRequest(object):
21 22 SERVER_VERSION = "couchdbkit/%s" % __version__ 23
24 - def __init__(self, line):
25 self.line = line 26 self.response_status = 200 27 self.response_headers = {} 28 self.start_response_called = False
29
30 - def read(self):
31 headers = self.parse_headers() 32 33 length = headers.get("CONTENT_LENGTH") 34 if self.line["body"] and self.line["body"] != "undefined": 35 length = len(self.line["body"]) 36 body = StringIO.StringIO(self.line["body"]) 37 38 else: 39 body = StringIO.StringIO() 40 41 # path 42 script_name, path_info = self.line['path'][:2], self.line['path'][2:] 43 if path_info: 44 path_info = "/%s" % "/".join(path_info) 45 else: 46 path_info = "" 47 script_name = "/%s" % "/".join(script_name) 48 49 # build query string 50 args = [] 51 query_string = None 52 for k, v in self.line["query"].items(): 53 if v is None: 54 continue 55 else: 56 args.append((k,v)) 57 if args: query_string = url_encode(dict(args)) 58 59 # raw path could be useful 60 path = "%s%s" % (path_info, query_string) 61 62 # get server address 63 if ":" in self.line["headers"]["Host"]: 64 server_address = self.line["headers"]["Host"].split(":") 65 else: 66 server_address = (self.line["headers"]["Host"], 80) 67 68 environ = { 69 "wsgi.url_scheme": 'http', 70 "wsgi.input": body, 71 "wsgi.errors": StringIO.StringIO(), 72 "wsgi.version": (1, 0), 73 "wsgi.multithread": False, 74 "wsgi.multiprocess": True, 75 "wsgi.run_once": False, 76 "SCRIPT_NAME": script_name, 77 "SERVER_SOFTWARE": self.SERVER_VERSION, 78 "COUCHDB_INFO": self.line["info"], 79 "COUCHDB_REQUEST": self.line, 80 "REQUEST_METHOD": self.line["verb"].upper(), 81 "PATH_INFO": unquote(path_info), 82 "QUERY_STRING": query_string, 83 "RAW_URI": path, 84 "CONTENT_TYPE": headers.get('CONTENT-TYPE', ''), 85 "CONTENT_LENGTH": length, 86 "REMOTE_ADDR": self.line['peer'], 87 "REMOTE_PORT": 0, 88 "SERVER_NAME": server_address[0], 89 "SERVER_PORT": int(server_address[1]), 90 "SERVER_PROTOCOL": "HTTP/1.1" 91 } 92 93 for key, value in headers.items(): 94 key = 'HTTP_' + key.replace('-', '_') 95 if key not in ('HTTP_CONTENT_TYPE', 'HTTP_CONTENT_LENGTH'): 96 environ[key] = value 97 98 return environ
99
100 - def start_response(self, status, response_headers):
101 self.response_status = int(status.split(" ")[0]) 102 for name, value in response_headers: 103 name = _normalize_name(name) 104 self.response_headers[name] = value.strip() 105 self.start_response_called = True
106
107 - def parse_headers(self):
108 headers = {} 109 for name, value in self.line.get("headers", {}).items(): 110 name = name.strip().upper().encode("utf-8") 111 headers[name] = value.strip().encode("utf-8") 112 return headers
113
114 -class WSGIHandler(External):
115
116 - def __init__(self, application, stdin=sys.stdin, 117 stdout=sys.stdout):
118 External.__init__(self, stdin=stdin, stdout=stdout) 119 self.app = application
120
121 - def handle_line(self, line):
122 try: 123 req = WSGIRequest(line) 124 response = self.app(req.read(), req.start_response) 125 except: 126 self.send_response(500, "".join(traceback.format_exc()), 127 {"Content-Type": "text/plain"}) 128 return 129 130 content = "".join(response).encode("utf-8") 131 self.send_response(req.response_status, content, req.response_headers)
132