]> sjero.net Git - wget/blobdiff - src/url.c
[svn] Applied Philipp Thomas's safe-ctype patch. Published in
[wget] / src / url.c
index 0cbc3cd18275f003021ed02314a28d7c725d6f13..f91263e66085096915cd26d0b8d9d35be7d151d2 100644 (file)
--- a/src/url.c
+++ b/src/url.c
@@ -26,7 +26,6 @@ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.  */
 #else
 # include <strings.h>
 #endif
-#include <ctype.h>
 #include <sys/types.h>
 #ifdef HAVE_UNISTD_H
 # include <unistd.h>
@@ -43,11 +42,6 @@ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.  */
 extern int errno;
 #endif
 
-/* Default port definitions */
-#define DEFAULT_HTTP_PORT 80
-#define DEFAULT_FTP_PORT 21
-#define DEFAULT_HTTPS_PORT 443
-
 /* Table of Unsafe chars.  This is intialized in
    init_unsafe_char_table.  */
 
@@ -339,13 +333,13 @@ int
 skip_uname (const char *url)
 {
   const char *p;
-  for (p = url; *p && *p != '/'; p++)
-    if (*p == '@')
-      break;
+  const char *q = NULL;
+  for (p = url ; *p && *p != '/'; p++)
+    if (*p == '@') q = p;
   /* If a `@' was found before the first occurrence of `/', skip
      it.  */
-  if (*p == '@')
-    return p - url + 1;
+  if (q != NULL)
+    return q - url + 1;
   else
     return 0;
 }
@@ -475,13 +469,13 @@ parseurl (const char *url, struct urlinfo *u, int strict)
     u->proto = type = URLHTTP;
   if (!u->port)
     {
-      int i;
-      for (i = 0; i < ARRAY_SIZE (sup_protos); i++)
-       if (sup_protos[i].ind == type)
+      int ind;
+      for (ind = 0; ind < ARRAY_SIZE (sup_protos); ind++)
+       if (sup_protos[ind].ind == type)
          break;
-      if (i == ARRAY_SIZE (sup_protos))
+      if (ind == ARRAY_SIZE (sup_protos))
        return URLUNKNOWN;
-      u->port = sup_protos[i].port;
+      u->port = sup_protos[ind].port;
     }
   /* Some delimiter troubles...  */
   if (url[i] == '/' && url[i - 1] != ':')
@@ -497,6 +491,7 @@ parseurl (const char *url, struct urlinfo *u, int strict)
       /* #### We don't handle type `d' correctly yet.  */
       if (!u->ftp_type || TOUPPER (u->ftp_type) == 'D')
        u->ftp_type = 'I';
+      DEBUGP (("ftp_type %c -> ", u->ftp_type));
     }
   DEBUGP (("opath %s -> ", u->path));
   /* Parse the username and password (if existing).  */
@@ -607,7 +602,7 @@ static uerr_t
 parse_uname (const char *url, char **user, char **passwd)
 {
   int l;
-  const char *p, *col;
+  const char *p, *q, *col;
   char **where;
 
   *user = NULL;
@@ -627,7 +622,7 @@ parse_uname (const char *url, char **user, char **passwd)
   if (*p != '@')
     return URLOK;
   /* Else find the username and password.  */
-  for (p = col = url; *p != '@'; p++)
+  for (p = q = col = url; *p != '/'; p++)
     {
       if (*p == ':' && !*user)
        {
@@ -636,12 +631,13 @@ parse_uname (const char *url, char **user, char **passwd)
          (*user)[p - url] = '\0';
          col = p + 1;
        }
+      if (*p == '@') q = p;
     }
   /* Decide whether you have only the username or both.  */
   where = *user ? passwd : user;
-  *where = (char *)xmalloc (p - col + 1);
-  memcpy (*where, col, p - col);
-  (*where)[p - col] = '\0';
+  *where = (char *)xmalloc (q - col + 1);
+  memcpy (*where, col, q - col);
+  (*where)[q - col] = '\0';
   return URLOK;
 }
 
@@ -661,10 +657,11 @@ process_ftp_type (char *path)
     return '\0';
 }
 \f
