On Sat, 17 Feb 2001, Martin Kraemer wrote:

> On Wed, Feb 14, 2001 at 07:56:05AM -0800, Jeffrey W. Baker wrote:
> > > It looks good, although in the line
> > >    29                     uptr->scheme = DEFAULT_URI_SCHEME;
> > > you assign to a "const" structure, and some compilers dislike that.
> > 
> > Ah, you are right I meant to remove that but my versions got out of sync.
> 
> Does that mean: your patch, minus exactly this one line?
> But that breaks the check for the default port further down.
> (uptr->port == ap_default_port_for_scheme(uptr->scheme)))
> although if no scheme is set, the port and per_str are probably
> unset as well?!
> 
> I am unsure, could you please re-submit the cleaned patch?

Attached.  I replaced the loop initializer with memset, and avoided
modifying the const argument by holding the scheme in a local
variable.  Passes local tests and mod_test_util_uri.c.

-jwb
Index: util_uri.c
===================================================================
RCS file: /home/cvspublic/apache-1.3/src/main/util_uri.c,v
retrieving revision 1.30
diff -u -r1.30 util_uri.c
--- util_uri.c  2001/02/17 14:07:04     1.30
+++ util_uri.c  2001/02/17 18:47:49
@@ -170,61 +170,118 @@
 
 /* Unparse a uri_components structure to an URI string.
  * Optionally suppress the password for security reasons.
+ * See also RFC 2396.
  */
 API_EXPORT(char *) ap_unparse_uri_components(pool *p,
                                              const uri_components * uptr,
                                              unsigned flags)
 {
-    char *ret = "";
-
-    /* If suppressing the site part, omit both user name & scheme://hostname */
+    char *parts[16];     /* 16 distinct parts of a URI */
+    char *scheme = NULL; /* to hold the scheme without modifying const args */
+    int j = 0;           /* an index into parts */
+    
+    memset(parts, 0, sizeof(parts));
+        
+    /* If suppressing the site part, omit all of scheme://user:pass@host:port */
     if (!(flags & UNP_OMITSITEPART)) {
 
-        /* Construct a "user:password@" string, honoring the passed UNP_ flags: */
-        if (uptr->user || uptr->password)
-            ret = ap_pstrcat(p,
-                             (uptr->user
-                              && !(flags & UNP_OMITUSER)) ? uptr->user : "",
-                             (uptr->password
-                              && !(flags & UNP_OMITPASSWORD)) ? ":" : "",
-                             (uptr->password && !(flags & UNP_OMITPASSWORD))
-                             ? ((flags & UNP_REVEALPASSWORD) ? uptr->
-                                password : "XXXXXXXX")
-                             : "", "@", NULL);
-
-        /* Construct scheme://site string */
-        if (uptr->hostname) {
-            int is_default_port;
-
-            is_default_port =
-                (uptr->port_str == NULL ||
-                 uptr->port == 0 ||
-                 uptr->port == ap_default_port_for_scheme(uptr->scheme));
-
-            ret = ap_pstrcat(p,
-                             uptr->scheme, "://", ret,
-                             uptr->hostname ? uptr->hostname : "",
-                             is_default_port ? "" : ":",
-                             is_default_port ? "" : uptr->port_str, NULL);
+        /* if the user passes in a scheme, we'll assume an absoluteURI */
+        if (uptr->scheme) {
+            scheme = uptr->scheme;
+            
+            parts[j++] = uptr->scheme;
+            parts[j++] = ":";
+        }
+        
+        /* handle the hier_part */
+        if (uptr->user || uptr->password || uptr->hostname) {
+            
+            /* this stuff requires absoluteURI, so we have to add the scheme */
+            if (!uptr->scheme) {
+                scheme = DEFAULT_URI_SCHEME;
+                
+                parts[j++] = DEFAULT_URI_SCHEME;
+                parts[j++] = ":";
+            }
+            
+            parts[j++] = "//";
+            
+            /* userinfo requires hostport */
+            if (uptr->hostname && (uptr->user || uptr->password)) {
+                if (uptr->user && !(flags & UNP_OMITUSER))
+                    parts[j++] = uptr->user;
+                
+                if (uptr->password && !(flags & UNP_OMITPASSWORD)) {
+                    parts[j++] = ":";
+
+                    if (flags & UNP_REVEALPASSWORD)
+                        parts[j++] = uptr->password;
+                    else
+                        parts[j++] = "XXXXXXXX";
+                }    
+
+                parts[j++] = "@";
+            }                
+            
+            /* If we get here, there must be a hostname. */
+            parts[j++] = uptr->hostname;
+            
+            /* Emit the port.  A small beautification
+             * prevents http://host:80/ and similar visual blight.
+             */
+            if (uptr->port_str &&
+                !(uptr->port   &&
+                  scheme       &&
+                  uptr->port == ap_default_port_for_scheme(scheme))) {
+
+                parts[j++] = ":";
+                parts[j++] = uptr->port_str;
+            }
         }
     }
-
-    /* Should we suppress all path info? */
+        
     if (!(flags & UNP_OMITPATHINFO)) {
-        /* Append path, query and fragment strings: */
-        ret = ap_pstrcat(p,
-                         ret,
-                         uptr->path ? uptr->path : "",
-                         (uptr->query && !(flags & UNP_OMITQUERY)) ? "?" : "",
-                         (uptr->query
-                          && !(flags & UNP_OMITQUERY)) ? uptr->query : "",
-                         (uptr->fragment
-                          && !(flags & UNP_OMITQUERY)) ? "#" : NULL,
-                         (uptr->fragment
-                          && !(flags & UNP_OMITQUERY)) ? uptr->
-                         fragment : NULL, NULL);
+        
+        
+        /* We must ensure we don't put out a hier_part and a rel_path */
+        if (j && uptr->path && *uptr->path != '/')
+            parts[j++] = "/";
+        
+        parts[j++] = uptr->path;
+
+        if (!(flags & UNP_OMITQUERY)) {
+            if (uptr->query) {
+                parts[j++] = "?";
+                parts[j++] = uptr->query;
+            }
+            
+            if (uptr->fragment) {
+                parts[j++] = "#";
+                parts[j++] = uptr->fragment;
+            }
+        }
     }
-    return ret;
+
+    /* Ugly, but correct and probably faster than ap_vsnprintf. */
+    return ap_pstrcat(p,
+        parts[0],
+        parts[1],
+        parts[2],
+        parts[3],
+        parts[4],
+        parts[5],
+        parts[6],
+        parts[7],
+        parts[8],
+        parts[9],
+        parts[10],
+        parts[11],
+        parts[12],
+        parts[13],
+        parts[14],
+        parts[15],
+        NULL
+    );
 }
 
 /* The regex version of parse_uri_components has the advantage that it is
Index: util_uri.h
===================================================================
RCS file: /home/cvspublic/apache-1.3/src/include/util_uri.h,v
retrieving revision 1.15
diff -u -r1.15 util_uri.h
--- util_uri.h  2001/01/15 17:04:41     1.15
+++ util_uri.h  2001/02/17 18:48:13
@@ -80,6 +80,8 @@
 #define        DEFAULT_SNEWS_PORT      563
 #define        DEFAULT_PROSPERO_PORT   1525    /* WARNING: conflict w/Oracle */
 
+#define DEFAULT_URI_SCHEME "http"
+
 /* Flags passed to unparse_uri_components(): */
 #define UNP_OMITSITEPART       (1U<<0) /* suppress "scheme://user@site:port" */
 #define        UNP_OMITUSER            (1U<<1) /* Just omit user */

Reply via email to