def proxy(request): """Pass an HTTP request on to another server.""" # TODO: don't hardcode http uri = "http://" + HOST + request.META['PATH_INFO'] if request.META['QUERY_STRING']: uri += '?' + request.META['QUERY_STRING'] headers = {} for name, val in six.iteritems(request.environ): if name.startswith('HTTP_'): name = header_name(name) headers[name] = val # TODO: try/except http = Http() http.follow_redirects = False logger.debug("GET for: %s" % uri) info, content = http.request(uri, 'GET', headers=headers) response = HttpResponse(content, status=info.pop('status')) for name, val in info.items(): if not is_hop_by_hop(name): response[name] = val logger.info("PROXY to: %s" % uri) return response
def proxy(request, path, plname=None, headers=None): """ handle revproxy """ headers = headers or {} for key, value in request.META.iteritems(): if key.startswith('HTTP_'): key = header_name(key) elif key in ('CONTENT_TYPE', 'CONTENT_LENGTH'): key = key.replace('_', '-') if not value: continue else: continue # rewrite location if key.lower() == "host": continue if is_hop_by_hop(key): continue else: headers[key] = value headers["X-Forwarded-For"] = request.META.get("REMOTE_ADDR") headers["X-Forwarded-Host"] = request.get_host() headers["PATH-INFO"] = request.get_full_path() if hasattr(request, 'user') and request.user.is_authenticated(): headers.update({ 'X-AIMPL-User': request.user.username, 'X-AIMPL-Priv': is_priv(request, plname), 'X-AIMPL-User-PL': ','.join([p.name for p in privileges(request)]), 'X-AIMPL-Groups': ','.join(str(g) \ for g in request.user.groups.all() \ if has_group(request, str(g), plname) \ or str(g) == "Chief Editor"), 'X-AIMPL-Token': hmac.new(settings.SECRET_KEY, request.user.username, hashlib.sha1).hexdigest() }) uri = "http://%s:%s%s" % (settings.WEB_PROXY_DOMAIN, settings.WEB_PROXY_PORT, path) # Django's internal mechanism doesn't pick up # PUT request, so we trick it a little here. if request.method.upper() == "PUT": coerce_put_post(request) try: resp = connection.request(uri, method=request.method, body=request.raw_post_data, headers=headers) body = resp.body_file except restkit.RequestFailed, e: msg = getattr(e, 'msg', '') if e.status_int >= 100: resp = e.response body = msg else: return http.HttpResponseBadRequest(msg)
def process_request(self, request): """This is called every time a new request arrives in Django, but *before* the url resolution is made. If this returns an HttpResponse -> nothing else is made by django and the HttpResponse is sent to client If this returns None -> the request is passed along to the url resolver for "normal" handling by Django """ if request.META['QUERY_STRING']: querystring = request.META['PATH_INFO'] + '?' + request.META[ 'QUERY_STRING'] else: querystring = request.META['PATH_INFO'] server_protocol = request.META['SERVER_PROTOCOL'] outgoing_headers = {} data = [] data.append(' '.join([request.method, querystring, server_protocol])) # for a, b in request.environ.iteritems(): if a.startswith('HTTP_'): a = header_name(a) outgoing_headers[a] = b data.append('%s %s' % (a, b)) data = '\r\n'.join(data) + '\r\n\r\n' # Instead of using sockets I now use urllib2, so that DNS "beautifying" is properly done. requ = urllib2.Request(querystring, None, outgoing_headers) remote = urllib2.urlopen(requ) status_code = remote.getcode() headers = remote.headers # This is a dict content = remote.read() # We should have all we need now. # I cleaned up the part with the sockets - it's much cleaner now. response = HttpResponse(content, status=int(status_code)) for header in headers.keys(): # We need to check if the header we forward is allowed (if it's not a hop by hop header) if not basehttp.is_hop_by_hop(header): response[header] = headers[header] return response
def process_request(self, request): """This is called every time a new request arrives in Django, but *before* the url resolution is made. If this returns an HttpResponse -> nothing else is made by django and the HttpResponse is sent to client If this returns None -> the request is passed along to the url resolver for "normal" handling by Django """ if request.META['QUERY_STRING']: querystring = request.META['PATH_INFO'] + '?' + request.META['QUERY_STRING'] else: querystring = request.META['PATH_INFO'] server_protocol = request.META['SERVER_PROTOCOL'] outgoing_headers = {} data = [] data.append(' '.join([request.method, querystring, server_protocol]))# for a, b in request.environ.iteritems(): if a.startswith('HTTP_'): a = header_name(a) outgoing_headers[a] = b data.append('%s %s' % (a, b)) data = '\r\n'.join(data) + '\r\n\r\n' # Instead of using sockets I now use urllib2, so that DNS "beautifying" is properly done. requ = urllib2.Request(querystring, None, outgoing_headers) remote = urllib2.urlopen(requ) status_code = remote.getcode() headers = remote.headers # This is a dict content = remote.read() # We should have all we need now. # I cleaned up the part with the sockets - it's much cleaner now. response = HttpResponse(content, status=int(status_code)) for header in headers.keys(): # We need to check if the header we forward is allowed (if it's not a hop by hop header) if not basehttp.is_hop_by_hop(header): response[header] = headers[header] return response
def proxy(request): # TODO: don't hardcode http uri = "http://" + HOST + request.META['PATH_INFO'] if request.META['QUERY_STRING']: uri += '?' + request.META['QUERY_STRING'] headers = {} for name, val in request.environ.iteritems(): if name.startswith('HTTP_'): name = header_name(name) headers[name] = val # TODO: try/except http = Http() http.follow_redirects = False info, content = http.request(uri, 'GET', headers=headers) response = HttpResponse(content, status=info.pop('status')) for name, val in info.items(): if not is_hop_by_hop(name): response[name] = val return response
def forward_header(k): return k.upper() not in ['HOST', 'CONTENT_LENGTH'] and \ not is_hop_by_hop(k) and not '.' in k
def proxy_request(request, **kwargs): """ generic view to proxy a request. Args: destination: string, the proxied url prefix: string, the prrefix behind we proxy the path headers: dict, custom HTTP headers no_redirect: boolean, False by default, do not redirect to "/" if no path is given decompress: boolean, False by default. If true the proxy will decompress the source body if it's gzip encoded. filters: list of revproxy.Filter instance Return: HttpResponse instance """ # proxy sid try: cookie_name = settings.REVPROXY_COOKIE except AttributeError: cookie_name = kwargs.get("cookie", "PROXY_SID") sid = request.COOKIES.get(cookie_name) # create a proxy session id only if it's needed so someone using # a cookie based authentification can just reuse this session id. # It can also be the session id from the session middleware. if not sid: sid = uuid.uuid4().hex kwargs['proxy_sid'] = sid # install request filters filters_classes = kwargs.get('filters') if not filters_classes: filters = None else: filters = [] for fclass in filters_classes: # add filter instance fobj = fclass(request, **kwargs) filters.append(fobj) # eventually rewrite request and kwargs if hasattr(fobj, 'setup'): ret = fobj.setup() if ret is not None: try: request, extra_kwargs = ret except ValueError: extra_kwargs = ret if extra_kwargs is not None: kwargs.update(extra_kwargs) destination = kwargs.get('destination') prefix = kwargs.get('prefix') headers = kwargs.get('headers') no_redirect = kwargs.get('no_redirect', False) decompress = kwargs.get("decompress", False) path = kwargs.get("path") proxy_sid = kwargs.get('proxy_sid') if path is None: path = request.path if prefix is not None and prefix: path = path.split(prefix, 1)[1] else: if not path and not request.path.endswith("/"): if not no_redirect: qs = request.META["QUERY_STRING"] redirect_url = "%s/" % request.path if qs: redirect_url = "%s?%s" % (redirect_url, qs) return HttpResponsePermanentRedirect(redirect_url) if path: prefix = request.path.rsplit(path, 1)[0] if not path.startswith("/"): path = "/%s" % path base_url = absolute_uri(request, destination) proxied_url = "" if not path: proxied_url = "%s/" % base_url else: proxied_url = "%s%s" % (base_url, path) qs = request.META.get("QUERY_STRING") if qs is not None and qs: proxied_url = "%s?%s" % (proxied_url, qs) # fix headers@ headers = headers or {} for key, value in request.META.iteritems(): if key.startswith('HTTP_'): key = header_name(key) elif key in ('CONTENT_TYPE', 'CONTENT_LENGTH'): key = key.replace('_', '-') if not value: continue else: continue # rewrite location if key.lower() != "host" and not is_hop_by_hop(key): headers[key] = value # we forward for headers["X-Forwarded-For"] = request.get_host() # django doesn't understand PUT sadly method = request.method.upper() if method == "PUT": coerce_put_post(request) # do the request try: resp = restkit.request(proxied_url, method=method, body=request.raw_post_data, headers=headers, follow_redirect=True, decompress=decompress, filters=filters) except restkit.RequestFailed, e: msg = getattr(e, 'msg', '') if e.status_int >= 100: resp = e.response body = msg else: return http.HttpResponseBadRequest(msg)
except restkit.RequestFailed, e: msg = getattr(e, 'msg', '') if e.status_int >= 100: resp = e.response body = msg else: return http.HttpResponseBadRequest(msg) body = resp.tee() response = HttpResponse(body, status=resp.status_int) # fix response headers for k, v in resp.headers.items(): kl = k.lower() if is_hop_by_hop(kl): continue if kl == "location": response[k] = rewrite_location(request, prefix, v) elif kl == "content-encoding": if not decompress: response[k] = v else: response[k] = v # save the session response.set_cookie(cookie_name, sid, max_age=None, expires=None, domain=settings.SESSION_COOKIE_DOMAIN,
def proxy_request(request, destination=None, prefix=None, headers=None, no_redirect=False, decompress=False, **kwargs): """ generic view to proxy a request. Args: destination: string, the proxied url prefix: string, the prrefix behind we proxy the path headers: dict, custom HTTP headers no_redirect: boolean, False by default, do not redirect to "/" if no path is given decompress: boolean, False by default. If true the proxy will decompress the source body if it's gzip encoded. Return: HttpResponse instance """ path = kwargs.get("path") if path is None: path = request.path if prefix is not None and prefix: path = path.split(prefix, 1)[1] else: if not path and not request.path.endswith("/"): if not no_redirect: qs = request.META["QUERY_STRING"] redirect_url = "%s/" % request.path if qs: redirect_url = "%s?%s" % (redirect_url, qs) return HttpResponsePermanentRedirect(redirect_url) if path: prefix = request.path.rsplit(path, 1)[0] if not path.startswith("/"): path = "/%s" % path base_url = absolute_uri(request, destination) proxied_url = "" if not path: proxied_url = "%s/" % base_url else: proxied_url = "%s%s" % (base_url, path) qs = request.META.get("QUERY_STRING") if qs is not None and qs: proxied_url = "%s?%s" % (proxied_url, qs) # fix headers headers = headers or {} for key, value in request.META.iteritems(): if key.startswith('HTTP_'): key = header_name(key) elif key in ('CONTENT_TYPE', 'CONTENT_LENGTH'): key = key.replace('_', '-') if not value: continue else: continue # rewrite location if key.lower() != "host" and not is_hop_by_hop(key): headers[key] = value # we forward for headers["X-Forwarded-For"] = request.get_host() # used in request session store. headers["X-Restkit-Reqid"] = uuid.uuid4().hex # django doesn't understand PUT sadly method = request.method.upper() if method == "PUT": coerce_put_post(request) # do the request try: resp = restkit.request(proxied_url, method=method, body=request.raw_post_data, headers=headers, follow_redirect=True, decompress=decompress, conn_manager=get_conn_manager()) except restkit.RequestFailed, e: msg = getattr(e, 'msg', '') if e.status_int >= 100: resp = e.response body = msg else: return http.HttpResponseBadRequest(msg)
except restkit.RequestFailed, e: msg = getattr(e, 'msg', '') if e.status_int >= 100: resp = e.response body = msg else: return http.HttpResponseBadRequest(msg) with resp.body_stream() as body: response = HttpResponse(BodyWrapper(body), status=resp.status_int) # fix response headers for k, v in resp.headers.items(): kl = k.lower() if is_hop_by_hop(kl): continue if kl == "location": response[k] = rewrite_location(request, prefix, v) print v print response[k] else: response[k] = v return response class ProxyTarget(object): def __init__(self, prefix, url, kwargs=None): if not prefix or not url: raise ValueError("REVPROXY_SETTINGS is invalid")
def forward_header(k): return k.upper() not in ["HOST", "CONTENT_LENGTH", "CONTENT_TYPE"] and not is_hop_by_hop(k) and not "." in k
try: resp = connection.request(uri, method=request.method, body=request.raw_post_data, headers=headers) body = resp.body_file except restkit.RequestFailed, e: msg = getattr(e, 'msg', '') if e.status_int >= 100: resp = e.response body = msg else: return http.HttpResponseBadRequest(msg) response = HttpResponse(body, status=resp.status_int) for k, v in resp.headers.items(): if is_hop_by_hop(k): continue else: response[k] = v return response def header_name(name): """Convert header name like HTTP_XXXX_XXX to Xxxx-Xxx:""" words = name[5:].split('_') for i in range(len(words)): words[i] = words[i][0].upper() + words[i][1:].lower() result = '-'.join(words) return result
def send_header(self, header, value): if not is_hop_by_hop(header): self._response[header] = value