Skip to content

Commit bed2dfe

Browse files
committed
feat: add gzip support, send UA containing version
1 parent e7642c6 commit bed2dfe

File tree

2 files changed

+47
-11
lines changed

2 files changed

+47
-11
lines changed

browserstack/local.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ def __init__(self, key=None, binary_path=None, **kwargs):
1515
self.key = os.environ['BROWSERSTACK_ACCESS_KEY'] if 'BROWSERSTACK_ACCESS_KEY' in os.environ else key
1616
self.options = kwargs
1717
self.local_logfile_path = os.path.join(os.getcwd(), 'local.log')
18+
LocalBinary.set_version(self.get_package_version())
1819

1920
def __xstr(self, key, value):
2021
if key is None:

browserstack/local_binary.py

Lines changed: 46 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,21 @@
11
import platform, os, sys, stat, tempfile, re, subprocess
22
from browserstack.bserrors import BrowserStackLocalError
3+
import gzip
34

45
try:
5-
from urllib.request import urlopen
6+
import urllib.request
7+
8+
def urlopen(url, headers=None):
9+
return urllib.request.urlopen(urllib.request.Request(url, headers=headers))
610
except ImportError:
7-
from urllib2 import urlopen
11+
import urllib2
12+
13+
def urlopen(url, headers=None):
14+
return urllib2.urlopen(urllib2.Request(url, headers=headers))
815

916
class LocalBinary:
17+
_version = None
18+
1019
def __init__(self):
1120
is_64bits = sys.maxsize > 2**32
1221
self.is_windows = False
@@ -32,11 +41,13 @@ def __init__(self):
3241
]
3342
self.path_index = 0
3443

44+
@staticmethod
45+
def set_version(version):
46+
LocalBinary._version = version
47+
3548
def is_alpine(self):
36-
grepOutput = subprocess.run("grep -w NAME /etc/os-release", capture_output=True, shell=True)
37-
if grepOutput.stdout.decode('utf-8').find('Alpine') > -1:
38-
return True
39-
return False
49+
response = subprocess.check_output(["grep", "-w", "NAME", "/etc/os-release"])
50+
return response.decode('utf-8').find('Alpine') > -1
4051

4152
def __make_path(self, dest_path):
4253
try:
@@ -57,33 +68,57 @@ def __available_dir(self):
5768
raise BrowserStackLocalError('Error trying to download BrowserStack Local binary')
5869

5970
def download(self, chunk_size=8192, progress_hook=None):
60-
response = urlopen(self.http_path)
71+
headers = {
72+
'User-Agent': '/'.join(('browserstack-local-python', LocalBinary._version)),
73+
'Accept-Encoding': 'gzip, *',
74+
}
75+
76+
if sys.version_info < (3, 2):
77+
# lack of support for gzip decoding for stream, response is expected to have a tell() method
78+
headers.pop('Accept-Encoding', None)
79+
80+
response = urlopen(self.http_path, headers=headers)
6181
try:
62-
total_size = int(response.info().getheader('Content-Length').strip())
82+
total_size = int(response.info().get('Content-Length', '').strip() or '0')
6383
except:
64-
total_size = int(response.info().get_all('Content-Length')[0].strip())
84+
total_size = int(response.info().get_all('Content-Length')[0].strip() or '0')
6585
bytes_so_far = 0
6686

6787
dest_parent_dir = self.__available_dir()
6888
dest_binary_name = 'BrowserStackLocal'
6989
if self.is_windows:
7090
dest_binary_name += '.exe'
7191

92+
content_encoding = response.info().get('Content-Encoding', '')
93+
gzip_file = gzip.GzipFile(fileobj=response, mode='rb') if content_encoding.lower() == 'gzip' else None
94+
95+
def read_chunk(chunk_size):
96+
if gzip_file:
97+
return gzip_file.read(chunk_size)
98+
else:
99+
return response.read(chunk_size)
100+
72101
with open(os.path.join(dest_parent_dir, dest_binary_name), 'wb') as local_file:
73102
while True:
74-
chunk = response.read(chunk_size)
103+
chunk = read_chunk(chunk_size)
75104
bytes_so_far += len(chunk)
76105

77106
if not chunk:
78107
break
79108

80-
if progress_hook:
109+
if total_size > 0 and progress_hook:
81110
progress_hook(bytes_so_far, chunk_size, total_size)
82111

83112
try:
84113
local_file.write(chunk)
85114
except:
86115
return self.download(chunk_size, progress_hook)
116+
117+
if gzip_file:
118+
gzip_file.close()
119+
120+
if callable(getattr(response, 'close', None)):
121+
response.close()
87122

88123
final_path = os.path.join(dest_parent_dir, dest_binary_name)
89124
st = os.stat(final_path)

0 commit comments

Comments
 (0)