Skip to content
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
41 changes: 41 additions & 0 deletions src/ogd/apis/utils/APIUtils.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
from json.decoder import JSONDecodeError
from logging import Logger
from typing import Any, List, Optional
from urllib import parse

# import OGD libraries
from ogd.common.storage.interfaces.Interface import Interface
Expand Down Expand Up @@ -42,6 +43,46 @@ def parse_list(list_str:str, logger:Optional[Logger]=None) -> Optional[List[Any]
ret_val = None
return ret_val

def urljoin(base:str, url:str, ignore_base_file:bool=False, allow_fragments:bool=True):
"""Custom variation of the `urllib.parse.urljoin` function provided by Python.

By default, this version allows filenames in the base path to remain in the joined path.

This is useful for working with Flask apps, particularly on Apache.
Specifically, unless you alias things in Apache, you'll have `app.py` or `app.wsgi` in the URL.
For a Flask API, then, you'll likely be joining a base URL like `"https://host.of.app/path/to/app.wsgi"` with an endpoint, call it `"endpoint"`.
Under `urllib.parse.urljoin`, you'll get `"https://host.of.app/path/to/endpoint"`.
With _this_ function, setting `ignore_base_file=False`, you'll get `"http://host.of.app/path/to/app.wsgi/endpoint"` as desired.

When `ignore_base_file=True`, this function directly falls back to use `urllib.parse.urljoin`.

:param base: The base URL, onto which the `url` parameter is joined.
:type base: str
:param url: The URL to be joined onto the given base URL.
:type url: str
:param ignore_base_file: Whether to ignore filenames in the base URL.
When True, such filenames are removed from the joined URL.
For example, joining `https://host.of.app/path/to/app.wsgi` with `endpoint` would yield `https://host.of.app/path/to/endpoint`.
When False, such filenames are included in the joined URL.
:type ignore_base_file: bool
:param allow_fragments: Whether to allow fragment parts in the URLs.
This is only used when `ignore_base_file=True`, in which case this function falls back on `urllib.parse.urljoin` and `allow_fragments` is passed to that function call.
:type ignore_base_file: bool
"""
if ignore_base_file:
return parse.urljoin(base=base, url=url, allow_fragments=allow_fragments)
else:
# Make sure we have a scheme
if not (base.startswith("http://") or base.startswith("https://")):
base = f"https://{base}"
# If base ends with a /, remove it so we don't double-up when joining
if base.endswith("/"):
base = base[:-1]
# If url starts with a /, remove it so we don't double-up when joining
if url.startswith("/"):
url = url[1:]
return f"{base}/{url}"

# def gen_interface(game_id, core_config:ConfigSchema, logger:Optional[Logger]=None) -> Optional[Interface]:
# """Utility to set up an Interface object for use by the API, given a game_id.

Expand Down
Loading