]> mj.ucw.cz Git - libucw.git/blobdiff - lib/url.c
Some Perl modules have moved to UCW namespace.
[libucw.git] / lib / url.c
index 105c7dd019e9f9d3c2de55a711b5cbd6eba390f8..8f1a435bb241fa2c4592f5f6d93e545baa10d2ef 100644 (file)
--- a/lib/url.c
+++ b/lib/url.c
@@ -1,8 +1,8 @@
 /*
- *     Sherlock Library -- URL Functions
+ *     UCW Library -- URL Functions
  *
  *     (c) 1997--2004 Martin Mares <mj@ucw.cz>
- *     (c) 2001 Robert Spalek <robert@ucw.cz>
+ *     (c) 2001--2005 Robert Spalek <robert@ucw.cz>
  *
  *     This software may be freely distributed and used according to the terms
  *     of the GNU Lesser General Public License.
@@ -11,9 +11,8 @@
  *
  *        o  Escaping of special characters still follows RFC 1738.
  *        o  Interpretation of path parameters follows RFC 1808.
- *        o  Parsing a relative URL "x" wrt. base "http://hell.org?y"
- *           gives an error, which might be wrong. However, I failed
- *           to find any rule applying to this case in the RFC.
+ *
+ *     XXX: The buffer handling in this module is really horrible, but it works.
  */
 
 #include "lib/lib.h"
 
 static uns url_ignore_spaces;
 static uns url_ignore_underflow;
-static byte *url_component_separators = "";
+static char *url_component_separators = "";
 static uns url_min_repeat_count = 0x7fffffff;
 static uns url_max_repeat_length = 0;
 
-static struct cfitem url_config[] = {
-  { "URL",                             CT_SECTION,     NULL },
-  { "IgnoreSpaces",                    CT_INT,         &url_ignore_spaces },
-  { "IgnoreUnderflow",                 CT_INT,         &url_ignore_underflow },
-  { "ComponentSeparators",             CT_STRING,      &url_component_separators },
-  { "MinRepeatCount",                  CT_INT,         &url_min_repeat_count },
-  { "MaxRepeatLength",                 CT_INT,         &url_max_repeat_length },
-  { NULL,                              CT_STOP,        NULL }
+static struct cf_section url_config = {
+  CF_ITEMS {
+    CF_UNS("IgnoreSpaces", &url_ignore_spaces),
+    CF_UNS("IgnoreUnderflow", &url_ignore_underflow),
+    CF_STRING("ComponentSeparators", &url_component_separators),
+    CF_UNS("MinRepeatCount", &url_min_repeat_count),
+    CF_UNS("MaxRepeatLength", &url_max_repeat_length),
+    CF_END
+  }
 };
 
 static void CONSTRUCTOR url_init_config(void)
 {
-  cf_register(url_config);
+  cf_declare_section("URL", &url_config, 0);
 }
 
 /* Escaping and de-escaping */
@@ -58,7 +58,7 @@ enhex(uns x)
 }
 
 int
