Skip to content

Commit

Permalink
fix PROV endpoints returning invalid double Content-Type headers
Browse files Browse the repository at this point in the history
  • Loading branch information
fmigneault committed Dec 21, 2024
1 parent dddcd7d commit 7a02f61
Show file tree
Hide file tree
Showing 4 changed files with 17 additions and 5 deletions.
4 changes: 3 additions & 1 deletion CHANGES.rst
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,9 @@ Changes:

Fixes:
------
- No change.
- Fix ``PROV`` endpoints returning multiple ``Content-Type`` headers
(default ``text/html`` inserted by ``webob.response.Response`` class onto top of the explicit one specified)
leading to inconsistent responses parsing and rendering across clients.

.. _changes_6.1.0:

Expand Down
11 changes: 11 additions & 0 deletions tests/functional/test_job_provenance.py
Original file line number Diff line number Diff line change
Expand Up @@ -99,6 +99,7 @@ def test_job_prov_json(self, queries, headers):
prov_url = f"{self.job_url}/prov"
resp = self.app.get(prov_url, params=queries, headers=headers)
assert resp.status_code == 200
assert len(list(filter(lambda header: header[0] == "Content-Type", resp.headerlist))) == 1
assert resp.content_type == ContentType.APP_JSON
prov = resp.json
assert "prefix" in prov
Expand All @@ -113,6 +114,7 @@ def test_job_prov_xml(self, queries, headers):
prov_url = f"{self.job_url}/prov"
resp = self.app.get(prov_url, params=queries, headers=headers)
assert resp.status_code == 200
assert len(list(filter(lambda header: header[0] == "Content-Type", resp.headerlist))) == 1
assert resp.content_type in ContentType.ANY_XML
prov = resp.text
assert "<prov:document xmlns:wfprov" in prov
Expand All @@ -121,6 +123,7 @@ def test_job_prov_ttl(self):
prov_url = f"{self.job_url}/prov"
resp = self.app.get(prov_url, headers={"Accept": ContentType.TEXT_TURTLE})
assert resp.status_code == 200
assert len(list(filter(lambda header: header[0] == "Content-Type", resp.headerlist))) == 1
assert resp.content_type == ContentType.TEXT_TURTLE
prov = resp.text
assert "@prefix cwlprov: " in prov
Expand All @@ -129,6 +132,7 @@ def test_job_prov_nt(self):
prov_url = f"{self.job_url}/prov"
resp = self.app.get(prov_url, headers={"Accept": ContentType.APP_NT})
assert resp.status_code == 200
assert len(list(filter(lambda header: header[0] == "Content-Type", resp.headerlist))) == 1
assert resp.content_type == ContentType.APP_NT
prov = resp.text
assert "_:N" in prov
Expand All @@ -138,6 +142,7 @@ def test_job_prov_provn(self):
prov_url = f"{self.job_url}/prov"
resp = self.app.get(prov_url, headers={"Accept": ContentType.TEXT_PROVN})
assert resp.status_code == 200
assert len(list(filter(lambda header: header[0] == "Content-Type", resp.headerlist))) == 1
assert resp.content_type == ContentType.TEXT_PROVN
prov = resp.text
assert "prov:type='wfprov:WorkflowEngine'" in prov
Expand All @@ -147,6 +152,7 @@ def test_job_prov_info_text(self):
job_id = self.job_url.rsplit("/", 1)[-1]
resp = self.app.get(prov_url, headers={"Accept": ContentType.TEXT_PLAIN})
assert resp.status_code == 200
assert len(list(filter(lambda header: header[0] == "Content-Type", resp.headerlist))) == 1
assert resp.content_type == ContentType.TEXT_PLAIN
prov = resp.text
assert f"Workflow run ID: urn:uuid:{job_id}" in prov
Expand All @@ -161,6 +167,7 @@ def test_job_prov_info_not_acceptable(self):
headers = self.json_headers # note: this is the test, while only plain text is supported
resp = self.app.get(f"{prov_url}/info", headers=headers, expect_errors=True)
assert resp.status_code == 406
assert len(list(filter(lambda header: header[0] == "Content-Type", resp.headerlist))) == 1
assert resp.content_type == ContentType.APP_JSON, (
"error should be in JSON regardless of Accept header or the normal contents media-type"
)
Expand All @@ -176,6 +183,8 @@ def test_job_prov_commands(self, path, cmd):
proc_url = f"/{path}/{self.proc_id}" if path == "processes" else ""
prov_url = f"{proc_url}/jobs/{job_id}/prov/{cmd}"
resp = self.app.get(prov_url, headers={"Accept": ContentType.TEXT_PLAIN})
assert resp.status_code == 200
assert len(list(filter(lambda header: header[0] == "Content-Type", resp.headerlist))) == 1
assert resp.content_type == ContentType.TEXT_PLAIN
assert resp.text != ""

Expand All @@ -194,6 +203,8 @@ def test_job_prov_run_id(self, path):
job_id = self.job_url.rsplit("/", 1)[-1]
prov_url = f"{self.job_url}/prov/{path}/{job_id}"
resp = self.app.get(prov_url, headers={"Accept": ContentType.TEXT_PLAIN})
assert resp.status_code == 200
assert len(list(filter(lambda header: header[0] == "Content-Type", resp.headerlist))) == 1
assert resp.content_type == ContentType.TEXT_PLAIN
assert resp.text != ""

Expand Down
2 changes: 1 addition & 1 deletion weaver/datatype.py
Original file line number Diff line number Diff line change
Expand Up @@ -1507,7 +1507,7 @@ def prov_path(self, container=None, extra_path=None, prov_format=None):
def prov_data(
self,
container=None, # type: Optional[AnySettingsContainer]
extra_path=None, # type: Optional[ProvenancePathType]
extra_path=None, # type: Optional[Union[ProvenancePathType, str]]
prov_format=None, # type: AnyContentType
): # type: (...) -> Tuple[Optional[str], Optional[AnyContentType]]
"""
Expand Down
5 changes: 2 additions & 3 deletions weaver/wps_restapi/jobs/utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -1451,8 +1451,7 @@ def get_job_prov_response(request):
prov_body["error"] = "No such run ID for specified job provenance."
prov_body["value"] = {"run_id": str(request.matchdict["run_id"])}
prov_body["status"] = prov_err.code
return prov_err(json=prov_body, headers={"Content-Type": ContentType.APP_JSON})
return prov_err(json=prov_body, content_type=ContentType.APP_JSON)
links = job.links(container=request, self_link="provenance")
headers = [("Link", make_link_header(link)) for link in links]
headers.append(("Content-Type", prov_type))
return HTTPOk(body=prov_data, headers=headers)
return HTTPOk(body=prov_data, headers=headers, content_type=prov_type, charset="utf-8")

0 comments on commit 7a02f61

Please sign in to comment.