-/* Return the URL as fine-formed string, with a proper protocol,
-   optional port number, directory and optional user/password.  If
-   HIDE is non-zero, password will be hidden.  The forbidden
-   characters in the URL will be cleansed.  */
+/* Return the URL as fine-formed string, with a proper protocol, optional port
+   number, directory and optional user/password.  If `hide' is non-zero (as it
+   is when we're calling this on a URL we plan to print, but not when calling it
+   to canonicalize a URL for use within the program), password will be hidden.
+   The forbidden characters in the URL will be cleansed.  */
 char *
 str_url (const struct urlinfo *u, int hide)
 {
@@ -688,11 +685,14 @@ str_url (const struct urlinfo *u, int hide)
     user = CLEANDUP (u->user);
   if (u->passwd)
     {
-      int i;
-      passwd = CLEANDUP (u->passwd);
       if (hide)
-       for (i = 0; passwd[i]; i++)
-         passwd[i] = 'x';
+       /* Don't output the password, or someone might see it over the user's
+          shoulder (or in saved wget output).  Don't give away the number of
+          characters in the password, either, as we did in past versions of
+          this code, when we replaced the password characters with 'x's. */
+       passwd = xstrdup("<password>");
+      else
+       passwd = CLEANDUP (u->passwd);
     }
   if (u->proto == URLFTP && *dir == '/')
     {
@@ -1311,6 +1311,7 @@ no_proxy_match (const char *host, const char **no_proxy)
 }
 \f
 static void write_backup_file PARAMS ((const char *, downloaded_file_t));
+static void replace_attr PARAMS ((const char **, int, FILE *, const char *));
 
 /* Change the links in an HTML document.  Accepts a structure that
    defines the positions of all the links.  */
@@ -1319,7 +1320,7 @@ convert_links (const char *file, urlpos *l)
 {
   struct file_memory *fm;
   FILE               *fp;
-  char               *p;
+  const char         *p;
   downloaded_file_t  downloaded_file_return;
 
   logprintf (LOG_VERBOSE, _("Converting %s... "), file);
@@ -1378,6 +1379,7 @@ convert_links (const char *file, urlpos *l)
   for (; l; l = l->next)
     {
       char *url_start = fm->content + l->pos;
+
       if (l->pos >= fm->length)
        {
          DEBUGP (("Something strange is going on.  Please investigate."));
@@ -1399,29 +1401,21 @@ convert_links (const char *file, urlpos *l)
          /* Convert absolute URL to relative. */
          char *newname = construct_relative (file, l->local_name);
          char *quoted_newname = html_quote_string (newname);
-         putc (*p, fp);        /* quoting char */
-         fputs (quoted_newname, fp);
-         p += l->size - 1;
-         putc (*p, fp);        /* close quote */
-         ++p;
-         xfree (newname);
-         xfree (quoted_newname);
+         replace_attr (&p, l->size, fp, quoted_newname);
          DEBUGP (("TO_RELATIVE: %s to %s at position %d in %s.\n",
                   l->url, newname, l->pos, file));
+         xfree (newname);
+         xfree (quoted_newname);
        }
       else if (l->convert == CO_CONVERT_TO_COMPLETE)
        {
          /* Convert the link to absolute URL. */
          char *newlink = l->url;
          char *quoted_newlink = html_quote_string (newlink);
-         putc (*p, fp);        /* quoting char */
-         fputs (quoted_newlink, fp);
-         p += l->size - 1;
-         putc (*p, fp);        /* close quote */
-         ++p;
-         xfree (quoted_newlink);
+         replace_attr (&p, l->size, fp, quoted_newlink);
          DEBUGP (("TO_COMPLETE: <something> to %s at position %d in %s.\n",
                   newlink, l->pos, file));
+         xfree (quoted_newlink);
        }
     }
   /* Output the rest of the file. */
@@ -1567,6 +1561,7 @@ write_backup_file (const char *file, downloaded_file_t downloaded_file_return)
         thought I could just add a field to the urlpos structure saying
         that we'd written a .orig file for this URL, but that didn't work,
         so I had to make this separate list.
+        -- Dan Harkless <wget@harkless.org>
 
          This [adding a field to the urlpos structure] didn't work
          because convert_file() is called twice: once after all its
@@ -1575,10 +1570,11 @@ write_backup_file (const char *file, downloaded_file_t downloaded_file_return)
          original linked list collected in recursive_retrieve() is
          lost after the first invocation of convert_links(), and
          convert_all_links() makes a new one (it calls get_urls_html()
-         for each file it covers.)  That's why your approach didn't
+         for each file it covers.)  That's why your first approach didn't
          work.  The way to make it work is perhaps to make this flag a
-         field in the `urls_html' list.  */
-
+         field in the `urls_html' list.
+        -- Hrvoje Niksic <hniksic@arsdigita.com>
+      */
       converted_file_ptr = xmalloc(sizeof(*converted_file_ptr));
       converted_file_ptr->string = xstrdup(file);  /* die on out-of-mem. */
       converted_file_ptr->next = converted_files;
@@ -1586,6 +1582,79 @@ write_backup_file (const char *file, downloaded_file_t downloaded_file_return)
     }
 }
 
+static int find_fragment PARAMS ((const char *, int, const char **,
+                                 const char **));
+
+static void
+replace_attr (const char **pp, int raw_size, FILE *fp, const char *new_str)
+{
+  const char *p = *pp;
+  int quote_flag = 0;
+  int size = raw_size;
+  char quote_char = '\"';
+  const char *frag_beg, *frag_end;
+
+  /* Structure of our string is:
+       "...old-contents..."
+       <---  l->size   --->  (with quotes)
+     OR:
+       ...old-contents...
+       <---  l->size  -->    (no quotes)   */
+
+  if (*p == '\"' || *p == '\'')
+    {
+      quote_char = *p;
+      quote_flag = 1;
+      ++p;
+      size -= 2;               /* disregard opening and closing quote */
+    }
+  putc (quote_char, fp);
+  fputs (new_str, fp);
+
+  /* Look for fragment identifier, if any. */
+  if (find_fragment (p, size, &frag_beg, &frag_end))
+    fwrite (frag_beg, 1, frag_end - frag_beg, fp);
+  p += size;
+  if (quote_flag)
+    ++p;
+  putc (quote_char, fp);
+  *pp = p;
+}
+
+/* Find the first occurrence of '#' in [BEG, BEG+SIZE) that is not
+   preceded by '&'.  If the character is not found, return zero.  If
+   the character is found, return 1 and set BP and EP to point to the
+   beginning and end of the region.
+
+   This is used for finding the fragment indentifiers in URLs.  */
+
+static int
+find_fragment (const char *beg, int size, const char **bp, const char **ep)
+{
+  const char *end = beg + size;
+  int saw_amp = 0;
+  for (; beg < end; beg++)
+    {
+      switch (*beg)
+       {
+       case '&':
+         saw_amp = 1;
+         break;
+       case '#':
+         if (!saw_amp)
+           {
+             *bp = beg;
+             *ep = end;
+             return 1;
+           }
+         /* fallthrough */
+       default:
+         saw_amp = 0;
+       }
+    }
+  return 0;
+}
+
 typedef struct _downloaded_file_list {
   char*                          file;
   downloaded_file_t              download_type;