Add PUT request support at /api/jobs/{job_id}/files to FastAPIJobFiles#20353
Add PUT request support at /api/jobs/{job_id}/files to FastAPIJobFiles#20353kysrpex wants to merge 5 commits intogalaxyproject:devfrom
/api/jobs/{job_id}/files to FastAPIJobFiles#20353Conversation
`FastAPIJobFiles` is the new, FastAPI version of `JobFilesAPIController`. The endpoints that have been migrated should exhibit exactly the same behavior as the old ones from `FastAPIJobFiles`. Something to keep in mind is that while FastAPI has some extra built-in features that the legacy WSGI system did not have, such as answering HEAD requests, those do not work because of the way legacy WSGI endpoints are injected into the FastAPI app (using `app.mount("/", wsgi_handler)`), meaning that for example, HEAD requests are passed to the `wsgi_handler` sub-application.
Endpoints dedicated to TUS uploads work in tandem with the WSGI middleware `TusMiddleware` from the `tuswsgi` package. As explained above, WSGI middlewares and endpoints are injected into the FastAPI app after FastAPI routes as a single sub-application `wsgi_handler` using `app.mount("/", wsgi_handler)`, meaning that requests are passed to the `wsgi_handler` sub-application (and thus to `TusMiddleware`) only if there was no FastAPI endpoint defined to handle them. Therefore, they cannot be migrated to FastAPI unless `TusMiddleware` is also migrated to ASGI.
Work around a bug in FastAPI (fastapi/fastapi#13175) that assigns the same operation id to both request methods GET and HEAD of the endpoint `/api/jobs/{job_id}/files` when using the `@router.api_route()` decorator with `methods=["GET", "HEAD"]` as keyword argument.
…T requests to `/api/jobs/{job_id}/files`
Pulsar formats the `path` and `job_key` parameters as query parameters when submitting POST requests to `/api/jobs/{job_id}/files`. However, many Galaxy tests format them as form parameters. The only way to keep the endpoint working as it should (as it worked before the migration to FastAPI) is to accept both query and form parameters.
… requests to `/api/jobs/{job_id}/files`
FastAPI will not use the parameter aliases of form parameters in the OpenAPI docs, but the name of their Python variables. Therefore, the API docs show `path_form` and `job_key_form`. Rename them so that the API docs show the correct parameter names.
…iles` This path already supports GET, HEAD and POST requests; add support for PUT requests. There is a significant difference in behavior between POST and PUT requests: - POST requests take `path` and `job_key` both as query parameters or as body parameters belonging to a multipart request. PUT requests take them only as query parameters (just like GET and HEAD). - POST requests submit a file as one of the fields of the multipart request, whereas the submitted file is the whole body of the request for PUT requests. - POST requests can append to the `tool_stdout` and `tool_stderr`, PUT requests can only create new files or overwrite whole files. - POST requests support resumable uploads but PUT requests do not. - POST requests take the form parameters `__file_path` (path of a file uploaded via the nginx upload module) and `__file` but PUT requests do not.
| "content": {"application/json": None, "application/octet-stream": {"example": None}}, | ||
| }, | ||
| 400: { | ||
| "description": ( |
Check failure
Code scanning / CodeQL
Uncontrolled data used in path expression High
| "File not found, path does not refer to a file, or input dataset(s) for job have been purged." | ||
| ) | ||
| }, | ||
| }, |
Check failure
Code scanning / CodeQL
Polynomial regular expression used on uncontrolled data High
| job = self.__authorize_job_access(trans, job_id, path=path, job_key=job_key) | ||
| self.__check_job_can_write_to_path(trans, job, path) | ||
|
|
||
| destination_file_exists = os.path.exists(path) |
Check failure
Code scanning / CodeQL
Uncontrolled data used in path expression High
| job = self.__authorize_job_access(trans, job_id, path=path, job_key=job_key) | ||
| self.__check_job_can_write_to_path(trans, job, path) | ||
|
|
||
| destination_file_exists = os.path.exists(path) |
Check failure
Code scanning / CodeQL
Uncontrolled data used in path expression High
| self.__check_job_can_write_to_path(trans, job, path) | ||
|
|
||
| destination_file_exists = os.path.exists(path) | ||
|
|
Check failure
Code scanning / CodeQL
Uncontrolled data used in path expression High
| destination_file_exists = os.path.exists(path) | ||
|
|
||
| # FastAPI can only read the file contents from the request body in an async context. To write the file without | ||
| # using an async endpoint, the async code that reads the file from the body and writes it to disk will have to |
Check failure
Code scanning / CodeQL
Uncontrolled data used in path expression High
| # `destination_file.write(chunk)`, it has to run on its own event loop within the thread spawned to answer the | ||
| # request to the sync endpoint. | ||
| async def write(): | ||
| with open(path, "wb") as destination_file: |
Check failure
Code scanning / CodeQL
Uncontrolled data used in path expression High
|
|
||
| target_dir = os.path.dirname(path) | ||
| util.safe_makedirs(target_dir) | ||
| event_loop = asyncio.new_event_loop() |
Check failure
Code scanning / CodeQL
Uncontrolled data used in path expression High
|
|
||
| target_dir = os.path.dirname(path) | ||
| util.safe_makedirs(target_dir) | ||
| event_loop = asyncio.new_event_loop() |
Check failure
Code scanning / CodeQL
Uncontrolled data used in path expression High
| util.safe_makedirs(target_dir) | ||
| event_loop = asyncio.new_event_loop() | ||
| try: | ||
| asyncio.set_event_loop(event_loop) |
Check failure
Code scanning / CodeQL
Uncontrolled data used in path expression High
|
@maikenp FYI |
This path already supports GET, HEAD and POST requests; add support for PUT requests. There is a significant difference in behavior between POST and PUT requests:
pathandjob_keyboth as query parameters or as body parameters belonging to a multipart request. PUT requests take them only as query parameters (just like GET and HEAD).tool_stdoutandtool_stderr, PUT requests can only create new files or overwrite whole files.__file_path(path of a file uploaded via the nginx upload module) and__filebut PUT requests do not.How to test the changes?
(Select all options that apply)
License