1
0
mirror of https://github.com/webrecorder/pywb.git synced 2025-03-15 00:03:28 +01:00

proxy testing: refactored test server thread into ServerThreadRunner

class which runs a server in a seperate thread.. used by http/s proxies
as well, as mock live server proxy
add test for live rewrite with proxy, covering simple case as well as
video
This commit is contained in:
Ilya Kreymer 2014-12-23 11:07:47 -08:00
parent a8b4041716
commit a9892f531f
6 changed files with 250 additions and 93 deletions

View File

@ -35,9 +35,11 @@ class RewriteHandler(SearchPageWbUrlHandler):
def __init__(self, config):
super(RewriteHandler, self).__init__(config)
self.proxy = config.get('proxyhostport')
proxyhostport = config.get('proxyhostport')
self.rewriter = LiveRewriter(is_framed_replay=self.is_frame_mode,
proxies=self.proxy)
proxies=proxyhostport)
self.proxies = self.rewriter.proxies
self.head_insert_view = HeadInsertView.init_from_config(config)
@ -81,7 +83,7 @@ class RewriteHandler(SearchPageWbUrlHandler):
readd_range = False
cache_key = None
if self.proxy:
if self.proxies:
rangeres = wbrequest.extract_range()
if rangeres:
@ -113,7 +115,7 @@ class RewriteHandler(SearchPageWbUrlHandler):
try:
content_length = int(content_length)
wbresponse.status_headers.add_range(0, content_length, content_length)
except ValueError:
except (ValueError, TypeError):
pass
if cache_key:
@ -150,9 +152,6 @@ class RewriteHandler(SearchPageWbUrlHandler):
referrer = wbrequest.env.get('REL_REFERER')
def do_ping():
proxies = {'http': self.proxy,
'https': self.proxy}
headers = self._live_request_headers(wbrequest)
headers['Connection'] = 'close'
@ -162,7 +161,7 @@ class RewriteHandler(SearchPageWbUrlHandler):
resp = requests.get(url=url,
headers=headers,
proxies=proxies,
proxies=self.proxies,
verify=False,
stream=True)
@ -170,6 +169,7 @@ class RewriteHandler(SearchPageWbUrlHandler):
resp.close()
except:
del self._cache[key]
raise
# also ping video info
if referrer:
@ -183,9 +183,9 @@ class RewriteHandler(SearchPageWbUrlHandler):
try:
do_ping()
except:
raise
pass
#do_ping()
wbresponse.body = wrap_buff_gen(wbresponse.body)
return wbresponse
@ -204,9 +204,7 @@ class RewriteHandler(SearchPageWbUrlHandler):
content_type = self.YT_DL_TYPE
metadata = json.dumps(info)
if self.proxy:
proxies = {'http': self.proxy}
if self.proxies:
headers = self._live_request_headers(wbrequest)
headers['Content-Type'] = content_type
@ -216,7 +214,7 @@ class RewriteHandler(SearchPageWbUrlHandler):
url=info_url,
data=metadata,
headers=headers,
proxies=proxies,
proxies=self.proxies,
verify=False)
return WbResponse.text_response(metadata, content_type=content_type)

32
tests/server_thread.py Normal file
View File

@ -0,0 +1,32 @@
import threading
from pywb.webapp.pywb_init import create_wb_router
from pywb.framework.wsgi_wrappers import init_app
class ServerThreadRunner(object):
def __init__(self, make_httpd, config_file=None):
if config_file:
self.app = init_app(create_wb_router,
load_yaml=True,
config_file=config_file)
else:
self.app = None
self.httpd = make_httpd(self.app)
self.port = self.httpd.socket.getsockname()[1]
proxy_str = 'http://localhost:' + str(self.port)
self.proxy_dict = {'http': proxy_str,
'https': proxy_str}
def run():
self.httpd.serve_forever()
self.thread = threading.Thread(target=run)
self.thread.daemon = True
self.thread.start()
def stop_thread(self):
self.httpd.shutdown()

179
tests/test_live_proxy.py Normal file
View File

