1 # This Source Code Form is subject to the terms of the Mozilla Public
2 # License, v. 2.0. If a copy of the MPL was not distributed with this
3 # file, You can obtain one at http://mozilla.org/MPL/2.0/.
10 from urllib
.parse
import urlparse
, urlunparse
15 def fetch_url_for_cdms(cdms
, urlParams
):
19 cdm
["fileUrl"] = cdm
["fileName"].format_map(urlParams
)
20 response
= requests
.get(cdm
["fileUrl"], allow_redirects
=False)
21 if response
.status_code
!= 302:
23 "{} unexpected status code {}".format(
24 cdm
["target"], response
.status_code
28 redirectUrl
= response
.headers
["Location"]
29 parsedUrl
= urlparse(redirectUrl
)
30 if parsedUrl
.scheme
!= "https":
32 "{} expected https scheme '{}'".format(cdm
["target"], redirectUrl
)
35 sanitizedUrl
= urlunparse(
36 (parsedUrl
.scheme
, parsedUrl
.netloc
, parsedUrl
.path
, None, None, None)
39 # Note that here we modify the returned URL from the
40 # component update service because it returns a preferred
41 # server for the caller of the script. This may not match
42 # up with what the end users require. Google has requested
43 # that we instead replace these results with the
44 # edgedl.me.gvt1.com domain/path, which should be location
46 normalizedUrl
= re
.sub(
48 "https://edgedl.me.gvt1.com/edgedl/release2",
53 "{} cannot normalize '{}'".format(cdm
["target"], sanitizedUrl
)
56 # Because some users are unable to resolve *.gvt1.com
57 # URLs, we supply an alternative based on www.google.com.
58 # This should resolve with success more frequently.
61 "https://www.google.com/dl/release2",
65 version
= re
.search(r
".*?_([\d]+\.[\d]+\.[\d]+\.[\d]+)/", sanitizedUrl
)
68 "{} cannot extract version '{}'".format(cdm
["target"], sanitizedUrl
)
70 if any_version
is None:
71 any_version
= version
.group(1)
72 elif version
.group(1) != any_version
:
74 "{} version {} mismatch {}".format(
75 cdm
["target"], version
.group(1), any_version
78 cdm
["fileName"] = normalizedUrl
79 if mirrorUrl
and mirrorUrl
!= normalizedUrl
:
80 cdm
["fileNameMirror"] = mirrorUrl
84 def fetch_data_for_cdms(cdms
, urlParams
):
87 cdm
["fileUrl"] = cdm
["fileName"].format_map(urlParams
)
88 response
= requests
.get(cdm
["fileUrl"])
89 response
.raise_for_status()
90 cdm
["hashValue"] = hashlib
.sha512(response
.content
).hexdigest()
91 if "fileNameMirror" in cdm
:
92 cdm
["mirrorUrl"] = cdm
["fileNameMirror"].format_map(urlParams
)
93 mirrorresponse
= requests
.get(cdm
["mirrorUrl"])
94 mirrorresponse
.raise_for_status()
95 mirrorhash
= hashlib
.sha512(mirrorresponse
.content
).hexdigest()
96 if cdm
["hashValue"] != mirrorhash
:
98 "Primary hash {} and mirror hash {} differ",
102 cdm
["filesize"] = len(response
.content
)
103 if cdm
["filesize"] == 0:
104 raise Exception("Empty response for {target}".format_map(cdm
))
107 def generate_json_for_cdms(cdms
):
113 + ' "alias": "{alias}"\n'
116 elif "mirrorUrl" in cdm
:
119 + ' "fileUrl": "{fileUrl}",\n'
120 + ' "mirrorUrls": [\n'
123 + ' "filesize": {filesize},\n'
124 + ' "hashValue": "{hashValue}"\n'
130 + ' "fileUrl": "{fileUrl}",\n'
131 + ' "mirrorUrls": [],\n'
132 + ' "filesize": {filesize},\n'
133 + ' "hashValue": "{hashValue}"\n'
136 return cdm_json
[:-2] + "\n"
139 def calculate_gmpopenh264_json(version
: str, version_hash
: str, url_base
: str) -> str:
142 {"target": "Darwin_aarch64-gcc3", "fileName": "{url_base}/openh264-macosx64-aarch64-{version}.zip"},
143 {"target": "Darwin_x86_64-gcc3", "fileName": "{url_base}/openh264-macosx64-{version}.zip"},
144 {"target": "Linux_aarch64-gcc3", "fileName": "{url_base}/openh264-linux64-aarch64-{version}.zip"},
145 {"target": "Linux_x86-gcc3", "fileName": "{url_base}/openh264-linux32-{version}.zip"},
146 {"target": "Linux_x86_64-gcc3", "fileName": "{url_base}/openh264-linux64-{version}.zip"},
147 {"target": "Linux_x86_64-gcc3-asan", "alias": "Linux_x86_64-gcc3"},
148 {"target": "WINNT_aarch64-msvc-aarch64", "fileName": "{url_base}/openh264-win64-aarch64-{version}.zip"},
149 {"target": "WINNT_x86-msvc", "fileName": "{url_base}/openh264-win32-{version}.zip"},
150 {"target": "WINNT_x86-msvc-x64", "alias": "WINNT_x86-msvc"},
151 {"target": "WINNT_x86-msvc-x86", "alias": "WINNT_x86-msvc"},
152 {"target": "WINNT_x86_64-msvc", "fileName": "{url_base}/openh264-win64-{version}.zip"},
153 {"target": "WINNT_x86_64-msvc-x64", "alias": "WINNT_x86_64-msvc"},
154 {"target": "WINNT_x86_64-msvc-x64-asan", "alias": "WINNT_x86_64-msvc"},
158 fetch_data_for_cdms(cdms
, {"url_base": url_base
, "version": version_hash
})
159 except Exception as e
:
160 logging
.error("calculate_gmpopenh264_json: could not create JSON due to: %s", e
)
165 + ' "hashFunction": "sha512",\n'
166 + ' "name": "OpenH264-{}",\n'.format(version
)
167 + ' "schema_version": 1000,\n'
169 + ' "gmp-gmpopenh264": {\n'
170 + ' "platforms": {\n'
171 + generate_json_for_cdms(cdms
)
173 + ' "version": "{}"\n'.format(version
)
180 def calculate_widevinecdm_json(version
: str, url_base
: str) -> str:
183 {"target": "Darwin_aarch64-gcc3", "fileName": "{url_base}/{version}-mac-arm64.zip"},
184 {"target": "Darwin_x86_64-gcc3", "alias": "Darwin_x86_64-gcc3-u-i386-x86_64"},
185 {"target": "Darwin_x86_64-gcc3-u-i386-x86_64", "fileName": "{url_base}/{version}-mac-x64.zip"},
186 {"target": "Linux_x86_64-gcc3", "fileName": "{url_base}/{version}-linux-x64.zip"},
187 {"target": "Linux_x86_64-gcc3-asan", "alias": "Linux_x86_64-gcc3"},
188 {"target": "WINNT_aarch64-msvc-aarch64", "fileName": "{url_base}/{version}-win-arm64.zip"},
189 {"target": "WINNT_x86-msvc", "fileName": "{url_base}/{version}-win-x86.zip"},
190 {"target": "WINNT_x86-msvc-x64", "alias": "WINNT_x86-msvc"},
191 {"target": "WINNT_x86-msvc-x86", "alias": "WINNT_x86-msvc"},
192 {"target": "WINNT_x86_64-msvc", "fileName": "{url_base}/{version}-win-x64.zip"},
193 {"target": "WINNT_x86_64-msvc-x64", "alias": "WINNT_x86_64-msvc"},
194 {"target": "WINNT_x86_64-msvc-x64-asan", "alias": "WINNT_x86_64-msvc"},
198 fetch_data_for_cdms(cdms
, {"url_base": url_base
, "version": version
})
199 except Exception as e
:
200 logging
.error("calculate_widevinecdm_json: could not create JSON due to: %s", e
)
205 + ' "hashFunction": "sha512",\n'
206 + ' "name": "Widevine-{}",\n'.format(version
)
207 + ' "schema_version": 1000,\n'
209 + ' "gmp-widevinecdm": {\n'
210 + ' "platforms": {\n'
211 + generate_json_for_cdms(cdms
)
213 + ' "version": "{}"\n'.format(version
)
220 def calculate_chrome_component_json(
221 name
: str, altname
: str, url_base
: str, cdms
224 version
= fetch_url_for_cdms(cdms
, {"url_base": url_base
})
225 fetch_data_for_cdms(cdms
, {})
226 except Exception as e
:
228 "calculate_chrome_component_json: could not create JSON due to: %s", e
234 + ' "hashFunction": "sha512",\n'
235 + ' "name": "{}-{}",\n'.format(name
, version
)
236 + ' "schema_version": 1000,\n'
238 + ' "gmp-{}": {{\n'.format(altname
)
239 + ' "platforms": {\n'
240 + generate_json_for_cdms(cdms
)
242 + ' "version": "{}"\n'.format(version
)
249 def calculate_widevinecdm_component_json(url_base
: str) -> str:
252 {"target": "Darwin_aarch64-gcc3", "fileName": "{url_base}&os=mac&arch=arm64&os_arch=arm64"},
253 {"target": "Darwin_x86_64-gcc3", "alias": "Darwin_x86_64-gcc3-u-i386-x86_64"},
254 {"target": "Darwin_x86_64-gcc3-u-i386-x86_64", "fileName": "{url_base}&os=mac&arch=x64&os_arch=x64"},
255 {"target": "Linux_x86_64-gcc3", "fileName": "{url_base}&os=Linux&arch=x64&os_arch=x64"},
256 {"target": "Linux_x86_64-gcc3-asan", "alias": "Linux_x86_64-gcc3"},
257 {"target": "WINNT_aarch64-msvc-aarch64", "fileName": "{url_base}&os=win&arch=arm64&os_arch=arm64"},
258 {"target": "WINNT_x86-msvc", "fileName": "{url_base}&os=win&arch=x86&os_arch=x86"},
259 {"target": "WINNT_x86-msvc-x64", "alias": "WINNT_x86-msvc"},
260 {"target": "WINNT_x86-msvc-x86", "alias": "WINNT_x86-msvc"},
261 {"target": "WINNT_x86_64-msvc", "fileName": "{url_base}&os=win&arch=x64&os_arch=x64"},
262 {"target": "WINNT_x86_64-msvc-x64", "alias": "WINNT_x86_64-msvc"},
263 {"target": "WINNT_x86_64-msvc-x64-asan", "alias": "WINNT_x86_64-msvc"},
266 return calculate_chrome_component_json(
269 url_base
.format_map({"guid": "oimompecagnajdejgnnjijobebaeigek"}),
274 def calculate_widevinecdm_l1_component_json(url_base
: str) -> str:
277 {"target": "WINNT_x86_64-msvc", "fileName": "{url_base}&os=win&arch=x64&os_arch=x64"},
278 {"target": "WINNT_x86_64-msvc-x64", "alias": "WINNT_x86_64-msvc"},
279 {"target": "WINNT_x86_64-msvc-x64-asan", "alias": "WINNT_x86_64-msvc"},
282 return calculate_chrome_component_json(
285 url_base
.format_map({"guid": "neifaoindggfcjicffkgpmnlppeffabd"}),
291 examples
= """examples:
292 python dom/media/tools/generateGmpJson.py widevine 4.10.2557.0 >toolkit/content/gmp-sources/widevinecdm.json
293 python dom/media/tools/generateGmpJson.py --url http://localhost:8080 openh264 2.3.1 0a48f4d2e9be2abb4fb01b4c3be83cf44ce91a6e
294 python dom/media/tools/generateGmpJson.py widevine_component"""
296 parser
= argparse
.ArgumentParser(
297 description
="Generate JSON for GMP plugin updates",
299 formatter_class
=argparse
.RawDescriptionHelpFormatter
,
303 help="which plugin: openh264, widevine, widevine_component, widevine_l1_component",
305 parser
.add_argument("version", help="version of plugin", nargs
="?")
306 parser
.add_argument("revision", help="revision hash of plugin", nargs
="?")
307 parser
.add_argument("--url", help="override base URL from which to fetch plugins")
311 help="request upcoming version for component update service",
313 args
= parser
.parse_args()
315 if args
.plugin
== "openh264":
316 url_base
= "http://ciscobinary.openh264.org"
317 if args
.version
is None or args
.revision
is None:
318 parser
.error("openh264 requires version and revision")
319 elif args
.plugin
== "widevine":
320 url_base
= "https://redirector.gvt1.com/edgedl/widevine-cdm"
321 if args
.version
is None:
322 parser
.error("widevine requires version")
323 if args
.revision
is not None:
324 parser
.error("widevine cannot use revision")
325 elif args
.plugin
in ("widevine_component", "widevine_l1_component"):
326 url_base
= "https://update.googleapis.com/service/update2/crx?response=redirect&x=id%3D{guid}%26uc&acceptformat=crx3&updaterversion=999"
328 url_base
+= "&testrequest=1"
329 if args
.version
is not None or args
.revision
is not None:
330 parser
.error("chrome component cannot use version or revision")
332 parser
.error("plugin not recognized")
334 if args
.url
is not None:
337 if url_base
[-1] == "/":
338 url_base
= url_base
[:-1]
340 if args
.plugin
== "openh264":
341 json_result
= calculate_gmpopenh264_json(args
.version
, args
.revision
, url_base
)
342 elif args
.plugin
== "widevine":
343 json_result
= calculate_widevinecdm_json(args
.version
, url_base
)
344 elif args
.plugin
== "widevine_component":
345 json_result
= calculate_widevinecdm_component_json(url_base
)
346 elif args
.plugin
== "widevine_l1_component":
347 json_result
= calculate_widevinecdm_l1_component_json(url_base
)
350 json
.loads(json_result
)
351 except json
.JSONDecodeError
as e
:
352 logging
.error("invalid JSON produced: %s", e
)