Package restkit :: Package ext :: Module wsgi_proxy
[hide private]
[frames] | no frames]

Source Code for Module restkit.ext.wsgi_proxy

  1  # -*- coding: utf-8 - 
  2  # 
  3  # This file is part of restkit released under the MIT license.  
  4  # See the NOTICE for more information. 
  5   
  6  import urlparse 
  7  from restkit import ConnectionPool, request 
  8  from restkit.sock import MAX_BODY 
  9   
 10  ALLOWED_METHODS = ['GET', 'HEAD'] 
 11   
 12  BLOCK_SIZE = 4096 * 16 
 13   
14 -class ResponseIter(object):
15
16 - def __init__(self, response):
17 response.CHUNK_SIZE = BLOCK_SIZE 18 self.body = response.body_file
19
20 - def next(self):
21 data = self.body.read(BLOCK_SIZE) 22 if not data: 23 raise StopIteration 24 return data
25
26 - def __iter__(self):
27 return self
28
29 -class Proxy(object):
30 """A proxy wich redirect the request to SERVER_NAME:SERVER_PORT 31 and send HTTP_HOST header""" 32
33 - def __init__(self, pool=None, allowed_methods=ALLOWED_METHODS, 34 strip_script_name=True, **kwargs):
35 self.pool = pool or ConnectionPool(**kwargs) 36 self.allowed_methods = allowed_methods 37 self.strip_script_name = strip_script_name
38
39 - def extract_uri(self, environ):
40 port = None 41 scheme = environ['wsgi.url_scheme'] 42 if 'SERVER_NAME' in environ: 43 host = environ['SERVER_NAME'] 44 else: 45 host = environ['HTTP_HOST'] 46 if ':' in host: 47 host, port = host.split(':') 48 49 if not port: 50 if 'SERVER_PORT' in environ: 51 port = environ['SERVER_PORT'] 52 else: 53 port = scheme == 'https' and '443' or '80' 54 55 uri = '%s://%s:%s' % (scheme, host, port) 56 return uri
57
58 - def __call__(self, environ, start_response):
59 method = environ['REQUEST_METHOD'] 60 if method not in self.allowed_methods: 61 start_response('403 Forbidden', ()) 62 return [''] 63 64 if method in ('POST', 'PUT'): 65 if 'CONTENT_LENGTH' in environ: 66 content_length = int(environ['CONTENT_LENGTH']) 67 body = environ['wsgi.input'].read(content_length) 68 else: 69 body = environ['wsgi.input'].read() 70 else: 71 body=None 72 73 if self.strip_script_name: 74 path_info = '' 75 else: 76 path_info = environ['SCRIPT_NAME'] 77 path_info += environ['PATH_INFO'] 78 79 query_string = environ['QUERY_STRING'] 80 if query_string: 81 path_info += '?' + query_string 82 83 uri = self.extract_uri(environ)+path_info 84 85 new_headers = {} 86 for k, v in environ.items(): 87 if k.startswith('HTTP_'): 88 k = k[5:].replace('_', '-').title() 89 new_headers[k] = v 90 91 for k, v in (('CONTENT_TYPE', None), ('CONTENT_LENGTH', '0')): 92 v = environ.get(k, None) 93 if v is not None: 94 new_headers[k.replace('_', '-').title()] = v 95 96 response = request(uri, method, 97 body=body, headers=new_headers, 98 pool_instance=self.pool) 99 100 start_response(response.status, response.headerslist) 101 102 if 'content-length' in response and \ 103 int(response['content-length']) <= MAX_BODY: 104 return [response.body] 105 106 return ResponseIter(response)
107
108 -class TransparentProxy(Proxy):
109 """A proxy based on HTTP_HOST environ variable""" 110
111 - def extract_uri(self, environ):
112 port = None 113 scheme = environ['wsgi.url_scheme'] 114 host = environ['HTTP_HOST'] 115 if ':' in host: 116 host, port = host.split(':') 117 118 if not port: 119 port = scheme == 'https' and '443' or '80' 120 121 uri = '%s://%s:%s' % (scheme, host, port) 122 return uri
123 124
125 -class HostProxy(Proxy):
126 """A proxy to redirect all request to a specific uri""" 127
128 - def __init__(self, uri, **kwargs):
129 super(HostProxy, self).__init__(**kwargs) 130 self.uri = uri.rstrip('/') 131 self.scheme, self.net_loc = urlparse.urlparse(self.uri)[0:2]
132
133 - def extract_uri(self, environ):
134 environ['HTTP_HOST'] = self.net_loc 135 return self.uri
136 137
138 -class CouchdbProxy(HostProxy):
139 """A proxy to redirect all request to CouchDB database"""
140 - def __init__(self, db_name='', uri='http://127.0.0.1:5984', 141 allowed_methods=['GET'], **kwargs):
142 uri = uri.rstrip('/') 143 if db_name: 144 uri += '/' + db_name.strip('/') 145 super(CouchdbProxy, self).__init__(uri, allowed_methods=allowed_methods, 146 **kwargs)
147
148 -def get_config(local_config):
149 """parse paste config""" 150 config = {} 151 allowed_methods = local_config.get('allowed_methods', None) 152 if allowed_methods: 153 config['allowed_methods'] = [m.upper() for m in allowed_methods.split()] 154 strip_script_name = local_config.get('strip_script_name', 'true') 155 if strip_script_name.lower() in ('false', '0'): 156 config['strip_script_name'] = False 157 config['max_connections'] = int(local_config.get('max_connections', '5')) 158 return config
159
160 -def make_proxy(global_config, **local_config):
161 """TransparentProxy entry_point""" 162 config = get_config(local_config) 163 print 'Running TransparentProxy with %s' % config 164 return TransparentProxy(**config)
165
166 -def make_host_proxy(global_config, uri=None, **local_config):
167 """HostProxy entry_point""" 168 uri = uri.rstrip('/') 169 config = get_config(local_config) 170 print 'Running HostProxy on %s with %s' % (uri, config) 171 return HostProxy(uri, **config)
172
173 -def make_couchdb_proxy(global_config, db_name='', uri='http://127.0.0.1:5984', 174 **local_config):
175 """CouchdbProxy entry_point""" 176 uri = uri.rstrip('/') 177 config = get_config(local_config) 178 print 'Running CouchdbProxy on %s/%s with %s' % (uri, db_name, config) 179 return CouchdbProxy(db_name=db_name, uri=uri, **config)
180