@ -0,0 +1,179 @@
from SocketServer import ThreadingMixIn
from BaseHTTPServer import HTTPServer, BaseHTTPRequestHandler
from server_thread import ServerThreadRunner
from pywb.webapp.live_rewrite_handler import create_live_rewriter_app, RewriteHandler
from pywb.framework.wsgi_wrappers import init_app
import webtest
import shutil
#=================================================================
#ThreadingMixIn.deamon_threads = True
#class ProxyServer(ThreadingMixIn, HTTPServer):
class ProxyServer(HTTPServer):
pass
class ProxyRequest(BaseHTTPRequestHandler):
def do_GET(self):
if self.server.force_err:
# just close connection
self.wfile.close()
return
buff = ''
buff += self.command + ' ' + self.path + ' ' + self.request_version + '\n'
for n in self.headers:
buff += n + ': ' + self.headers[n] + '\n'
self.server.requestlog.append(buff)
self.send_response(200)
self.send_header('x-proxy', 'test')
self.send_header('content-length', str(len(buff)))
self.send_header('content-type', 'text/plain')
self.end_headers()
self.wfile.write(buff)
self.wfile.close()
def do_PUTMETA(self):
self.do_GET()
#=================================================================
class TestProxyLiveRewriter:
def setup(self):
self.requestlog = []
def make_httpd(app):
proxyserv = ProxyServer(('', 0), ProxyRequest)
proxyserv.requestlog = self.requestlog
proxyserv.force_err = False
self.proxyserv = proxyserv
return proxyserv
self.server = ServerThreadRunner(make_httpd)
self.app = init_app(create_live_rewriter_app, load_yaml=False,
config=dict(framed_replay=True,
proxyhostport=self.server.proxy_dict))
print(self.server.proxy_dict)
self.testapp = webtest.TestApp(self.app)
def teardown(self):
self.server.stop_thread()
def test_echo_proxy_referrer(self):
headers = [('User-Agent', 'python'), ('Referer', 'http://localhost:80/rewrite/other.example.com')]
resp = self.testapp.get('/rewrite/http://example.com/', headers=headers)
# ensure just one request
assert len(self.requestlog) == 1
# equal to returned response (echo)
assert self.requestlog[0] == resp.body
assert resp.headers['x-archive-orig-x-proxy'] == 'test'
assert resp.body.startswith('GET http://example.com/ HTTP/1.1')
assert 'referer: http://other.example.com' in resp.body
def test_echo_proxy_start_unbounded_remove_range(self):
headers = [('Range', 'bytes=0-')]
resp = self.testapp.get('/rewrite/http://example.com/', headers=headers)
# actual response is with range
assert resp.status_int == 206
assert 'Content-Range' in resp.headers
assert resp.headers['Accept-Ranges'] == 'bytes'
assert len(self.requestlog) == 1
# proxied, but without range
assert self.requestlog[0] == resp.body
assert resp.headers['x-archive-orig-x-proxy'] == 'test'
assert self.requestlog[0].startswith('GET http://example.com/ HTTP/1.1')
assert 'range: ' not in self.requestlog[0]
def test_echo_proxy_bounded_noproxy_range(self):
headers = [('Range', 'bytes=10-1000')]
resp = self.testapp.get('/rewrite/http://example.com/foobar', headers=headers)
# actual response is with range
assert resp.status_int == 206
assert 'Content-Range' in resp.headers
assert resp.headers['Accept-Ranges'] == 'bytes'
# not from proxy
assert 'x-archive-orig-x-proxy' not in resp.headers
# proxy receives a request also, but w/o range
assert len(self.requestlog) == 1
# proxy receives different request than our response
assert self.requestlog[0] != resp.body
assert self.requestlog[0].startswith('GET http://example.com/foobar HTTP/1.1')
# no range request
assert 'range: ' not in self.requestlog[0]
# Second Request
# clear log
self.requestlog.pop()
headers = [('Range', 'bytes=1001-1500')]
resp = self.testapp.get('/rewrite/http://example.com/foobar', headers=headers)
# actual response is with range
assert resp.status_int == 206
assert 'Content-Range' in resp.headers
assert resp.headers['Accept-Ranges'] == 'bytes'
# not from proxy
assert 'x-archive-orig-x-proxy' not in resp.headers
# already pinged proxy, no additional requests set to proxy
assert len(self.requestlog) == 0
def test_echo_proxy_video_info(self):
resp = self.testapp.get('/rewrite/vi_/https://www.youtube.com/watch?v=DjFZyFWSt1M')
assert resp.status_int == 200
assert resp.content_type == RewriteHandler.YT_DL_TYPE, resp.content_type
assert len(self.requestlog) == 1
assert self.requestlog[0].startswith('PUTMETA http://www.youtube.com/watch?v=DjFZyFWSt1M HTTP/1.1')
def test_echo_proxy_video_with_referrer(self):
headers = [('Range', 'bytes=1000-2000'), ('Referer', 'http://localhost:80/rewrite/https://example.com/')]
resp = self.testapp.get('/rewrite/http://www.youtube.com/watch?v=DjFZyFWSt1M', headers=headers)
# not from proxy
assert 'x-archive-orig-x-proxy' not in resp.headers
# proxy receives two requests
assert len(self.requestlog) == 2
# first, non-ranged request for page
assert self.requestlog[0].startswith('GET http://www.youtube.com/watch?v=DjFZyFWSt1M HTTP/1.1')
assert 'range' not in self.requestlog[0]
# also a video info request recording the page
assert self.requestlog[1].startswith('PUTMETA http://example.com/ HTTP/1.1')
def test_echo_proxy_error(self):
headers = [('Range', 'bytes=1000-2000'), ('Referer', 'http://localhost:80/rewrite/https://example.com/')]
self.proxyserv.force_err = True
resp = self.testapp.get('/rewrite/http://www.youtube.com/watch?v=DjFZyFWSt1M', headers=headers)
# not from proxy
assert 'x-archive-orig-x-proxy' not in resp.headers
# no proxy requests as we're forcing exception
assert len(self.requestlog) == 0

