src/server/util/util.c

changeset 693
b26cae13b79a
parent 660
f00d03835dd9
--- a/src/server/util/util.c	Sat Feb 21 14:40:03 2026 +0100
+++ b/src/server/util/util.c	Sat Feb 21 19:36:15 2026 +0100
@@ -1173,3 +1173,132 @@
     }
     return 0;
 }
+
+/* -------------------------- util_parse_http_uri -------------------------- */
+
+NSAPI_PUBLIC int util_parse_uri(const char *uri, WSUri *result) {
+    if(!uri) {
+        return 0;
+    }
+    return util_parse_uri_len(uri, strlen(uri), result);
+}
+ 
+NSAPI_PUBLIC int util_parse_uri_len(const char *uri, size_t length, WSUri *result) {
+    if(length == 0) {
+        return 0;
+    }
+    
+    memset(result, 0, sizeof(WSUri));
+    
+    // get uri scheme
+    int scheme = -1;
+    const char *scheme_str = uri;
+    size_t scheme_len = length;
+    short port = 0;
+    size_t i = 0;
+    for(;i<length;i++) {
+        if(uri[i] == ':') {
+            if(i+3 < length && uri[i+1] == '/' && uri[i+2] == '/') {
+                cxstring scheme_s = cx_strn(uri, i);
+                scheme_len = i;
+                if(!cx_strcmp(scheme_s, "http")) {
+                    scheme = WS_URI_HTTP;
+                    port = 80;
+                } else if(!cx_strcmp(scheme_s, "https")) {
+                    scheme = WS_URI_HTTPS;
+                    port = 443;
+                } else {
+                    scheme = WS_URI_OTHER;
+                }
+                i += 3;
+                break;
+            } else {
+                return 0; // invalid uri
+            }
+        }
+    }
+    result->scheme_num = scheme;
+    result->scheme = scheme_str;
+    result->schemelen = scheme_len;
+    
+    if(i == length) {
+        return 0; // invlid uri
+    }
+    
+    // get host
+    size_t hostlen = 0;
+    const char *port_str = NULL;
+    const char *path = NULL;
+    int is_ipv6_addr = 0;
+    size_t host_start = i;
+    if(uri[i] == '[') {
+        host_start++;
+        is_ipv6_addr = 1;
+        i++;
+    }
+    for(;i<length;i++) {
+        char c = uri[i];
+        if(is_ipv6_addr) {
+            if(c == ']') {
+                // end of ipv6 address
+                result->host = uri + host_start;
+                result->hostlen = i - host_start;
+                is_ipv6_addr = 0;
+                
+                // the next character must be a port or path separator
+                if(i+1 < length) {
+                    c = uri[i+1];
+                    if(c != '/' && c != ':') {
+                        return 0; // invalid uri
+                    }
+                } 
+            } else if(c != ':' && c != '.' && c != '%' && !isalnum(c)) {
+                return 0; // invalid ipv6 address
+            }
+        } else if(c == ':') {
+            if(port_str) {
+                return 0; // error: port was already specified
+            }
+            if(!result->host) {
+                result->host = uri + host_start;
+                result->hostlen = i - host_start;
+            }
+            // get port
+            port_str = uri + i + 1;
+        } else if(c == '/') {
+            path = uri + i;
+            break;
+        } else if(c == '[' || c == ']') {
+            return 0; // invalid hostname
+        }
+    }
+    if(is_ipv6_addr) {
+        return 0; // ipv6 address was not terminated
+    }
+    
+    if(port_str) {
+        size_t port_len = uri + i - port_str;
+        cxstring port_s = cx_strn(port_str, port_len);
+        if(cx_strtos(port_s, &port, 10)) {
+            return 0; // invalid port
+        }
+    }
+    if(!result->host) {
+        result->host = uri + host_start;
+        result->hostlen = i - host_start;
+    }
+    if(result->hostlen == 0) {
+        return 0;
+    }
+    
+    size_t pathlen = 0;
+    if(path) {
+        pathlen = uri + length - path;
+    }
+    
+    result->path = path;
+    result->pathlen = pathlen;
+    result->port = port;
+    
+    return 1;
+}

mercurial