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