|
| 1 | +# Copyright 2020-2021 The MathWorks, Inc. |
| 2 | + |
| 3 | +import os, json, sys |
| 4 | +from json.decoder import JSONDecodeError |
| 5 | +from . import mw_logger |
| 6 | + |
| 7 | +logger = mw_logger.get() |
| 8 | + |
| 9 | + |
| 10 | +def get(): |
| 11 | + """Returns a dict containing custom http headers to inject into responses from the |
| 12 | + MATLAB Embedded Connector and to the static files in 'gui' folder. |
| 13 | +
|
| 14 | + Parses valid JSON data if provided as a string or in a JSON file. |
| 15 | +
|
| 16 | + Returns: |
| 17 | + Dict: Representing custom headers. |
| 18 | + """ |
| 19 | + env_var = __get_custom_header_env_var() |
| 20 | + # custom_headers_path can contain valid JSON data as a string or a path to a file containing valid JSON |
| 21 | + custom_headers_path = os.getenv(env_var) |
| 22 | + |
| 23 | + # If the environment variable is not present |
| 24 | + if custom_headers_path is None: |
| 25 | + logger.info( |
| 26 | + f"Environment variable {env_var} is not set, hence no custom HTTP headers are applied." |
| 27 | + ) |
| 28 | + return dict() |
| 29 | + |
| 30 | + logger.info( |
| 31 | + f"Envinronment variable {env_var} is set and has the value: {custom_headers_path}" |
| 32 | + ) |
| 33 | + is_file = os.path.isfile(custom_headers_path) |
| 34 | + |
| 35 | + if is_file and __check_file_validity(custom_headers_path): |
| 36 | + return __get_file_contents(custom_headers_path) |
| 37 | + |
| 38 | + else: |
| 39 | + exception_statement = __get_exception_statement() |
| 40 | + try: |
| 41 | + # Valid JSON data as a string |
| 42 | + data = json.loads(custom_headers_path) |
| 43 | + logger.info( |
| 44 | + f"Successfully parsed HTTP headers from the environment variable {env_var}\nThe parsed HTTP headers are:\n{data}\n" |
| 45 | + ) |
| 46 | + return data |
| 47 | + |
| 48 | + except JSONDecodeError as json_decode_error: |
| 49 | + # Invalid JSON data as a string. |
| 50 | + print( |
| 51 | + exception_statement.format( |
| 52 | + env_var=__get_custom_header_env_var(), |
| 53 | + env_var_value=custom_headers_path, |
| 54 | + ) |
| 55 | + ) |
| 56 | + logger.error( |
| 57 | + f"Failed with {type(json_decode_error).__name__} exception. Check the value in {env_var} environment variable for syntax errors." |
| 58 | + ) |
| 59 | + sys.exit(1) |
| 60 | + |
| 61 | + except Exception as e: |
| 62 | + print( |
| 63 | + exception_statement.format( |
| 64 | + env_var=__get_custom_header_env_var(), |
| 65 | + env_var_value=custom_headers_path, |
| 66 | + ) |
| 67 | + ) |
| 68 | + logger.error( |
| 69 | + f"Raised {type(e).__name__} exception when parsing JSON data in the environment variable {env_var}" |
| 70 | + ) |
| 71 | + sys.exit(1) |
| 72 | + |
| 73 | + |
| 74 | +def __check_file_validity(custom_headers_path): |
| 75 | + """Checks the file at custom_headers_path for the read access to the file for the current python process. |
| 76 | +
|
| 77 | + Args: |
| 78 | + custom_headers_path (String): File path of custom headers. |
| 79 | +
|
| 80 | + Raises: |
| 81 | + OSError: When the current python process doesn't have read access to the custom_headers_path |
| 82 | + """ |
| 83 | + exception_statement = __get_exception_statement() |
| 84 | + logger.debug( |
| 85 | + f"The value in environment variable {__get_custom_header_env_var()} contains a path to a file." |
| 86 | + ) |
| 87 | + try: |
| 88 | + if not os.access(custom_headers_path, os.R_OK): |
| 89 | + raise OSError |
| 90 | + |
| 91 | + logger.debug( |
| 92 | + f"Current python process has read access rights to the file at: {custom_headers_path}" |
| 93 | + ) |
| 94 | + return True |
| 95 | + |
| 96 | + except OSError as os_error: |
| 97 | + print( |
| 98 | + f"\n{type(os_error).__name__}: Permission denied. Cannot read file: {custom_headers_path}\n" |
| 99 | + + exception_statement.format( |
| 100 | + env_var=__get_custom_header_env_var(), |
| 101 | + env_var_value=custom_headers_path, |
| 102 | + ) |
| 103 | + ) |
| 104 | + logger.error( |
| 105 | + f"{type(os_error).__name__}: Permission denied. For the current python process, check read access rights for the file: {custom_headers_path}." |
| 106 | + ) |
| 107 | + sys.exit(1) |
| 108 | + |
| 109 | + except Exception as e: |
| 110 | + print( |
| 111 | + f"\n{type(e).__name__} exception raised with error message: {e.args}\n" |
| 112 | + + exception_statement.format( |
| 113 | + env_var=__get_custom_header_env_var(), |
| 114 | + env_var_value=custom_headers_path, |
| 115 | + ) |
| 116 | + ) |
| 117 | + logger.error( |
| 118 | + f"{type(e).__name__} exception raised when checking read access rights to the file at: {custom_headers_path}" |
| 119 | + ) |
| 120 | + sys.exit(1) |
| 121 | + |
| 122 | + |
| 123 | +def __get_file_contents(custom_headers_path): |
| 124 | + """Reads the file containing custom headers and returns a dict. |
| 125 | + Raises JSONDecodeError if the JSON data in the file is not valid. |
| 126 | +
|
| 127 | + Args: |
| 128 | + custom_headers_path (String): File path of custom headers. |
| 129 | +
|
| 130 | + Raises: |
| 131 | + JSONDecodeError: when the contents of the file containing custom headers |
| 132 | + does not have valid JSON data. |
| 133 | +
|
| 134 | + Returns: |
| 135 | + Dict: Containing custom headers. |
| 136 | + """ |
| 137 | + |
| 138 | + custom_headers = None |
| 139 | + exception_statement = __get_exception_statement() |
| 140 | + try: |
| 141 | + with open(custom_headers_path, "r") as json_file: |
| 142 | + custom_headers = json.load(json_file) |
| 143 | + logger.info( |
| 144 | + f"Successfully parsed HTTP headers present in the file: {custom_headers_path}" |
| 145 | + ) |
| 146 | + logger.debug(f"The parsed HTTP headers are :\n{custom_headers}\n") |
| 147 | + return custom_headers |
| 148 | + |
| 149 | + except JSONDecodeError as json_decode_error: |
| 150 | + print( |
| 151 | + f"\n{type(json_decode_error).__name__} exception raised with error message: {json_decode_error.args[0]}\n" |
| 152 | + + exception_statement.format( |
| 153 | + env_var=__get_custom_header_env_var(), |
| 154 | + env_var_value=custom_headers_path, |
| 155 | + ) |
| 156 | + ) |
| 157 | + logger.error( |
| 158 | + f"{type(json_decode_error).__name__}: Failed to parse JSON data in the file: {custom_headers_path}.\nCheck contents of the file for any syntax errors." |
| 159 | + ) |
| 160 | + sys.exit(1) |
| 161 | + |
| 162 | + except Exception as e: |
| 163 | + print( |
| 164 | + f"\nFailed with {type(e).__name__} exception with error message:\n{e.args}" |
| 165 | + + exception_statement.format( |
| 166 | + env_var=__get_custom_header_env_var(), |
| 167 | + env_var_value=custom_headers_path, |
| 168 | + ) |
| 169 | + ) |
| 170 | + logger.error( |
| 171 | + f"Failed with {type(e).__name__} when reading JSON data from the file: {custom_headers_path}" |
| 172 | + ) |
| 173 | + sys.exit(1) |
| 174 | + |
| 175 | + |
| 176 | +def __get_custom_header_env_var(): |
| 177 | + """Returns the name of the environment variable which contains path |
| 178 | + to the file containing custom headers. |
| 179 | +
|
| 180 | + Returns: |
| 181 | + String: Environment variable containing path to the file containing custom headers. |
| 182 | + """ |
| 183 | + return "CUSTOM_HTTP_HEADERS" |
| 184 | + |
| 185 | + |
| 186 | +def __get_exception_statement(): |
| 187 | + """Returns a generic exception statement pertaining to HTTP headers. |
| 188 | +
|
| 189 | + Returns: |
| 190 | + String: Containing a generic exception statement to print to stdout. |
| 191 | + """ |
| 192 | + exception_statement = """HTTP headers defined in the environment variable {env_var} are not valid.\n |
| 193 | + The value in {env_var} is: {env_var_value}\n |
| 194 | + Please provide either valid JSON data as a string or a path to a file with read access containing valid JSON data.""" |
| 195 | + |
| 196 | + return exception_statement |
0 commit comments