Skip to content

Commit a204fb1

Browse files
Merge branch 'master' into master
2 parents 9986915 + 48accb7 commit a204fb1

File tree

10 files changed

+230
-60
lines changed

10 files changed

+230
-60
lines changed

.travis.yml

Lines changed: 17 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,15 @@
11
language: python
2+
3+
jdk:
4+
- oraclejdk8
5+
6+
addons:
7+
apt:
8+
packages:
9+
- oracle-java8-installer
10+
- oracle-java8-set-default
11+
- google-chrome-stable
12+
213
sudo: false
314
python:
415
- 2.6
@@ -7,10 +18,12 @@ python:
718
- 3.4
819
- 3.5
920
before_script:
10-
- curl -l -L -O https://github.com/lightbody/browsermob-proxy/releases/download/browsermob-proxy-2.1.0-beta-6/browsermob-proxy-2.1.0-beta-6-bin.zip
11-
- unzip browsermob-proxy-2.1.0-beta-6-bin.zip
12-
- sh browsermob-proxy-2.1.0-beta-6/bin/browsermob-proxy --port=9090 &
21+
- export DISPLAY=:99.0
22+
- sh -e /etc/init.d/xvfb start
23+
- ./bootstrap.sh
24+
- ./start-servers.sh
1325
- sleep 5
1426
install: pip install pytest selenium
15-
script: python setup.py develop && py.test -m "not human" test
27+
script: python setup.py develop && py.test test
1628
sudo: false
29+
dist: trusty

History.md

Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,45 @@
11

2+
0.8.0 / 2017-02-07
3+
==================
4+
5+
* Adds rewrite rules clear api. Fixes content type for request/response intercept and adds doc links for writing intercept code. Adds comments clarifying intercept client test coverage. Augments human test for url rewrite and adds clear portion. Adds test for response intercept. Adds bootstrap script to download tools to test with. Refactors human tests so browser session are cleaned up when tests fail and tests run with chromium. Adds server start script for travis. Changes .travis.yml to use provided scripts and also run headless chrome.
6+
* If the JSON doesn't load, it's likely because the user has another server running on the same port. Improve the error message here so can figure out what's going on more easily.
7+
* Inherit from Exception as StandardError was removed in Python 3
8+
* Add ProxyServerError and raise it instead of Exception
9+
* Fix docstring for limits()
10+
* Fix path join issue: log_path_name would be /server.log
11+
* Make default option values more robust
12+
* Add retry sleep and count in options
13+
* Reenabling timeout tests as they have been fixed in B6 of the server
14+
* Removing duplicate method. Fixes #41
15+
* docstrings cleanup
16+
* configurable log file
17+
* added title options for new har and new har page
18+
* replaced mutable default values with None
19+
* Update Requests dependency version
20+
* Updating supported Python versions
21+
* Disabling a test due to BMP Server bug
22+
* Bumping version number of BMP server used in testing
23+
* Add bmp.log to .gitignore
24+
* Add details on how to contribute
25+
* Updating response URL endpoints to use filter
26+
* Ignoring .cache directory
27+
* Change remap_hosts to accept dictionary
28+
* Make sure the process is still running while waiting for the server to start.
29+
* Changed hostmap to be a named argument for compatibility
30+
* Merge remote-tracking branch 'upstream/master' into patch-1
31+
* Add the ability to empty the DNS cache
32+
* Correct function name
33+
* Add the ability to return all active proxy ports from Browsermob
34+
* switch to Travis container setup
35+
* Update to latest browsermob proxy release for testing
36+
* Correct exception typo
37+
* Update remap_hosts test
38+
* Fix whitespace
39+
* Let remap_hosts accept a dictionary
40+
* Upgrading Travis to it's container system
41+
* bumping to 0.7.1
42+
243
0.7.1 / 2015-07-09
344
==================
445

