1 /* MIT License 2 * 3 * Copyright (c) 2024 Brad House 4 * 5 * Permission is hereby granted, free of charge, to any person obtaining a copy 6 * of this software and associated documentation files (the "Software"), to deal 7 * in the Software without restriction, including without limitation the rights 8 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 * copies of the Software, and to permit persons to whom the Software is 10 * furnished to do so, subject to the following conditions: 11 * 12 * The above copyright notice and this permission notice (including the next 13 * paragraph) shall be included in all copies or substantial portions of the 14 * Software. 15 * 16 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 22 * SOFTWARE. 23 * 24 * SPDX-License-Identifier: MIT 25 */ 26 #ifndef __ARES_URI_H 27 #define __ARES_URI_H 28 29 /*! \addtogroup ares_uri URI parser and writer implementation 30 * 31 * This is a fairly complete URI parser and writer implementation (RFC 3986) for 32 * schemes which use the :// syntax. Does not currently support URIs without an 33 * authority section, such as "mailto:person@example.com". 34 * 35 * Its implementation is overkill for our current needs to be able to express 36 * DNS server configuration, but there was really no reason not to support 37 * a greater subset of the specification. 38 * 39 * @{ 40 */ 41 42 43 struct ares_uri; 44 45 /*! URI object */ 46 typedef struct ares_uri ares_uri_t; 47 48 /*! Create a new URI object 49 * 50 * \return new ares_uri_t, must be freed with ares_uri_destroy() 51 */ 52 ares_uri_t *ares_uri_create(void); 53 54 /*! Destroy an initialized URI object 55 * 56 * \param[in] uri Initialized URI object 57 */ 58 void ares_uri_destroy(ares_uri_t *uri); 59 60 /*! Set the URI scheme. Automatically lower-cases the scheme provided. 61 * Only allows Alpha, Digit, +, -, and . characters. Maximum length is 62 * 15 characters. This is required to be set to write a URI. 63 * 64 * \param[in] uri Initialized URI object 65 * \param[in] scheme Scheme to set the object to use 66 * \return ARES_SUCCESS on success 67 */ 68 ares_status_t ares_uri_set_scheme(ares_uri_t *uri, const char *scheme); 69 70 /*! Retrieve the currently configured URI scheme. 71 * 72 * \param[in] uri Initialized URI object 73 * \return string containing URI scheme 74 */ 75 const char *ares_uri_get_scheme(const ares_uri_t *uri); 76 77 /*! Set the username in the URI object 78 * 79 * \param[in] uri Initialized URI object 80 * \param[in] username Username to set. May be NULL to unset existing username. 81 * \return ARES_SUCCESS on success 82 */ 83 ares_status_t ares_uri_set_username(ares_uri_t *uri, const char *username); 84 85 /*! Retrieve the currently configured username. 86 * 87 * \param[in] uri Initialized URI object 88 * \return string containing username, maybe NULL if not set. 89 */ 90 const char *ares_uri_get_username(const ares_uri_t *uri); 91 92 /*! Set the password in the URI object 93 * 94 * \param[in] uri Initialized URI object 95 * \param[in] password Password to set. May be NULL to unset existing password. 96 * \return ARES_SUCCESS on success 97 */ 98 ares_status_t ares_uri_set_password(ares_uri_t *uri, const char *password); 99 100 /*! Retrieve the currently configured password. 101 * 102 * \param[in] uri Initialized URI object 103 * \return string containing password, maybe NULL if not set. 104 */ 105 const char *ares_uri_get_password(const ares_uri_t *uri); 106 107 /*! Set the host or ip address in the URI object. This is required to be 108 * set to write a URI. The character set is strictly validated. 109 * 110 * \param[in] uri Initialized URI object 111 * \param[in] host IPv4, IPv6, or hostname to set. 112 * \return ARES_SUCCESS on success 113 */ 114 ares_status_t ares_uri_set_host(ares_uri_t *uri, const char *host); 115 116 /*! Retrieve the currently configured host (or ip address). IPv6 addresses 117 * May include a link-local scope (e.g. fe80::b542:84df:1719:65e3%en0). 118 * 119 * \param[in] uri Initialized URI object 120 * \return string containing host, maybe NULL if not set. 121 */ 122 const char *ares_uri_get_host(const ares_uri_t *uri); 123 124 /*! Set the port to use in the URI object. A port value of 0 will omit 125 * the port from the URI when written, thus using the scheme's default. 126 * 127 * \param[in] uri Initialized URI object 128 * \param[in] port Port to set. Use 0 to unset. 129 * \return ARES_SUCCESS on success 130 */ 131 ares_status_t ares_uri_set_port(ares_uri_t *uri, unsigned short port); 132 133 /*! Retrieve the currently configured port 134 * 135 * \param[in] uri Initialized URI object 136 * \return port number, or 0 if not set. 137 */ 138 unsigned short ares_uri_get_port(const ares_uri_t *uri); 139 140 /*! Set the path in the URI object. Unsupported characters will be URI-encoded 141 * when written. 142 * 143 * \param[in] uri Initialized URI object 144 * \param[in] path Path to set. May be NULL to unset existing path. 145 * \return ARES_SUCCESS on success 146 */ 147 ares_status_t ares_uri_set_path(ares_uri_t *uri, const char *path); 148 149 /*! Retrieves the path in the URI object. If retrieved after parse, this 150 * value will be URI-decoded already. 151 * 152 * \param[in] uri Initialized URI object 153 * \return path string, or NULL if not set. 154 */ 155 const char *ares_uri_get_path(const ares_uri_t *uri); 156 157 /*! Set a new query key/value pair. There is no set order for query keys 158 * when output in the URI, they will be emitted in a random order. Keys are 159 * case-insensitive. Query keys and values will be automatically URI-encoded 160 * when written. 161 * 162 * \param[in] uri Initialized URI object 163 * \param[in] key Query key to use, must be non-zero length. 164 * \param[in] val Query value to use, may be NULL. 165 * \return ARES_SUCCESS on success 166 */ 167 ares_status_t ares_uri_set_query_key(ares_uri_t *uri, const char *key, 168 const char *val); 169 170 /*! Delete a specific query key. 171 * 172 * \param[in] uri Initialized URI object 173 * \param[in] key Key to delete. 174 * \return ARES_SUCCESS if deleted, ARES_ENOTFOUND if not found 175 */ 176 ares_status_t ares_uri_del_query_key(ares_uri_t *uri, const char *key); 177 178 /*! Retrieve the value associated with a query key. Keys are case-insensitive. 179 * 180 * \param[in] uri Initialized URI object 181 * \param[in] key Key to retrieve. 182 * \return string representing value, may be NULL if either not found or 183 * NULL value set. There is currently no way to indicate the 184 * difference. 185 */ 186 const char *ares_uri_get_query_key(const ares_uri_t *uri, const char *key); 187 188 /*! Retrieve a complete list of query keys. 189 * 190 * \param[in] uri Initialized URI object 191 * \param[out] num Number of keys. 192 * \return NULL on failure or no keys. Use 193 * ares_free_array(keys, num, ares_free) when done with array. 194 */ 195 char **ares_uri_get_query_keys(const ares_uri_t *uri, size_t *num); 196 197 /*! Set the fragment in the URI object. Unsupported characters will be 198 * URI-encoded when written. 199 * 200 * \param[in] uri Initialized URI object 201 * \param[in] fragment Fragment to set. May be NULL to unset existing fragment. 202 * \return ARES_SUCCESS on success 203 */ 204 ares_status_t ares_uri_set_fragment(ares_uri_t *uri, const char *fragment); 205 206 /*! Retrieves the fragment in the URI object. If retrieved after parse, this 207 * value will be URI-decoded already. 208 * 209 * \param[in] uri Initialized URI object 210 * \return fragment string, or NULL if not set. 211 */ 212 const char *ares_uri_get_fragment(const ares_uri_t *uri); 213 214 /*! Parse the provided URI buffer into a new URI object. 215 * 216 * \param[out] out Returned new URI object. free with ares_uri_destroy(). 217 * \param[in] buf Buffer object containing the URI 218 * \return ARES_SUCCESS on successful parse. On failure the 'buf' object will 219 * be restored to its initial state in case another parser needs to 220 * be attempted. 221 */ 222 ares_status_t ares_uri_parse_buf(ares_uri_t **out, ares_buf_t *buf); 223 224 /*! Parse the provided URI string into a new URI object. 225 * 226 * \param[out] out Returned new URI object. free with ares_uri_destroy(). 227 * \param[in] uri URI string to parse 228 * \return ARES_SUCCESS on successful parse 229 */ 230 ares_status_t ares_uri_parse(ares_uri_t **out, const char *uri); 231 232 /*! Write URI object to a new string buffer. Requires at least the scheme 233 * and host to be set for this to succeed. 234 * 235 * \param[out] out Returned new URI string. Free with ares_free(). 236 * \param[in] uri Initialized URI object. 237 * \return ARES_SUCCESS on successful write. 238 */ 239 ares_status_t ares_uri_write(char **out, const ares_uri_t *uri); 240 241 /*! Write URI object to an existing ares_buf_t object. Requires at least the 242 * scheme and host to be set for this to succeed. 243 * 244 * \param[in] uri Initialized URI object. 245 * \param[in,out] buf Destination buf object. 246 * \return ARES_SUCCESS on successful write. 247 */ 248 ares_status_t ares_uri_write_buf(const ares_uri_t *uri, ares_buf_t *buf); 249 250 /*! @} */ 251 252 #endif /* __ARES_URI_H */ 253