View File

@ -1,4 +1,4 @@
from pywb.webapp.live_rewrite_handler import create_live_rewriter_app
from pywb.webapp.live_rewrite_handler import create_live_rewriter_app, RewriteHandler
from pywb.framework.wsgi_wrappers import init_app
import webtest
@ -41,6 +41,4 @@ class TestLiveRewriter:
def test_live_video_info(self):
resp = self.testapp.get('/rewrite/vi_/https://www.youtube.com/watch?v=DjFZyFWSt1M')
assert resp.status_int == 200
assert resp.content_type == 'application/vnd.youtube-dl_formats+json', resp.content_type
assert resp.content_type == RewriteHandler.YT_DL_TYPE, resp.content_type

View File

@ -1,57 +1,31 @@
from pywb.webapp.pywb_init import create_wb_router
from pywb.framework.wsgi_wrappers import init_app
from wsgiref.simple_server import make_server
from pywb.framework.proxy_resolvers import CookieResolver
import threading
import requests
import shutil
import sys
import os
from server_thread import ServerThreadRunner
#=================================================================
TEST_CONFIG = 'tests/test_config_proxy_http_cookie.yaml'
server = None
sesh_key = None
#=================================================================
# Inited once per module
def setup_module():
def make_httpd(app):
return make_server('', 0, app)
global server
server = ServeThread()
server.daemon = True
server.start()
global session
session = requests.Session()
server = ServerThreadRunner(make_httpd, TEST_CONFIG)
def teardown_module():
try:
server.httpd.shutdown()
threading.current_thread().join(server)
except Exception:
pass
class ServeThread(threading.Thread):
def __init__(self, *args, **kwargs):
super(ServeThread, self).__init__(*args, **kwargs)
self.app = init_app(create_wb_router,
load_yaml=True,
config_file=TEST_CONFIG)
# init with port 0 to allow os to pick a port
self.httpd = make_server('', 0, self.app)
port = self.httpd.socket.getsockname()[1]
proxy_str = 'http://localhost:' + str(port)
self.proxy_dict = {'http': proxy_str}
def run(self, *args, **kwargs):
self.httpd.serve_forever()
global server
server.stop_thread()
#=================================================================
class TestProxyHttpCookie:
def setup(self):
self.session = requests.Session()

View File

@ -1,69 +1,45 @@
import pytest
from pywb.webapp.pywb_init import create_wb_router
from pywb.framework.wsgi_wrappers import init_app
from server_thread import ServerThreadRunner
from wsgiref.simple_server import make_server
from pywb.framework.proxy_resolvers import CookieResolver
import threading
import requests
import shutil
import sys
import os
TEST_CONFIG = 'tests/test_config_proxy_https_cookie.yaml'
#=================================================================
TEST_CA_DIR = './tests/pywb_test_certs'
TEST_CA_ROOT = './tests/pywb_test_ca.pem'
TEST_CONFIG = 'tests/test_config_proxy_https_cookie.yaml'
server = None
sesh_key = None
#=================================================================
# Inited once per module
def setup_module():
openssl_support = pytest.importorskip("OpenSSL")
def make_httpd(app):
return make_server('', 0, app)
global server
server = ServeThread()
server.daemon = True
server.start()
global session
session = requests.Session()
server = ServerThreadRunner(make_httpd, TEST_CONFIG)
def teardown_module():
try:
server.httpd.shutdown()
threading.current_thread().join(server)
except Exception:
pass
global server
server.stop_thread()
# delete test root and certs
shutil.rmtree(TEST_CA_DIR)
os.remove(TEST_CA_ROOT)
class ServeThread(threading.Thread):
def __init__(self, *args, **kwargs):
super(ServeThread, self).__init__(*args, **kwargs)
self.app = init_app(create_wb_router,
load_yaml=True,
config_file=TEST_CONFIG)
# init with port 0 to allow os to pick a port
self.httpd = make_server('', 0, self.app)
port = self.httpd.socket.getsockname()[1]
proxy_str = 'http://localhost:' + str(port)
self.proxy_dict = {'http': proxy_str, 'https': proxy_str}
def run(self, *args, **kwargs):
self.httpd.serve_forever()
#=================================================================
class TestProxyHttpsCookie:
def setup(self):
self.session = requests.Session()