On Tuesday 01 August 2006 10:07, david reid wrote:
> Having looked at these, they're small and self contained and would seem
> to be a good fit for apr-util. Question is where/how would they go in?

+1 in principle, and I agree apr_uri is not a great match.
Maybe it would fit as a new apr_uriencode source file in the /uri/ directory?

> Once we have an answer I'll submit a patch :-)

Which reminds me, support for *relative* URLs still isn't in apr_uri,
and I've been shipping it separately for years in apps that need it.
Anyone object to the attached patch going in?

-- 
Nick Kew
Index: uri/apr_uri.c
===================================================================
--- uri/apr_uri.c	(revision 427512)
+++ uri/apr_uri.c	(working copy)
@@ -460,3 +460,93 @@
     }
     return APR_EGENERAL;
 }
+
+/* Resolve relative to a base.  This means host/etc, and (crucially) path */
+APU_DECLARE(int) apr_uri_resolve_relative(apr_pool_t* pool,
+                                          const apr_uri_t* base,
+                                          apr_uri_t* uptr)
+{
+    if (uptr == NULL || base == NULL || ! base->is_initialized
+        || ! uptr->is_initialized) {
+        return APR_EGENERAL;
+    }
+    /* The interesting bit is the path.  */
+    if (uptr->path == NULL) {
+        if (uptr->hostname == NULL) {
+            /* is this compatible with is_initialised?  Harmless in any case */
+            uptr->path = base->path ? base->path : apr_pstrdup(pool, "/") ;
+        }
+        else {
+            /* deal with the idiosyncracy of APR allowing path==NULL
+             * without risk of breaking back-compatibility
+             */
+            uptr->path = apr_pstrdup(pool, "/") ;
+        }
+    }
+    else if (uptr->path[0] != '/') {
+        size_t baselen;
+        const char* basepath = base->path ? base->path :"/";
+        const char* path = uptr->path;
+        const char* base_end = strrchr(basepath, '/');
+
+        /* if base is nonsensical, bail out */
+        if (basepath[0] != '/') {
+            return APR_EGENERAL;
+        }
+        /* munch "up" components at the start, and chop them from base path */
+        while (!strncmp(path, "../", 3)) {
+            while (base_end > basepath) {
+                if (*--base_end == '/') {
+                    break;
+                }
+            }
+            path += 3;
+        }
+        /* munch "here" components at the start */
+        while (!strncmp(path, "./", 2)) {
+            path += 2;
+        }
+        baselen = base_end-basepath+1;
+        uptr->path = apr_palloc(pool, baselen + strlen(path) + 1 );
+        memcpy(uptr->path, basepath, baselen);
+        strcpy(uptr->path+baselen, path);
+    }
+
+    /* The trivial bits are everything-but-path */
+    if (uptr->scheme == NULL) {
+        uptr->scheme = base->scheme;
+    }
+    if (uptr->hostinfo == NULL) {
+        uptr->hostinfo = base->hostinfo;
+    }
+    if (uptr->user == NULL) {
+        uptr->user = base->user;
+    }
+    if (uptr->password == NULL) {
+        uptr->password = base->password;
+    }
+    if (uptr->hostname == NULL) {
+        uptr->hostname = base->hostname;
+    }
+    if (uptr->port_str == NULL) {
+        uptr->port_str = base->port_str;
+    }
+    if (uptr->hostent == NULL) {
+        uptr->hostent = base->hostent;
+    }
+    if (!uptr->port) {
+        uptr->port = base->port;
+    }
+    return APR_SUCCESS ;
+}
+APU_DECLARE(int) apr_uri_parse_relative(apr_pool_t* p,
+                                        const apr_uri_t* base,
+                                        const char* uri,
+                                        apr_uri_t* uptr)
+{
+    int ret = apr_uri_parse(p, uri, uptr) ;
+    if (ret != APR_SUCCESS) {
+        return ret;
+    }
+    return apr_uri_resolve_relative(p, base, uptr);
+}
Index: include/apr_uri.h
===================================================================
--- include/apr_uri.h	(revision 427512)
+++ include/apr_uri.h	(working copy)
@@ -160,6 +160,37 @@
                                         apr_uri_t *uptr);
 
 /**
+ * Resolve a (possibly-relative) URI against a given base URI.
+ * Fill in all supplied fields of a apr_uri_t structure.
+ * This eliminates the necessity of extracting host, port,
+ * path, query info repeatedly in the modules.
+ * @param p The pool to allocate out of
+ * @param base The base URI to parse against
+ * @param uptr The apr_uri_t to fill out any unset fields of
+ * @return APR_SUCCESS for success or error code
+ */
+APU_DECLARE(apr_status_t) apr_uri_resolve_relative(apr_pool_t *p,
+                                                   const apr_uri_t *base,
+                                                   apr_uri_t *uptr);
+
+/**
+ * Parse a given URI relative to a given base URI.
+ * Fill in all supplied fields of a apr_uri_t structure.
+ * This eliminates the necessity of extracting host, port,
+ * path, query info repeatedly in the modules.
+ * @param p The pool to allocate out of
+ * @param base The base URI to parse against
+ * @param uri The uri to parse
+ * @param uptr The apr_uri_t to fill out
+ * @return APR_SUCCESS for success or error code
+ */
+APU_DECLARE(apr_status_t) apr_uri_parse_relative(apr_pool_t *p,
+                                                 const apr_uri_t *base,
+                                                 const char* uri,
+                                                 apr_uri_t* uptr);
+
+
+/**
  * Special case for CONNECT parsing: it comes with the hostinfo part only
  * @param p The pool to allocate out of
  * @param hostinfo The hostinfo string to parse

Reply via email to