#endif
#include "convert.h"
+#ifdef TESTING
+#include "test.h"
+#endif
+
extern char *version_string;
#ifndef MIN
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
* 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);
}
}
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
*/