bootstrap.sh

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
#!/usr/bin/env bash
2+
if [ "$(uname)" == "Darwin" ]; then
3+
echo "We're on a MAC!"
4+
chromeDriver="chromedriver_mac64.zip"
5+
geckoDriverVersion="v0.13.0"
6+
geckoDriver="geckodriver-$geckoDriverVersion-macos.tar.gz"
7+
else
8+
echo "We're not on a MAC!"
9+
chromeDriver="chromedriver_linux64.zip"
10+
geckoDriverVersion="v0.14.0"
11+
geckoDriver="geckodriver-$geckoDriverVersion-linux64.tar.gz"
12+
fi
13+
rm -rf tools
14+
mkdir -p tools && \
15+
cd tools && \
16+
wget https://github.com/lightbody/browsermob-proxy/releases/download/browsermob-proxy-2.1.4/browsermob-proxy-2.1.4-bin.zip && \
17+
unzip -o browsermob-proxy-2.1.4-bin.zip && \
18+
rm -rf browsermob-proxy*.zip* && \
19+
wget http://selenium-release.storage.googleapis.com/3.0/selenium-server-standalone-3.0.1.jar && \
20+
wget https://github.com/mozilla/geckodriver/releases/download/${geckoDriverVersion}/${geckoDriver} && \
21+
tar zxf ${geckoDriver} && \
22+
rm -rf ${geckoDriver}* && \
23+
wget https://chromedriver.storage.googleapis.com/2.27/${chromeDriver} && \
24+
unzip ${chromeDriver} && \
25+
rm -rf ${chromeDriver}* && \
26+
cd ..

browsermobproxy/client.py

Lines changed: 30 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,8 @@ def __init__(self, url, params=None, options=None):
3434
jcontent = json.loads(content)
3535
except Exception as e:
3636
raise Exception("Could not read Browsermob-Proxy json\n"
37-
"Another server running on this port?\n%s..."%content[:512])
37+
"Another server running on this port?\n%s..."%content[:512])
38+
3839
self.port = jcontent['port']
3940
url_parts = self.host.split(":")
4041
self.proxy = url_parts[1][2:] + ":" + str(self.port)
@@ -103,7 +104,6 @@ def har(self):
103104

104105
return r.json()
105106

106-
107107
def new_har(self, ref=None, options=None, title=None):
108108
"""
109109
This sets a new HAR to be recorded
@@ -199,24 +199,30 @@ def headers(self, headers):
199199

200200
def response_interceptor(self, js):
201201
"""
202-
Executes the javascript against each response
203-
204-
:param str js: the javascript to execute
202+
Executes the java/js code against each response
203+
`HttpRequest request <https://netty.io/4.1/api/io/netty/handler/codec/http/HttpRequest.html>`_,
204+
`HttpMessageContents contents <https://raw.githubusercontent.com/lightbody/browsermob-proxy/master/browsermob-core/src/main/java/net/lightbody/bmp/util/HttpMessageContents.java>`_,
205+
`HttpMessageInfo messageInfo <https://raw.githubusercontent.com/lightbody/browsermob-proxy/master/browsermob-core/src/main/java/net/lightbody/bmp/util/HttpMessageInfo.java>`_
206+
are available objects to interact with.
207+
:param str js: the js/java code to execute
205208
"""
206209
r = requests.post(url='%s/proxy/%s/filter/response' % (self.host, self.port),
207-
data=js,
208-
headers={'content-type': 'application/json'})
210+
data=js,
211+
headers={'content-type': 'text/plain'})
209212
return r.status_code
210213

211214
def request_interceptor(self, js):
212215
"""
213-
Executes the javascript against each request
214-
215-
:param str js: the javascript to execute
216+
Executes the java/js code against each response
217+
`HttpRequest request <https://netty.io/4.1/api/io/netty/handler/codec/http/HttpRequest.html>`_,
218+
`HttpMessageContents contents <https://raw.githubusercontent.com/lightbody/browsermob-proxy/master/browsermob-core/src/main/java/net/lightbody/bmp/util/HttpMessageContents.java>`_,
219+
`HttpMessageInfo messageInfo <https://raw.githubusercontent.com/lightbody/browsermob-proxy/master/browsermob-core/src/main/java/net/lightbody/bmp/util/HttpMessageInfo.java>`_
220+
are available objects to interact with.
221+
:param str js: the js/java code to execute
216222
"""
217223
r = requests.post(url='%s/proxy/%s/filter/request' % (self.host, self.port),
218-
data=js,
219-
headers={'content-type': 'application/json'})
224+
data=js,
225+
headers={'content-type': 'text/plain'})
220226
return r.status_code
221227

222228
LIMITS = {
@@ -295,7 +301,7 @@ def remap_hosts(self, address=None, ip_address=None, hostmap=None):
295301
hostmap[address] = ip_address
296302

297303
r = requests.post('%s/proxy/%s/hosts' % (self.host, self.port),
298-
json.dumps(hostmap),
304+
json.dumps(hostmap),
299305
headers={'content-type': 'application/json'})
300306
return r.status_code
301307

@@ -308,7 +314,7 @@ def wait_for_traffic_to_stop(self, quiet_period, timeout):
308314
:param int timeout: max number of milliseconds to wait
309315
"""
310316
r = requests.put('%s/proxy/%s/wait' % (self.host, self.port),
311-
{'quietPeriodInMs': quiet_period, 'timeoutInMs': timeout})
317+
{'quietPeriodInMs': quiet_period, 'timeoutInMs': timeout})
312318
return r.status_code
313319

