Skip to content

Commit

Permalink
redirect Execute POST XML on REST endpoint to WPS endpoint (resolves #…
Browse files Browse the repository at this point in the history
  • Loading branch information
fmigneault committed Aug 12, 2022
1 parent bc29cd7 commit ec2090c
Show file tree
Hide file tree
Showing 5 changed files with 50 additions and 8 deletions.
3 changes: 3 additions & 0 deletions CHANGES.rst
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,9 @@ Changes:
to `XML` Media-Type is identified in the request (resolves `#125 <https://github.com/crim-ca/weaver/issues/125>`_).
- Add support of ``f`` and ``format`` query parameters to describe a `Process` with `JSON` when requested from
the `WPS` endpoint with redirect to REST API URL (resolves `#125 <https://github.com/crim-ca/weaver/issues/125>`_).
- Add support of `Job` submission with `WPS`-like `XML` content and HTTP ``POST`` request directly submitted through
the `OGC APi - Processes` REST endpoint. Response is returned in `JSON` regardless of `WPS`-like `Job` submission
in order to provide the status response (resolves `#125 <https://github.com/crim-ca/weaver/issues/125>`_).

Fixes:
------
Expand Down
2 changes: 1 addition & 1 deletion weaver/formats.py
Original file line number Diff line number Diff line change
Expand Up @@ -663,7 +663,7 @@ def clean_mime_type_format(mime_type, suffix_subtype=False, strip_parameters=Fal


def guess_target_format(request, default=ContentType.APP_JSON):
# type: (AnyRequestType, str) -> str
# type: (AnyRequestType, Optional[Union[ContentType, str]]) -> ContentType
"""
Guess the best applicable response ``Content-Type`` header from the request.
Expand Down
2 changes: 1 addition & 1 deletion weaver/utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -1090,7 +1090,7 @@ def islambda(func):
def get_path_kvp(path, sep=",", **params):
# type: (str, str, **KVP_Item) -> str
"""
Generates the URL with Key-Value-Pairs (KVP) query parameters.
Generates the URL with Key-Value-Pairs (:term:`KVP`) query parameters.
:param path: WPS URL or Path
:param sep: separator to employ when multiple values are provided.
Expand Down
17 changes: 13 additions & 4 deletions weaver/wps_restapi/jobs/utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,7 @@
get_any_id,
get_any_value,
get_file_headers,
get_header,
get_path_kvp,
get_settings,
get_weaver_url,
Expand All @@ -63,6 +64,7 @@
AnyValueType,
ExecutionResultArray,
ExecutionResultObject,
ExecutionResultValue,
ExecutionResults,
HeadersTupleType,
JSON,
Expand Down Expand Up @@ -453,8 +455,8 @@ def get_job_results_response(job, container, headers=None):
# raw response can be data-only value, link-only or a mix of them
if results:
# https://docs.ogc.org/is/18-062r2/18-062r2.html#req_core_process-execute-sync-raw-value-one
out_vals = list(results.items())
out_info = out_vals[0][-1]
out_vals = list(results.items()) # type: List[Tuple[str, ExecutionResultValue]] # noqa
out_info = out_vals[0][-1] # type: ExecutionResultValue
out_type = get_any_value(out_info, key=True)
out_data = get_any_value(out_info)

Expand Down Expand Up @@ -502,6 +504,13 @@ def get_job_submission_response(body, headers, error=False):
:func:`weaver.processes.execution.submit_job`
:func:`weaver.processes.execution.submit_job_handler`
"""
# convert headers to pass as list to avoid any duplicate Content-related headers
# otherwise auto-added by JSON handling when provided by dict-like structure
if hasattr(headers, "items"):
headers = list(headers.items())
get_header("Content-Type", headers, pop=True)
headers.append(("Content-Type", ContentType.APP_JSON))

status = map_status(body.get("status"))
if status in JOB_STATUS_CATEGORIES[StatusCategory.FINISHED]:
if error:
Expand All @@ -513,11 +522,11 @@ def get_job_submission_response(body, headers, error=False):
body = sd.CompletedJobStatusSchema().deserialize(body)

body["description"] = http_desc
return http_class(json=body, headers=headers)
return http_class(json=body, headerlist=headers)

body["description"] = sd.CreatedLaunchJobResponse.description
body = sd.CreatedJobStatusSchema().deserialize(body)
return HTTPCreated(json=body, headers=headers)
return HTTPCreated(json=body, headerlist=headers)


def validate_service_process(request):
Expand Down
34 changes: 32 additions & 2 deletions weaver/wps_restapi/processes/processes.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,18 +13,35 @@
)
from pyramid.response import Response
from pyramid.settings import asbool
from werkzeug.wrappers.request import BaseRequest

from weaver.database import get_db
from weaver.exceptions import ProcessNotFound, ServiceException, log_unhandled_exceptions
from weaver.formats import ContentType, OutputFormat, add_content_type_charset, guess_target_format, repr_json
from weaver.formats import (
ContentType,
OutputFormat,
add_content_type_charset,
clean_mime_type_format,
guess_target_format,
repr_json
)
from weaver.processes import opensearch
from weaver.processes.constants import ProcessSchema
from weaver.processes.execution import submit_job
from weaver.processes.utils import deploy_process_from_payload, get_process, update_process_metadata
from weaver.status import Status
from weaver.store.base import StoreJobs, StoreProcesses
from weaver.utils import clean_json_text_body, fully_qualified_name, get_any_id
from weaver.utils import (
clean_json_text_body,
extend_instance,
fully_qualified_name,
get_any_id,
get_header,
get_path_kvp
)
from weaver.visibility import Visibility
from weaver.wps.service import get_pywps_service
from weaver.wps.utils import get_wps_path
from weaver.wps_restapi import swagger_definitions as sd
from weaver.wps_restapi.processes.utils import get_process_list_links, get_processes_filtered_by_valid_schemas
from weaver.wps_restapi.providers.utils import get_provider_services
Expand Down Expand Up @@ -328,4 +345,17 @@ def submit_local_job(request):
Execution location and method is according to deployed Application Package.
"""
process = get_process(request=request)
ctype = clean_mime_type_format(get_header("content-type", request.headers, default=None), strip_parameters=True)
if ctype in ContentType.ANY_XML:
# Send the XML request to the WPS endpoint which knows how to parse it properly.
# Execution will end up in the same 'submit_job_handler' function as other branch for JSON.
service = get_pywps_service()
wps_params = {"version": "1.0.0", "request": "Execute", "service": "WPS", "identifier": process.id}
request.path_info = get_wps_path(request)
request.query_string = get_path_kvp("", **wps_params)[1:]
location = request.application_url + request.path_info + request.query_string
LOGGER.warning("Route redirection [%s] -> [%s] for WPS-XML support.", request.url, location)
http_request = extend_instance(request, BaseRequest)
http_request.shallow = False
return service.call(http_request)
return submit_job(request, process, tags=["wps-rest"])

0 comments on commit ec2090c

Please sign in to comment.