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

Source Code for Module restkit.contrib.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   
  8  try: 
  9      from cStringIO import StringIO 
 10  except ImportError: 
 11      from StringIO import StringIO 
 12   
 13  from restkit.client import Client  
 14  from restkit.globals import _manager  
 15  from restkit.sock import MAX_BODY 
 16  from restkit.util import rewrite_location 
 17   
 18  ALLOWED_METHODS = ['GET', 'HEAD', 'POST', 'PUT', 'DELETE'] 
 19   
 20  BLOCK_SIZE = 4096 * 16 
 21   
 22  WEBOB_ERROR = ("Content-Length is set to -1. This usually mean that WebOb has " 
 23          "already parsed the content body. You should set the Content-Length " 
 24          "header to the correct value before forwarding your request to the " 
 25          "proxy: ``req.content_length = str(len(req.body));`` " 
 26          "req.get_response(proxy)") 
 27   
28 -class Proxy(object):
29 """A proxy wich redirect the request to SERVER_NAME:SERVER_PORT 30 and send HTTP_HOST header""" 31
32 - def __init__(self, manager=None, allowed_methods=ALLOWED_METHODS, 33 strip_script_name=True, **kwargs):
34 self.allowed_methods = allowed_methods 35 self.strip_script_name = strip_script_name 36 self.client = Client(manager=manager)
37
38 - def extract_uri(self, environ):
39 port = None 40 scheme = environ['wsgi.url_scheme'] 41 if 'SERVER_NAME' in environ: 42 host = environ['SERVER_NAME'] 43 else: 44 host = environ['HTTP_HOST'] 45 if ':' in host: 46 host, port = host.split(':') 47 48 if not port: 49 if 'SERVER_PORT' in environ: 50 port = environ['SERVER_PORT'] 51 else: 52 port = scheme == 'https' and '443' or '80' 53 54 uri = '%s://%s:%s' % (scheme, host, port) 55 return uri
56
57 - def __call__(self, environ, start_response):
58 method = environ['REQUEST_METHOD'] 59 if method not in self.allowed_methods: 60 start_response('403 Forbidden', ()) 61 return [''] 62 63 if self.strip_script_name: 64 path_info = '' 65 else: 66 path_info = environ['SCRIPT_NAME'] 67 path_info += environ['PATH_INFO'] 68 69 query_string = environ['QUERY_STRING'] 70 if query_string: 71 path_info += '?' + query_string 72 73 host_uri = self.extract_uri(environ) 74 uri = host_uri + path_info 75 76 new_headers = {} 77 for k, v in environ.items(): 78 if k.startswith('HTTP_'): 79 k = k[5:].replace('_', '-').title() 80 new_headers[k] = v 81 82 for k, v in (('CONTENT_TYPE', None), ('CONTENT_LENGTH', '0')): 83 v = environ.get(k, None) 84 if v is not None: 85 new_headers[k.replace('_', '-').title()] = v 86 87 if new_headers.get('Content-Length', '0') == '-1': 88 raise ValueError(WEBOB_ERROR) 89 90 response = self.client.request(uri, method, body=environ['wsgi.input'], 91 headers=new_headers) 92 93 if 'location' in response: 94 if self.strip_script_name: 95 prefix_path = environ['SCRIPT_NAME'] 96 97 new_location = rewrite_location(host_uri, response.location, 98 prefix_path=prefix_path) 99 100 headers = [] 101 for k, v in response.headerslist: 102 if k.lower() == 'location': 103 v = new_location 104 headers.append((k, v)) 105 else: 106 headers = response.headerslist 107 108 start_response(response.status, headers) 109 110 if method == "HEAD": 111 return StringIO() 112 113 return response.tee()
114
115 -class TransparentProxy(Proxy):
116 """A proxy based on HTTP_HOST environ variable""" 117
118 - def extract_uri(self, environ):
119 port = None 120 scheme = environ['wsgi.url_scheme'] 121 host = environ['HTTP_HOST'] 122 if ':' in host: 123 host, port = host.split(':') 124 125 if not port: 126 port = scheme == 'https' and '443' or '80' 127 128 uri = '%s://%s:%s' % (scheme, host, port) 129 return uri
130 131
132 -class HostProxy(Proxy):
133 """A proxy to redirect all request to a specific uri""" 134
135 - def __init__(self, uri, **kwargs):
136 super(HostProxy, self).__init__(**kwargs) 137 self.uri = uri.rstrip('/') 138 self.scheme, self.net_loc = urlparse.urlparse(self.uri)[0:2]
139
140 - def extract_uri(self, environ):
141 environ['HTTP_HOST'] = self.net_loc 142 return self.uri
143
144 -def get_config(local_config):
145 """parse paste config""" 146 config = {} 147 allowed_methods = local_config.get('allowed_methods', None) 148 if allowed_methods: 149 config['allowed_methods'] = [m.upper() for m in allowed_methods.split()] 150 strip_script_name = local_config.get('strip_script_name', 'true') 151 if strip_script_name.lower() in ('false', '0'): 152 config['strip_script_name'] = False 153 config['max_connections'] = int(local_config.get('max_connections', '5')) 154 return config
155
156 -def make_proxy(global_config, **local_config):
157 """TransparentProxy entry_point""" 158 config = get_config(local_config) 159 print 'Running TransparentProxy with %s' % config 160 return TransparentProxy(**config)
161
162 -def make_host_proxy(global_config, uri=None, **local_config):
163 """HostProxy entry_point""" 164 uri = uri.rstrip('/') 165 config = get_config(local_config) 166 print 'Running HostProxy on %s with %s' % (uri, config) 167 return HostProxy(uri, **config)
168