314320
def clear_dns_cache(self):
@@ -334,12 +340,21 @@ def rewrite_url(self, match, replace):
334340
params)
335341
return r.status_code
336342

343+
def clear_all_rewrite_url_rules(self):
344+
"""
345+
Clears all URL rewrite rules
346+
:return: status code
347+
"""
348+
349+
r = requests.delete('%s/proxy/%s/rewrite' % (self.host, self.port))
350+
return r.status_code
351+
337352
def retry(self, retry_count):
338353
"""
339354
Retries. No idea what its used for, but its in the API...
340355
341356
:param int retry_count: the number of retries
342357
"""
343358
r = requests.put('%s/proxy/%s/retry' % (self.host, self.port),
344-
{'retrycount': retry_count})
359+
{'retrycount': retry_count})
345360
return r.status_code

browsermobproxy/server.py

Lines changed: 27 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,13 @@
11
import os
22
import platform
3+
import signal
34
import socket
45
import subprocess
56
import time
67
import logging
78

9+
import sys
10+
811
from .client import Client
912
from .exceptions import ProxyServerError
1013

@@ -63,6 +66,8 @@ def __init__(self, path='browsermob-proxy', options=None):
6366
More items will be added in the future.
6467
This defaults to an empty dictionary
6568
"""
69+
self.win_env = sys.platform == "win32"
70+
6671
options = options if options is not None else {}
6772

6873
path_var_sep = ':'
@@ -82,7 +87,7 @@ def __init__(self, path='browsermob-proxy', options=None):
8287
"in path provided: %s" % path)
8388

8489
self.path = path
85-
self.host = 'localhost'
90+
self.host = options.get('host', 'localhost')
8691
self.port = options.get('port', 8080)
8792
self.process = None
8893

@@ -109,13 +114,16 @@ def start(self, options=None):
109114
log_path_name = os.path.join(log_path, log_file)
110115
self.log_file = open(log_path_name, 'w')
111116

117+
112118
if self._is_listening(.1):
113119
logging.info("BrowserMob proxy already running. Won't start again.")
114120
return
115-
116-
self.process = subprocess.Popen(self.command,
117-
stdout=self.log_file,
118-
stderr=subprocess.STDOUT)
121+
122+
if self.win_env:
123+
self.process = self._start_on_windows()
124+
else:
125+
self.process = self._start_on_unix()
126+
119127
count = 0
120128
while not self._is_listening():
121129
if self.process.poll():
@@ -131,16 +139,30 @@ def start(self, options=None):
131139
self.stop()
132140
raise ProxyServerError("Can't connect to Browsermob-Proxy")
133141

142+
def _start_on_windows(self):
143+
return subprocess.Popen(self.command,
144+
creationflags=subprocess.CREATE_NEW_PROCESS_GROUP,
145+
stdout=self.log_file,
146+
stderr=subprocess.STDOUT)
147+
148+
def _start_on_unix(self):
149+
return subprocess.Popen(self.command,
150+
preexec_fn=os.setsid,
151+
stdout=self.log_file,
152+
stderr=subprocess.STDOUT)
153+
134154
def stop(self):
135155
"""
136156
This will stop the process running the proxy
137157
"""
138158
if self.process.poll() is not None:
139159
return
140160

161+
group_pid = os.getpgid(self.process.pid) if not self.win_env else self.process.pid
141162
try:
142163
self.process.kill()
143164
self.process.wait()
165+
os.killpg(group_pid, signal.SIGINT)
144166
except AttributeError:
145167
# kill may not be available under windows environment
146168
pass

setup.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,10 @@
11
from setuptools import setup, find_packages
22

33
setup(name='browsermob-proxy',
4-
version='0.7.1',
4+
version='0.8.0',
55
description='A library for interacting with the Browsermob Proxy',
66
author='David Burns',
7-
author_email='david.burns at theautomatedtester dot co dot uk',
7+
author_email='david.burns@theautomatedtester.co.uk',
88
url='http://oss.theautomatedtester.co.uk/browsermob-proxy-py',
99
classifiers=['Development Status :: 3 - Alpha',
1010
'Intended Audience :: Developers',

start-servers.sh

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
#!/usr/bin/env bash
2+
TOOLS=$(pwd)/tools
3+
cd $TOOLS/browsermob-proxy-2.1.4/bin/ && \
4+
./browsermob-proxy --port 9090 & \
5+
cd $TOOLS && \
6+
java -Dwebdriver.chrome.driver=chromedriver -Dwebdriver.gecko.driver=geckodriver -jar selenium-server-standalone-3.0.1.jar &

test/test_client.py

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -167,6 +167,8 @@ def test_close(self):
167167
def test_response_interceptor_with_parsing_js(self):
168168
"""
169169
/proxy/:port/interceptor/response
170+
This test is only checking very basic syntax rules. The snippet needs to be JAVA/JS
171+
Code only gets validated if the filter/interceptor is used.
170172
"""
171173
js = 'alert("foo")'
172174
status_code = self.client.response_interceptor(js)
@@ -175,6 +177,8 @@ def test_response_interceptor_with_parsing_js(self):
175177
def test_response_interceptor_with_invalid_js(self):
176178
"""
177179
/proxy/:port/interceptor/response
180+
This test is only checking very basic syntax rules. The snippet needs to be JAVA/JS
181+
Code only gets validated if the filter/interceptor is used.
178182
"""
179183
js = 'alert("foo"'
180184
status_code = self.client.response_interceptor(js)
@@ -183,6 +187,8 @@ def test_response_interceptor_with_invalid_js(self):
183187
def test_request_interceptor_with_parsing_js(self):
184188
"""
185189
/proxy/:port/interceptor/request
190+
This test is only checking very basic syntax rules. The snippet needs to be JAVA/JS
191+
Code only gets validated if the filter/interceptor is used.
186192
"""
187193
js = 'alert("foo")'
188194
status_code = self.client.request_interceptor(js)
@@ -191,6 +197,8 @@ def test_request_interceptor_with_parsing_js(self):
191197
def test_request_interceptor_with_invalid_js(self):
192198
"""
193199
/proxy/:port/interceptor/request
200+
This test is only checking very basic syntax rules. The snippet needs to be JAVA/JS
201+
Code only gets validated if the filter/interceptor is used.
194202
"""
195203
js = 'alert("foo"'
196204
status_code = self.client.request_interceptor(js)

0 commit comments

Comments
 (0)