Skip to content

Instantly share code, notes, and snippets.

@manuelep
Last active February 13, 2018 14:34
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save manuelep/81ffe8ce57de4dc9b2d80a99c08992cc to your computer and use it in GitHub Desktop.
Save manuelep/81ffe8ce57de4dc9b2d80a99c08992cc to your computer and use it in GitHub Desktop.
web2py proxy
# -*- 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