-url_deescape(byte *s, byte *d)
+url_deescape(const byte *s, byte *d)
 {
   byte *dstart = d;
   byte *end = d + MAX_URL_SIZE - 10;
@@ -100,7 +100,7 @@ url_deescape(byte *s, byte *d)
        *d++ = *s++;
       else if (Cspace(*s))
        {
-         byte *s0 = s;
+         const byte *s0 = s;
          while (Cspace(*s))
            s++;
          if (!url_ignore_spaces || !(!*s || d == dstart))
@@ -121,7 +121,7 @@ url_deescape(byte *s, byte *d)
 }
 
 int
-url_enescape(byte *s, byte *d)
+url_enescape(const byte *s, byte *d)
 {
   byte *end = d + MAX_URL_SIZE - 10;
   unsigned int c;
@@ -150,13 +150,36 @@ url_enescape(byte *s, byte *d)
   return 0;
 }
 
+int
+url_enescape_friendly(const byte *src, byte *dest)
+{
+  byte *end = dest + MAX_URL_SIZE - 10;
+  while (*src)
+    {
+      if (dest >= end)
+       return URL_ERR_TOO_LONG;
+      if (*src < NCC_MAX)
+       *dest++ = NCC_CHARS[*src++];
+      else if (*src >= 0x20 && *src < 0x7f)
+       *dest++ = *src++;
+      else
+       {
+         *dest++ = '%';
+         *dest++ = enhex(*src >> 4);
+         *dest++ = enhex(*src++ & 0x0f);
+       }
+    }
+  *dest = 0;
+  return 0;
+}
+
 /* Split an URL (several parts may be copied to the destination buffer) */
 
 byte *url_proto_names[URL_PROTO_MAX] = URL_PNAMES;
 static int url_proto_path_flags[URL_PROTO_MAX] = URL_PATH_FLAGS;
 
 uns
-identify_protocol(byte *p)
+identify_protocol(const byte *p)
 {
   uns i;
 
@@ -202,18 +225,28 @@ url_split(byte *s, struct url *u, byte *d)
     {
       if (s[1] == '/')                 /* Host spec */
        {
-         byte *q, *w, *e;
+         byte *q, *e;
+         byte *at = NULL;
          char *ep;
 
          s += 2;
          q = d;
          while (*s && *s != '/' && *s != '?')  /* Copy user:passwd@host:port */
-           *d++ = *s++;
+           {
+             if (*s != '@')
+               *d++ = *s;
+             else if (!at)
+               {
+                 *d++ = 0;
+                 at = d;
+               }
+             else                      /* This shouldn't happen with sane URL's, but we need to be sure */
+               *d++ = NCC_AT;
+             s++;
+           }
          *d++ = 0;
-         w = strchr(q, '@');
-         if (w)                        /* user:passwd present */
+         if (at)                       /* user:passwd present */
            {
-             *w++ = 0;
              u->user = q;
              if (e = strchr(q, ':'))
                {
@@ -222,8 +255,8 @@ url_split(byte *s, struct url *u, byte *d)
                }
            }
          else
-           w = q;
-         e = strchr(w, ':');
+           at = q;
+         e = strchr(at, ':');
          if (e)                        /* host:port present */
            {
              uns p;
@@ -234,7 +267,7 @@ url_split(byte *s, struct url *u, byte *d)
              else if (p)               /* Port 0 (e.g. in :/) is treated as default port */
                u->port = p;
            }
-         u->host = w;
+         u->host = at;
        }
     }
 
@@ -369,8 +402,7 @@ url_normalize(struct url *u, struct url *b)
   int err;
 
   /* Basic checks */
-  if (url_proto_path_flags[u->protoid] && !u->host ||
-      u->host && !*u->host ||
+  if (url_proto_path_flags[u->protoid] && (!u->host || !*u->host) ||
       !u->host && u->user ||
       !u->user && u->pass ||
       !u->rest)
@@ -396,6 +428,18 @@ url_normalize(struct url *u, struct url *b)
        }
     }
 
+  /* Change path "?" to "/?" because it's the true meaning */
+  if (u->rest[0] == '?')
+    {
+      int l = strlen(u->rest);
+      if (u->bufend - u->buf < l+1)
+       return URL_ERR_TOO_LONG;
+      u->buf[0] = '/';
+      memcpy(u->buf+1, u->rest, l+1);
+      u->rest = u->buf;
+      u->buf += l+2;
+    }
+
   /* Fill in missing info */
   if (u->port == ~0U)
     u->port = std_ports[u->protoid];
@@ -448,7 +492,7 @@ url_canonicalize(struct url *u)
 /* Pack a broken-down URL */
 
 static byte *
-append(byte *d, byte *s, byte *e)
+append(byte *d, const byte *s, byte *e)
 {
   if (d)
     while (*s)
@@ -527,7 +571,7 @@ url_error(uns err)
 /* Standard cookbook recipes */
 
 int
-url_canon_split(byte *u, byte *buf1, byte *buf2, struct url *url)
+url_canon_split_rel(const byte *u, byte *buf1, byte *buf2, struct url *url, struct url *base)
 {
   int err;
 
@@ -535,19 +579,19 @@ url_canon_split(byte *u, byte *buf1, byte *buf2, struct url *url)
     return err;
   if (err = url_split(buf1, url, buf2))
     return err;
-  if (err = url_normalize(url, NULL))
+  if (err = url_normalize(url, base))
     return err;
   return url_canonicalize(url);
 }
 
 int
-url_auto_canonicalize(byte *src, byte *dst)
+url_auto_canonicalize_rel(const byte *src, byte *dst, struct url *base)
 {
   byte buf1[MAX_URL_SIZE], buf2[MAX_URL_SIZE], buf3[MAX_URL_SIZE];
   int err;
   struct url ur;
 
-  (void)((err = url_canon_split(src, buf1, buf2, &ur)) ||
+  (void)((err = url_canon_split_rel(src, buf1, buf2, &ur, base)) ||
    (err = url_pack(&ur, buf3)) ||
    (err = url_enescape(buf3, dst)));
   return err;
@@ -621,13 +665,13 @@ int main(int argc, char **argv)
 #endif
 
 struct component {
-       byte *start;
+       const byte *start;
        int length;
        u32 hash;
 };
 
 static inline u32
-hashf(byte *start, int length)
+hashf(const byte *start, int length)
 {
        u32 hf = length;
        while (length-- > 0)
@@ -657,11 +701,11 @@ repeat_count(struct component *comp, uns count, uns len)
 }
 
 int
-url_has_repeated_component(byte *url)
+url_has_repeated_component(const byte *url)
 {
        struct component *comp;
        uns comps, comp_len, rep_prefix;
-       byte *c;
+       const byte *c;
        uns i;
 
        for (comps=0, c=url; c; comps++)