]> sjero.net Git - wget/commitdiff
[svn] Implement correct parsing of HTTP Content-Disposition header.
authormtortonesi <devnull@localhost>
Fri, 3 Feb 2006 09:33:57 +0000 (01:33 -0800)
committermtortonesi <devnull@localhost>
Fri, 3 Feb 2006 09:33:57 +0000 (01:33 -0800)
src/ChangeLog
src/http.c
src/test.c

index 43684209fa4385e1f559485edb1f2ce66d9b2f38..7b45114141be23c807beebd3e26f0dd80c467cd9 100644 (file)
@@ -1,3 +1,10 @@
+2006-02-03  Mauro Tortonesi  <mauro@ferrara.linux.it>
+
+       * http.c: Fixed support for Content-Disposition header.
+
+       * test.c: Added test_parse_content_disposition to the list of unit
+       tests to run.
+
 2006-02-02  Hrvoje Niksic  <hniksic@xemacs.org>
 
        * hash.c: Don't define countof if it's already defined.
 2006-02-02  Hrvoje Niksic  <hniksic@xemacs.org>
 
        * hash.c: Don't define countof if it's already defined.
index a499c176b89e51d0b130dd032313e7138c92c43f..2225b43ce8b495245d0d1e5af8837dee5197fc91 100644 (file)
@@ -60,6 +60,10 @@ so, delete this exception statement from your version.  */
 #endif
 #include "convert.h"
 
 #endif
 #include "convert.h"
 
+#ifdef TESTING
+#include "test.h"
+#endif
+
 extern char *version_string;
 
 #ifndef MIN
 extern char *version_string;
 
 #ifndef MIN
@@ -850,6 +854,79 @@ skip_short_body (int fd, wgint contlen)
   DEBUGP (("] done.\n"));
   return true;
 }
   DEBUGP (("] done.\n"));
   return true;
 }
+
+static bool
+extract_param_value_delim (const char *begin, const char *end, 
+                           const char *param_name, char **param_value)
+{
+  const char *p; 
+  int len;  
+
+  assert (begin);
+  assert (end);
+  assert (param_name);
+  assert (param_value);
+
+  len = strlen (param_name);
+
+  /* skip initial whitespaces */
+  p = begin;
+  while (*p && ISSPACE (*p) && p < end) ++p;
+  
+  if (end - p > len
+      && 0 == strncasecmp (p, param_name, len))
+    {
+      const char *e;
+
+      /* skip white spaces, equal sign and inital quote */
+      p += len;
+      while (*p && (ISSPACE (*p) || *p == '\"' || *p == '=') && p < end) ++p;
+
+      /* find last quote */
+      e = p;
+      while (*e && *e != '\"' && e < end) ++e;
+      
+      *param_value = strdupdelim (p, e);
+      
+      return true;
+    }
+
+  return false;
+}
+
+/* Parse the `Content-Disposition' header and extract the information it
+   contains.  Returns true if successful, false otherwise.  */
+static bool
+parse_content_disposition (const char *hdrval, char **filename)
+{
+  const char *b = hdrval; /* b - begin */
+  const char *e = hdrval; /* e - end   */
+
+  assert (hdrval);
+  assert (filename);
+
+  for (; *e; ++e)
+    {
+      if (*e == ';'
+          && e > b)
+        {           
+          /* process chars b->e-1 */
+          if (true == extract_param_value_delim (b, e - 1, "filename", filename)) 
+            return true;
+
+          b = e + 1;
+        }      
+    }
+
+  if (b != e)
+    {
+      /* process chars b->e */
+      if (true == extract_param_value_delim (b, e, "filename", filename)) 
+        return true;
+    }
+
+  return false;
+}
 \f
 /* Persistent connections.  Currently, we cache the most recently used
    connection as persistent, provided that the HTTP server agrees to
 \f
 /* Persistent connections.  Currently, we cache the most recently used
    connection as persistent, provided that the HTTP server agrees to
@@ -1608,14 +1685,11 @@ gethttp (struct url *u, struct http_stat *hs, int *dt, struct url *proxy)
    * hstat.local_file is set by http_loop to the argument of -O. */
   if (!hs->local_file)     
     {
    * hstat.local_file is set by http_loop to the argument of -O. */
   if (!hs->local_file)     
     {
-      if (resp_header_copy (resp, "Content-Disposition", hdrval, sizeof (hdrval)))
-        /* Honor Content-Disposition. */
-        {
-          hs->local_file = xstrdup (hdrval);
-        }
-      else
-        /* Choose filename according to URL name. */
+      /* Honor Content-Disposition whether possible. */
+      if (!resp_header_copy (resp, "Content-Disposition", hdrval, sizeof (hdrval))
+          || false == parse_content_disposition (hdrval, &hs->local_file))
         {
         {
+          /* Choose filename according to URL name. */
           hs->local_file = url_file_name (u);
         }
     }
           hs->local_file = url_file_name (u);
         }
     }
@@ -2896,6 +2970,42 @@ http_cleanup (void)
     cookie_jar_delete (wget_cookie_jar);
 }
 
     cookie_jar_delete (wget_cookie_jar);
 }
 
+
+#ifdef TESTING
+
+char *
+test_parse_content_disposition()
+{
+  int i;
+  struct {
+    char *hdrval;    
+    char *filename;
+    bool result;
+  } test_array[] = {
+    { "filename=\"file.ext\"", "file.ext", true },
+    { "attachment; filename=\"file.ext\"", "file.ext", true },
+    { "attachment; filename=\"file.ext\"; dummy", "file.ext", true },
+    { "attachment", NULL, false },    
+  };
+  
+  for (i = 0; i < sizeof(test_array)/sizeof(test_array[0]); ++i) 
+    {
+      char *filename;
+      bool res = parse_content_disposition (test_array[i].hdrval, &filename);
+
+      mu_assert ("test_parse_content_disposition: wrong result", 
+                 res == test_array[i].result
+                 && (res == false 
+                     || 0 == strcmp (test_array[i].filename, filename)));
+
+      /* printf ("test %d: %s\n", i, res == false ? "false" : filename); */
+    }
+
+  return NULL;
+}
+
+#endif /* TESTING */
+
 /*
  * vim: et ts=2 sw=2
  */
 /*
  * vim: et ts=2 sw=2
  */
index 5f547d8411cb935c73fdd2b8bd65a8820dfb899d..06cd0a4b03e187bd7ae18b8609ce133b8e3f17fe 100644 (file)
@@ -37,12 +37,10 @@ so, delete this exception statement from your version.  */
 
 int tests_run;
 
 
 int tests_run;
 
-/* char *test_ccache(); */
-
 static char *
 all_tests()
 {
 static char *
 all_tests()
 {
-  /* mu_run_test (test_ccache); */
+  mu_run_test (test_parse_content_disposition);
   
   return NULL;
 }
   
   return NULL;
 }