Last active
February 13, 2018 14:34
-
-
Save manuelep/81ffe8ce57de4dc9b2d80a99c08992cc to your computer and use it in GitHub Desktop.
web2py proxy
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
# -*- coding: utf-8 -*- | |
# coding: utf8 | |
import requests | |
#from requests.auth import HTTPBasicAuth | |
from storage import Storage | |
@auth.requires_login() | |
def index(): | |
# 1. It seams that relative path "./" is interpreted differently by web2py | |
# if the called url contains a / (slash) at the end or not. | |
# so when libraries (js and css) are called with relative path can happen that | |
# the required parameter for retrieving the host from db sometime is considered | |
# and sometimes not. | |
start = 0 | |
if (not request.env.http_referer is None) and request.env.http_referer.startswith(URL(scheme=True, host=True)): | |
# in those cases libraries (js and css) are loaded by the main html page | |
# called and the needed id is not considered in the interpretation of the | |
# relative path so I get it from the http_referer attribute of the request. | |
this_url = URL(scheme=True, host=True) | |
if request.env.http_referer.startswith(this_url): | |
start = len(this_url) | |
else: | |
start = 0 | |
path_referer = request.env.http_referer[start:].strip('/').split('/') | |
dm_id = int(path_referer[0]) | |
start = int(str(dm_id)==request.args(0)) | |
else: | |
dm_id = int(request.args.pop(0)) | |
if session.proxy is None: | |
session.proxy = {} | |
if not dm_id in session.proxy: | |
site = db.site[dm_id] | |
if not site.use_proxy: | |
redirect(site.url) | |
else: | |
from urlparse import urlparse | |
parsed = urlparse(site.url) | |
session.proxy[dm_id] = Storage( | |
# Custom solution: | |
# host = db.p_data_manager[dm_id].info['host'], | |
# host = site.url.split("/")[2] | |
host = parsed.netloc or site.url, | |
# cookies = request.cookies.copy() | |
) | |
# I compose the url to call | |
host = session.proxy[dm_id].host | |
session.forget() | |
# https protocol is not managed because it would imply a double encryption | |
protocol = 'http' # 'https' if request.is_https else 'http' | |
url = '%(protocol)s://%(host)s:8100' % locals() | |
location = '/'.join(request.args[start:]) | |
if location: | |
url += '/%s' % location | |
method = request.env.request_method.upper() if not 'force_method' in request.vars else request.vars.pop('force_method').upper() | |
data = { | |
'params' if method == 'GET' else 'data': dict(request.vars) | |
} | |
def _build_raw_cookie(): | |
""" """ | |
return "; ".join(["%s=%s" % (v.key, v.value) for k,v in request.cookies.items()]) | |
try: | |
res = requests.request(method, url, | |
allow_redirects = False, | |
# 2. In this way cookies are correctly managed and passed between the | |
# client and the server and back again transparently to the user | |
headers = dict( | |
cookie = _build_raw_cookie() | |
# ^^^^^^ NOT "cookies" | |
), | |
**data | |
) | |
except requests.exceptions.ConnectionError as err: | |
msg = """ConnectionError contacting: '%(url)s' with method '%(method)s' and data: | |
%(data)s | |
%(err)s | |
""" % locals() | |
logger.error(msg) | |
raise HTTP(408) | |
for k,v in (res.cookies or {}).iteritems(): | |
response.cookies[k] = v.strip('\"') | |
response.cookies[k]['path'] = '/' | |
if res.status_code == 200: | |
for k,v in res.headers.items(): | |
if k not in ('content-length', 'content-encoding', ): | |
response.headers[k.title()] = v | |
return res.content | |
elif res.status_code in (302, 303, ): | |
redirect(URL(args=[dm_id])+res.headers['location'], how=res.status_code) | |
else: | |
err = res.content | |
code = res.status_code | |
msg = """Error contacting: '%(url)s' with method '%(method)s' and data: | |
%(data)s | |
Returned status code: %(code)s | |
%(err)s | |
""" % locals() | |
logger.error(msg) | |
raise HTTP(res.status_code) |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment