]> sjero.net Git - wget/blobdiff - src/html-url.c
mass change: update copyright years.
[wget] / src / html-url.c
index 0d580f9aaf74b3df8032756fc0ac929b541ea540..287b2f548414fbbcb6e8fa1d62040ec43910e80e 100644 (file)
@@ -1,6 +1,6 @@
 /* Collect URLs from HTML source.
    Copyright (C) 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006,
-   2007, 2008 Free Software Foundation, Inc.
+   2007, 2008, 2009, 2010, 2011 Free Software Foundation, Inc.
 
 This file is part of GNU Wget.
 
@@ -41,10 +41,9 @@ as that of the covered work.  */
 #include "utils.h"
 #include "hash.h"
 #include "convert.h"
-#include "recur.h"              /* declaration of get_urls_html */
-#include "iri.h"
-
-struct map_context;
+#include "recur.h"
+#include "html-url.h"
+#include "css-url.h"
 
 typedef void (*tag_handler_t) (int, struct taginfo *, struct map_context *);
 
@@ -164,16 +163,22 @@ static struct {
    from the information above.  However, some places in the code refer
    to the attributes not mentioned here.  We add them manually.  */
 static const char *additional_attributes[] = {
-  "rel",                        /* used by tag_handle_link */
-  "http-equiv",                 /* used by tag_handle_meta */
-  "name",                       /* used by tag_handle_meta */
-  "content",                    /* used by tag_handle_meta */
-  "action"                      /* used by tag_handle_form */
+  "rel",                        /* used by tag_handle_link  */
+  "type",                       /* used by tag_handle_link  */
+  "http-equiv",                 /* used by tag_handle_meta  */
+  "name",                       /* used by tag_handle_meta  */
+  "content",                    /* used by tag_handle_meta  */
+  "action",                     /* used by tag_handle_form  */
+  "style"                       /* used by check_style_attr */
 };
 
 static struct hash_table *interesting_tags;
 static struct hash_table *interesting_attributes;
 
+/* Will contains the (last) charset found in 'http-equiv=content-type'
+   meta tags  */
+static char *meta_charset;
+
 static void
 init_interesting (void)
 {
@@ -247,34 +252,25 @@ find_attr (struct taginfo *tag, const char *name, int *attrind)
   return NULL;
 }
 
-struct map_context {
-  char *text;                   /* HTML text. */
-  char *base;                   /* Base URI of the document, possibly
-                                   changed through <base href=...>. */
-  const char *parent_base;      /* Base of the current document. */
-  const char *document_file;    /* File name of this document. */
-  bool nofollow;                /* whether NOFOLLOW was specified in a
-                                   <meta name=robots> tag. */
-
-  struct urlpos *head, *tail;   /* List of URLs that is being
-                                   built. */
-};
+/* used for calls to append_url */
+#define ATTR_POS(tag, attrind, ctx) \
+ (tag->attrs[attrind].value_raw_beginning - ctx->text)
+#define ATTR_SIZE(tag, attrind) \
+ (tag->attrs[attrind].value_raw_size)
 
 /* Append LINK_URI to the urlpos structure that is being built.
 
-   LINK_URI will be merged with the current document base.  TAG and
-   ATTRIND are the necessary context to store the position and
-   size.  */
+   LINK_URI will be merged with the current document base.
+*/
 
-static struct urlpos *
-append_url (const char *link_uri,
-            struct taginfo *tag, int attrind, struct map_context *ctx)
+struct urlpos *
+append_url (const char *link_uri, int position, int size,
+            struct map_context *ctx)
 {
   int link_has_scheme = url_has_scheme (link_uri);
   struct urlpos *newel;
   const char *base = ctx->base ? ctx->base : ctx->parent_base;
   struct url *url;
-  bool utf8_encode = false;
 
   if (!base)
     {
@@ -293,7 +289,7 @@ append_url (const char *link_uri,
           return NULL;
         }
 
-      url = url_parse (link_uri, NULL, &utf8_encode);
+      url = url_parse (link_uri, NULL, NULL, false);
       if (!url)
         {
           DEBUGP (("%s: link \"%s\" doesn't parse.\n",
@@ -309,10 +305,13 @@ append_url (const char *link_uri,
 
       char *complete_uri = uri_merge (base, link_uri);
 
-      DEBUGP (("%s: merge(\"%s\", \"%s\") -> %s\n",
-               ctx->document_file, base, link_uri, complete_uri));
+      DEBUGP (("%s: merge(%s, %s) -> %s\n",
+               quotearg_n_style (0, escape_quoting_style, ctx->document_file),
+               quote_n (1, base),
+               quote_n (2, link_uri),
+               quotearg_n_style (3, escape_quoting_style, complete_uri)));
 
-      url = url_parse (complete_uri, NULL, &utf8_encode);
+      url = url_parse (complete_uri, NULL, NULL, false);
       if (!url)
         {
           DEBUGP (("%s: merged link \"%s\" doesn't parse.\n",
@@ -323,12 +322,12 @@ append_url (const char *link_uri,
       xfree (complete_uri);
     }
 
-  DEBUGP (("appending \"%s\" to urlpos.\n", url->url));
+  DEBUGP (("appending %s to urlpos.\n", quote (url->url)));
 
   newel = xnew0 (struct urlpos);
   newel->url = url;
-  newel->pos = tag->attrs[attrind].value_raw_beginning - ctx->text;
-  newel->size = tag->attrs[attrind].value_raw_size;
+  newel->pos = position;
+  newel->size = size;
 
   /* A URL is relative if the host is not named, and the name does not
      start with `/'.  */
@@ -337,17 +336,58 @@ append_url (const char *link_uri,
   else if (link_has_scheme)
     newel->link_complete_p = 1;
 
-  if (ctx->tail)
+  /* Append the new URL maintaining the order by position.  */
+  if (ctx->head == NULL)
+    ctx->head = newel;
+  else
     {
-      ctx->tail->next = newel;
-      ctx->tail = newel;
+      struct urlpos *it, *prev = NULL;
+
+      it = ctx->head;
+      while (it && position > it->pos)
+        {
+          prev = it;
+          it = it->next;
+        }
+
+      newel->next = it;
+
+      if (prev)
+        prev->next = newel;
+      else
+        ctx->head = newel;
     }
-  else
-    ctx->tail = ctx->head = newel;
 
   return newel;
 }
 \f
+static void
+check_style_attr (struct taginfo *tag, struct map_context *ctx)
+{
+  int attrind;
+  int raw_start;
+  int raw_len;
+  char *style = find_attr (tag, "style", &attrind);
+  if (!style)
+    return;
+
+  /* raw pos and raw size include the quotes, skip them when they are
+     present.  */
+  raw_start = ATTR_POS (tag, attrind, ctx);
+  raw_len  = ATTR_SIZE (tag, attrind);
+  if( *(char *)(ctx->text + raw_start) == '\''
+      || *(char *)(ctx->text + raw_start) == '"')
+    {
+      raw_start += 1;
+      raw_len -= 2;
+    }
+
+  if(raw_len <= 0)
+       return;
+
+  get_urls_css (ctx, raw_start, raw_len);
+}
+
 /* All the tag_* functions are called from collect_tags_mapper, as
    specified by KNOWN_TAGS.  */
 
@@ -396,7 +436,8 @@ tag_find_urls (int tagid, struct taginfo *tag, struct map_context *ctx)
           if (0 == strcasecmp (tag->attrs[attrind].name,
                                tag_url_attributes[i].attr_name))
             {
-              struct urlpos *up = append_url (link, tag, attrind, ctx);
+              struct urlpos *up = append_url (link, ATTR_POS(tag,attrind,ctx),
+                                              ATTR_SIZE(tag,attrind), ctx);
               if (up)
                 {
                   int flags = tag_url_attributes[i].flags;
@@ -421,7 +462,8 @@ tag_handle_base (int tagid, struct taginfo *tag, struct map_context *ctx)
   if (!newbase)
     return;
 
-  base_urlpos = append_url (newbase, tag, attrind, ctx);
+  base_urlpos = append_url (newbase, ATTR_POS(tag,attrind,ctx),
+                            ATTR_SIZE(tag,attrind), ctx);
   if (!base_urlpos)
     return;
   base_urlpos->ignore_when_downloading = 1;
@@ -442,9 +484,11 @@ tag_handle_form (int tagid, struct taginfo *tag, struct map_context *ctx)
 {
   int attrind;
   char *action = find_attr (tag, "action", &attrind);
+
   if (action)
     {
-      struct urlpos *up = append_url (action, tag, attrind, ctx);
+      struct urlpos *up = append_url (action, ATTR_POS(tag,attrind,ctx),
+                                      ATTR_SIZE(tag,attrind), ctx);
       if (up)
         up->ignore_when_downloading = 1;
     }
@@ -462,23 +506,39 @@ tag_handle_link (int tagid, struct taginfo *tag, struct map_context *ctx)
   /* All <link href="..."> link references are external, except those
      known not to be, such as style sheet and shortcut icon:
 
-       <link rel="stylesheet" href="...">
-       <link rel="shortcut icon" href="...">
+     <link rel="stylesheet" href="...">
+     <link rel="shortcut icon" href="...">
   */
   if (href)
     {
-      struct urlpos *up = append_url (href, tag, attrind, ctx);
+      struct urlpos *up = append_url (href, ATTR_POS(tag,attrind,ctx),
+                                      ATTR_SIZE(tag,attrind), ctx);
       if (up)
         {
           char *rel = find_attr (tag, "rel", NULL);
-          if (rel
-              && (0 == strcasecmp (rel, "stylesheet")
-                  || 0 == strcasecmp (rel, "shortcut icon")))
-            up->link_inline_p = 1;
-          else
-            /* The external ones usually point to HTML pages, such as
-               <link rel="next" href="..."> */
-            up->link_expect_html = 1;
+          if (rel)
+            {
+              if (0 == strcasecmp (rel, "stylesheet"))
+                {
+                  up->link_inline_p = 1;
+                  up->link_expect_css = 1;
+                }
+              else if (0 == strcasecmp (rel, "shortcut icon"))
+                {
+                  up->link_inline_p = 1;
+                }
+              else
+                {
+                  /* The external ones usually point to HTML pages, such as
+                     <link rel="next" href="...">
+                     except when the type attribute says otherwise:
+                     <link rel="alternate" type="application/rss+xml" href=".../?feed=rss2" />
+                  */
+                  char *type = find_attr (tag, "type", NULL);
+                  if (!type || strcasecmp (type, "text/html") == 0)
+                    up->link_expect_html = 1;
+                }
+            }
         }
     }
 }
@@ -528,7 +588,8 @@ tag_handle_meta (int tagid, struct taginfo *tag, struct map_context *ctx)
       while (c_isspace (*p))
         ++p;
 
-      entry = append_url (p, tag, attrind, ctx);
+      entry = append_url (p, ATTR_POS(tag,attrind,ctx),
+                          ATTR_SIZE(tag,attrind), ctx);
       if (entry)
         {
           entry->link_refresh_p = 1;
@@ -550,10 +611,8 @@ tag_handle_meta (int tagid, struct taginfo *tag, struct map_context *ctx)
       if (!mcharset)
         return;
 
-      /*logprintf (LOG_VERBOSE, "Meta tag charset : %s\n", quote (mcharset));*/
-
-      set_current_charset (mcharset);
-      xfree (mcharset);
+      xfree_null (meta_charset);
+      meta_charset = mcharset;
     }
   else if (name && 0 == strcasecmp (name, "robots"))
     {
@@ -568,15 +627,25 @@ tag_handle_meta (int tagid, struct taginfo *tag, struct map_context *ctx)
         {
           while (*content)
             {
-              /* Find the next occurrence of ',' or the end of
-                 the string.  */
-              char *end = strchr (content, ',');
-              if (end)
-                ++end;
-              else
-                end = content + strlen (content);
+              char *end;
+              /* Skip any initial whitespace. */
+              content += strspn (content, " \f\n\r\t\v");
+              /* Find the next occurrence of ',' or whitespace,
+               * or the end of the string.  */
+              end = content + strcspn (content, ", \f\n\r\t\v");
               if (!strncasecmp (content, "nofollow", end - content))
                 ctx->nofollow = true;
+              /* Skip past the next comma, if any. */
+              if (*end == ',')
+                ++end;
+              else
+                {
+                  end = strchr (end, ',');
+                  if (end)
+                    ++end;
+                  else
+                    end = content + strlen (content);
+                }
               content = end;
             }
         }
@@ -592,11 +661,26 @@ collect_tags_mapper (struct taginfo *tag, void *arg)
   struct map_context *ctx = (struct map_context *)arg;
 
   /* Find the tag in our table of tags.  This must not fail because
-     map_html_tags only returns tags found in interesting_tags.  */
+     map_html_tags only returns tags found in interesting_tags.
+
+     I've changed this for now, I'm passing NULL as interesting_tags
+     to map_html_tags.  This way we can check all tags for a style
+     attribute.
+  */
   struct known_tag *t = hash_table_get (interesting_tags, tag->name);
-  assert (t != NULL);
 
-  t->handler (t->tagid, tag, ctx);
+  if (t != NULL)
+    t->handler (t->tagid, tag, ctx);
+
+  check_style_attr (tag, ctx);
+
+  if (tag->end_tag_p && (0 == strcasecmp (tag->name, "style")) &&
+      tag->contents_begin && tag->contents_end)
+  {
+    /* parse contents */
+    get_urls_css (ctx, tag->contents_begin - ctx->text,
+                  tag->contents_end - tag->contents_begin);
+  }
 }
 \f
 /* Analyze HTML tags FILE and construct a list of URLs referenced from
@@ -604,14 +688,15 @@ collect_tags_mapper (struct taginfo *tag, void *arg)
    <base href=...> and does the right thing.  */
 
 struct urlpos *
-get_urls_html (const char *file, const char *url, bool *meta_disallow_follow)
+get_urls_html (const char *file, const char *url, bool *meta_disallow_follow,
+               struct iri *iri)
 {
   struct file_memory *fm;
   struct map_context ctx;
   int flags;
 
   /* Load the file. */
-  fm = read_file (file);
+  fm = wget_read_file (file);
   if (!fm)
     {
       logprintf (LOG_NOTQUIET, "%s: %s\n", file, strerror (errno));
@@ -620,7 +705,7 @@ get_urls_html (const char *file, const char *url, bool *meta_disallow_follow)
   DEBUGP (("Loaded %s (size %s).\n", file, number_to_static_string (fm->length)));
 
   ctx.text = fm->content;
-  ctx.head = ctx.tail = NULL;
+  ctx.head = NULL;
   ctx.base = NULL;
   ctx.parent_base = url ? url : opt.base_href;
   ctx.document_file = file;
@@ -640,15 +725,20 @@ get_urls_html (const char *file, const char *url, bool *meta_disallow_follow)
   if (opt.strict_comments)
     flags |= MHT_STRICT_COMMENTS;
 
+  /* the NULL here used to be interesting_tags */
   map_html_tags (fm->content, fm->length, collect_tags_mapper, &ctx, flags,
-                 interesting_tags, interesting_attributes);
+                 NULL, interesting_attributes);
+
+  /* If meta charset isn't null, override content encoding */
+  if (iri && meta_charset)
+    set_content_encoding (iri, meta_charset);
 
   DEBUGP (("no-follow in %s: %d\n", file, ctx.nofollow));
   if (meta_disallow_follow)
     *meta_disallow_follow = ctx.nofollow;
 
   xfree_null (ctx.base);
-  read_file_free (fm);
+  wget_read_file_free (fm);
   return ctx.head;
 }
 
@@ -661,10 +751,9 @@ get_urls_file (const char *file)
   struct file_memory *fm;
   struct urlpos *head, *tail;
   const char *text, *text_end;
-  bool utf8_encode = false;
 
   /* Load the file.  */
-  fm = read_file (file);
+  fm = wget_read_file (file);
   if (!fm)
     {
       logprintf (LOG_NOTQUIET, "%s: %s\n", file, strerror (errno));
@@ -713,12 +802,14 @@ get_urls_file (const char *file)
           url_text = merged;
         }
 
-      url = url_parse (url_text, &up_error_code, &utf8_encode);
+      url = url_parse (url_text, &up_error_code, NULL, false);
       if (!url)
         {
+          char *error = url_error (url_text, up_error_code);
           logprintf (LOG_NOTQUIET, _("%s: Invalid URL %s: %s\n"),
-                     file, url_text, url_error (up_error_code));
+                     file, url_text, error);
           xfree (url_text);
+          xfree (error);
           continue;
         }
       xfree (url_text);
@@ -732,7 +823,7 @@ get_urls_file (const char *file)
         tail->next = entry;
       tail = entry;
     }
-  read_file_free (fm);
+  wget_read_file_free (fm);
   return head;
 }