aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/cache.c19
-rw-r--r--src/menu.cc2
-rw-r--r--src/misc.c46
-rw-r--r--src/misc.h1
-rw-r--r--src/uicmd.cc10
-rw-r--r--src/uicmd.hh2
6 files changed, 72 insertions, 8 deletions
diff --git a/src/cache.c b/src/cache.c
index d2827e65..319de1b6 100644
--- a/src/cache.c
+++ b/src/cache.c
@@ -52,6 +52,7 @@ typedef struct {
char *TypeHdr; /**< MIME type string as from the HTTP Header */
char *TypeMeta; /**< MIME type string from META HTTP-EQUIV */
char *TypeNorm; /**< MIME type string normalized */
+ char *ContentDisposition; /**< Content-Disposition header */
Dstr *Header; /**< HTTP header */
const DilloUrl *Location; /**< New URI for redirects */
Dlist *Auth; /**< Authentication fields */
@@ -196,6 +197,7 @@ static void Cache_entry_init(CacheEntry_t *NewEntry, const DilloUrl *Url)
NewEntry->TypeHdr = NULL;
NewEntry->TypeMeta = NULL;
NewEntry->TypeNorm = NULL;
+ NewEntry->ContentDisposition = NULL;
NewEntry->Header = dStr_new("");
NewEntry->Location = NULL;
NewEntry->Auth = NULL;
@@ -302,6 +304,7 @@ static void Cache_entry_free(CacheEntry_t *entry)
dFree(entry->TypeHdr);
dFree(entry->TypeMeta);
dFree(entry->TypeNorm);
+ dFree(entry->ContentDisposition);
dStr_free(entry->Header, TRUE);
a_Url_free((DilloUrl *)entry->Location);
Cache_auth_free(entry->Auth);
@@ -813,6 +816,9 @@ static void Cache_parse_header(CacheEntry_t *entry)
_MSG("TypeMeta {%s}\n", entry->TypeMeta);
dFree(Type);
}
+
+ entry->ContentDisposition = Cache_parse_field(header, "Content-Disposition");
+
Cache_ref_data(entry);
}
@@ -1123,6 +1129,7 @@ static void Cache_null_client(int Op, CacheClient_t *Client)
typedef struct {
BrowserWindow *bw;
DilloUrl *url;
+ char* filename;
} Cache_savelink_t;
/**
@@ -1133,7 +1140,7 @@ static void Cache_savelink_cb(void *vdata)
{
Cache_savelink_t *data = (Cache_savelink_t*) vdata;
- a_UIcmd_save_link(data->bw, data->url);
+ a_UIcmd_save_link(data->bw, data->url, data->filename);
a_Url_free(data->url);
dFree(data);
}
@@ -1184,6 +1191,8 @@ static CacheEntry_t *Cache_process_queue(CacheEntry_t *entry)
bool_t AbortEntry = FALSE;
bool_t OfferDownload = FALSE;
bool_t TypeMismatch = FALSE;
+ char *dtype = NULL;
+ char *dfilename = NULL;
if (Busy)
MSG_ERR("FATAL!: >>>> Cache_process_queue Caught busy!!! <<<<\n");
@@ -1204,6 +1213,9 @@ static CacheEntry_t *Cache_process_queue(CacheEntry_t *entry)
} else
return entry; /* i.e., wait for more data */
}
+ if (entry->ContentDisposition) {
+ a_Misc_parse_content_disposition(entry->ContentDisposition, &dtype, &dfilename);
+ }
Busy = TRUE;
for (i = 0; (Client = dList_nth_data(ClientQueue, i)); ++i) {
@@ -1268,6 +1280,8 @@ static CacheEntry_t *Cache_process_queue(CacheEntry_t *entry)
* connection and to keep a failed-resource flag in
* the cache entry. */
}
+ } else if (dtype && dStrnAsciiCasecmp(dtype, "attachment", 10) == 0) {
+ AbortEntry = OfferDownload = TRUE;
}
}
if (AbortEntry) {
@@ -1337,6 +1351,7 @@ static CacheEntry_t *Cache_process_queue(CacheEntry_t *entry)
Cache_savelink_t *data = dNew(Cache_savelink_t, 1);
data->bw = Client_bw;
data->url = a_Url_dup(url);
+ data->filename = dStrdup(dfilename);
a_Timeout_add(0.0, Cache_savelink_cb, data);
}
}
@@ -1345,6 +1360,8 @@ static CacheEntry_t *Cache_process_queue(CacheEntry_t *entry)
Cache_auth_entry(entry, Client_bw);
}
+ dFree(dtype); dFree(dfilename);
+
/* Trigger cleanup when there are no cache clients */
if (dList_length(ClientQueue) == 0) {
a_Dicache_cleanup();
diff --git a/src/menu.cc b/src/menu.cc
index 3cdc2f77..0a33e0ce 100644
--- a/src/menu.cc
+++ b/src/menu.cc
@@ -147,7 +147,7 @@ static void Menu_find_text_cb(Fl_Widget*, void*)
static void Menu_save_link_cb(Fl_Widget*, void *user_data)
{
DilloUrl *url = (DilloUrl *)user_data;
- a_UIcmd_save_link(popup_bw, url);
+ a_UIcmd_save_link(popup_bw, url, NULL);
}
/**
diff --git a/src/misc.c b/src/misc.c
index 9129f819..83c43eb4 100644
--- a/src/misc.c
+++ b/src/misc.c
@@ -354,6 +354,52 @@ int a_Misc_content_type_check(const char *EntryType, const char *DetectedType)
return st;
}
+
+/**
+ * Parse Content-Disposition string, e.g., "attachment; filename="file name.jpg"".
+ * Content-Disposition is defined in RFC 6266
+ */
+void a_Misc_parse_content_disposition(const char *disposition, char **type, char **filename)
+{
+ static const char tspecials_space[] = "()<>@,;:\\\"/[]?= ";
+ const char *str, *s;
+
+ if (type)
+ *type = NULL;
+ if (filename)
+ *filename = NULL;
+ if (!(str = disposition))
+ return;
+
+ for (s = str; *s && d_isascii((uchar_t)*s) && !iscntrl((uchar_t)*s) &&
+ !strchr(tspecials_space, *s); s++) ;
+ if (type)
+ *type = dStrndup(str, s - str);
+
+ if (*s == ';') {
+ const char terminators[] = " ;\t";
+ const char key[] = "filename";
+
+ if ((s = dStriAsciiStr(str, key)) &&
+ (s == str || strchr(terminators, s[-1]))) {
+ s += sizeof(key) - 1;
+ for ( ; *s == ' ' || *s == '\t'; ++s);
+ if (*s == '=') {
+ size_t len;
+ for (++s; *s == ' ' || *s == '\t'; ++s);
+ if ((len = strcspn(s, terminators))) {
+ if (*s == '"' && s[len-1] == '"' && len > 1) {
+ /* quoted string */
+ s++;
+ len -= 2;
+ }
+ *filename = dStrndup(s, len);
+ }
+ }
+ }
+ }
+}
+
/**
* Parse a geometry string.
*/
diff --git a/src/misc.h b/src/misc.h
index 5e52b5b3..b2d4fe6e 100644
--- a/src/misc.h
+++ b/src/misc.h
@@ -17,6 +17,7 @@ int a_Misc_content_type_check(const char *EntryType, const char *DetectedType);
void a_Misc_parse_content_type(const char *str, char **major, char **minor,
char **charset);
int a_Misc_content_type_cmp(const char* ct1, const char *ct2);
+void a_Misc_parse_content_disposition(const char *disposition, char **type, char **filename);
int a_Misc_parse_geometry(char *geom, int *x, int *y, int *w, int *h);
int a_Misc_parse_search_url(char *source, char **label, char **urlstr);
char *a_Misc_encode_base64(const char *in);
diff --git a/src/uicmd.cc b/src/uicmd.cc
index 15207408..06333d0c 100644
--- a/src/uicmd.cc
+++ b/src/uicmd.cc
@@ -1088,10 +1088,10 @@ static int UIcmd_save_file_check(const char *name)
/*
* Save a URL
*/
-static void UIcmd_save(BrowserWindow *bw, const DilloUrl *url,
+static void UIcmd_save(BrowserWindow *bw, const DilloUrl *url, char *filename,
const char *title)
{
- char *SuggestedName = UIcmd_make_save_filename(url);
+ char *SuggestedName = filename ? filename : UIcmd_make_save_filename(url);
while (1) {
const char *name = a_Dialog_save_file(title, NULL, SuggestedName);
@@ -1129,7 +1129,7 @@ void a_UIcmd_save(void *vbw)
const DilloUrl *url = a_History_get_url(NAV_TOP_UIDX(bw));
if (url) {
- UIcmd_save(bw, url, "Save Page as File");
+ UIcmd_save(bw, url, NULL, "Save Page as File");
}
}
@@ -1248,9 +1248,9 @@ const char *a_UIcmd_get_passwd(const char *user)
/*
* Save link URL
*/
-void a_UIcmd_save_link(BrowserWindow *bw, const DilloUrl *url)
+void a_UIcmd_save_link(BrowserWindow *bw, const DilloUrl *url, char *filename)
{
- UIcmd_save(bw, url, "Dillo: Save Link as File");
+ UIcmd_save(bw, url, filename, "Dillo: Save Link as File");
}
/*
diff --git a/src/uicmd.hh b/src/uicmd.hh
index 1343a4a9..b69b50db 100644
--- a/src/uicmd.hh
+++ b/src/uicmd.hh
@@ -45,7 +45,7 @@ void a_UIcmd_redirection0(void *vbw, const DilloUrl *url);
void a_UIcmd_save(void *vbw);
void a_UIcmd_stop(void *vbw);
void a_UIcmd_tools(void *vbw, int x, int y);
-void a_UIcmd_save_link(BrowserWindow *bw, const DilloUrl *url);
+void a_UIcmd_save_link(BrowserWindow *bw, const DilloUrl *url, char *filename);
void a_UIcmd_open_file(void *vbw);
const char *a_UIcmd_select_file(void);
void a_UIcmd_search_dialog(void *vbw);