summaryrefslogtreecommitdiff
path: root/desktop
diff options
context:
space:
mode:
authorJohn Mark Bell <jmb@netsurf-browser.org>2010-04-05 21:35:38 +0000
committerJohn Mark Bell <jmb@netsurf-browser.org>2010-04-05 21:35:38 +0000
commit2748fe4f6483f8cfb3c4f91a01e8d897b7d1ac47 (patch)
tree0647010a17aee4237d125e42cc8bd726ec0573ae /desktop
parent89daef932a9bbc46e276f6d306b0aabf109806f9 (diff)
downloadnetsurf-2748fe4f6483f8cfb3c4f91a01e8d897b7d1ac47.tar.gz
netsurf-2748fe4f6483f8cfb3c4f91a01e8d897b7d1ac47.tar.bz2
Make downloads work again.
svn path=/trunk/netsurf/; revision=10243
Diffstat (limited to 'desktop')
-rw-r--r--desktop/browser.c124
-rw-r--r--desktop/download.c215
-rw-r--r--desktop/download.h90
-rw-r--r--desktop/gui.h12
4 files changed, 349 insertions, 92 deletions
diff --git a/desktop/browser.c b/desktop/browser.c
index e1b071fdb..df53819c7 100644
--- a/desktop/browser.c
+++ b/desktop/browser.c
@@ -43,6 +43,7 @@
#include "css/css.h"
#include "desktop/401login.h"
#include "desktop/browser.h"
+#include "desktop/download.h"
#include "desktop/frames.h"
#include "desktop/history_core.h"
#include "desktop/gui.h"
@@ -81,7 +82,8 @@ static nserror browser_window_callback(hlcache_handle *c,
const hlcache_event *event, void *pw);
static void browser_window_refresh(void *p);
static bool browser_window_check_throbber(struct browser_window *bw);
-static void browser_window_convert_to_download(struct browser_window *bw);
+static void browser_window_convert_to_download(struct browser_window *bw,
+ llcache_handle *stream);
static void browser_window_start_throbber(struct browser_window *bw);
static void browser_window_stop_throbber(struct browser_window *bw);
static void browser_window_set_icon(struct browser_window *bw);
@@ -89,8 +91,6 @@ static void browser_window_set_status(struct browser_window *bw,
const char *text);
static void browser_window_set_pointer(struct gui_window *g,
gui_pointer_shape shape);
-static nserror download_window_callback(llcache_handle *handle,
- const llcache_event *event, void *pw);
static void browser_window_destroy_children(struct browser_window *bw);
static void browser_window_destroy_internal(struct browser_window *bw);
static void browser_window_set_scale_internal(struct browser_window *bw,
@@ -338,15 +338,24 @@ void browser_window_go_post(struct browser_window *bw, const char *url,
if (download) {
llcache_handle *l;
- error = llcache_handle_retrieve(url2,
- fetch_flags | LLCACHE_RETRIEVE_FORCE_FETCH,
- referer, fetch_is_post ? &post : NULL,
- download_window_callback, NULL, &l);
+ fetch_flags |= LLCACHE_RETRIEVE_FORCE_FETCH;
+ fetch_flags |= LLCACHE_RETRIEVE_STREAM_DATA;
+
+ error = llcache_handle_retrieve(url2, fetch_flags, referer,
+ fetch_is_post ? &post : NULL,
+ NULL, NULL, &l);
if (error != NSERROR_OK)
LOG(("Failed to fetch download: %d", error));
free(url2);
+ error = download_context_create(l, bw->window);
+ if (error != NSERROR_OK) {
+ LOG(("Failed creating download context: %d", error));
+ llcache_handle_abort(l);
+ llcache_handle_release(l);
+ }
+
return;
}
@@ -406,7 +415,9 @@ void browser_window_go_post(struct browser_window *bw, const char *url,
browser_window_set_status(bw, messages_get("Loading"));
bw->history_add = add_to_history;
- error = hlcache_handle_retrieve(url2, 0, referer,
+ error = hlcache_handle_retrieve(url2,
+ fetch_flags | HLCACHE_RETRIEVE_MAY_DOWNLOAD,
+ referer,
fetch_is_post ? &post : NULL,
browser_window_callback, bw,
parent != NULL ? &child : NULL,
@@ -439,21 +450,26 @@ nserror browser_window_callback(hlcache_handle *c,
struct browser_window *bw = pw;
switch (event->type) {
+ case CONTENT_MSG_DOWNLOAD:
+ assert(bw->loading_content == c);
+
+ browser_window_convert_to_download(bw, event->data.download);
+
+ break;
+
case CONTENT_MSG_LOADING:
assert(bw->loading_content == c);
- if (content_get_type(c) == CONTENT_OTHER)
- browser_window_convert_to_download(bw);
#ifdef WITH_THEME_INSTALL
- else if (content_get_type(c) == CONTENT_THEME) {
+ if (content_get_type(c) == CONTENT_THEME) {
theme_install_start(c);
bw->loading_content = NULL;
//newcache do we not just pass ownership to the theme installation stuff?
hlcache_handle_release(c);
browser_window_stop_throbber(bw);
- }
+ } else
#endif
- else {
+ {
bw->refresh_interval = -1;
browser_window_set_status(bw,
content_get_status_message(c));
@@ -612,24 +628,18 @@ nserror browser_window_callback(hlcache_handle *c,
* Transfer the loading_content to a new download window.
*/
-void browser_window_convert_to_download(struct browser_window *bw)
+void browser_window_convert_to_download(struct browser_window *bw,
+ llcache_handle *stream)
{
- struct gui_download_window *download_window;
- hlcache_handle *c = bw->loading_content;
- llcache_handle *stream;
-
- assert(c);
-
- stream = content_convert_to_download(c);
+ nserror error;
- /** \todo Sort parameters out here */
- download_window = gui_download_window_create(
- llcache_handle_get_url(stream),
- llcache_handle_get_header(stream, "Content-Type"),
- NULL, 0, NULL);
+ error = download_context_create(stream, bw->window);
+ if (error != NSERROR_OK) {
+ llcache_handle_abort(stream);
+ llcache_handle_release(stream);
- llcache_handle_change_callback(stream,
- download_window_callback, download_window);
+ return;
+ }
/* remove content from browser window */
hlcache_handle_release(bw->loading_content);
@@ -1341,64 +1351,6 @@ void browser_window_find_target_internal(struct browser_window *bw,
/**
- * Callback for fetch for download window fetches.
- */
-
-nserror download_window_callback(llcache_handle *handle,
- const llcache_event *event, void *pw)
-{
- struct gui_download_window *download_window = pw;
-
- switch (event->type) {
- case LLCACHE_EVENT_HAD_HEADERS:
- assert(download_window == NULL);
-
- /** \todo Ensure parameters are correct here */
- download_window = gui_download_window_create(
- llcache_handle_get_url(handle),
- llcache_handle_get_header(handle,
- "Content-Type"),
- NULL, 0, NULL);
- if (download_window == NULL)
- return NSERROR_NOMEM;
-
- llcache_handle_change_callback(handle,
- download_window_callback, download_window);
- break;
-
- case LLCACHE_EVENT_HAD_DATA:
- assert(download_window != NULL);
-
- /** \todo Lose ugly cast */
- gui_download_window_data(download_window,
- (char *) event->data.data.buf,
- event->data.data.len);
-
- break;
-
- case LLCACHE_EVENT_DONE:
- assert(download_window != NULL);
-
- gui_download_window_done(download_window);
-
- break;
-
- case LLCACHE_EVENT_ERROR:
- if (download_window != NULL)
- gui_download_window_error(download_window,
- event->data.msg);
-
- break;
-
- case LLCACHE_EVENT_PROGRESS:
- break;
- }
-
- return NSERROR_OK;
-}
-
-
-/**
* Handle mouse clicks in a browser window.
*
* \param bw browser window
diff --git a/desktop/download.c b/desktop/download.c
new file mode 100644
index 000000000..7ec41c37d
--- /dev/null
+++ b/desktop/download.c
@@ -0,0 +1,215 @@
+/*
+ * Copyright 2010 John-Mark Bell <jmb@netsurf-browser.org>
+ *
+ * This file is part of NetSurf, http://www.netsurf-browser.org/
+ *
+ * NetSurf is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ * NetSurf is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+/**
+ * \file Core download context (implementation)
+ */
+
+#include <assert.h>
+#include <stdlib.h>
+
+#include "content/llcache.h"
+#include "desktop/download.h"
+#include "desktop/gui.h"
+#include "utils/http.h"
+
+/**
+ * A context for a download
+ */
+struct download_context {
+ llcache_handle *llcache; /**< Low-level cache handle */
+ struct gui_window *parent; /**< Parent window */
+
+ char *mime_type; /**< MIME type of download */
+ unsigned long total_length; /**< Length of data, in bytes */
+
+ struct gui_download_window *window; /**< GUI download window */
+};
+
+/**
+ * Process fetch headers for a download context.
+ * Extracts MIME type, total length, and creates gui_download_window
+ *
+ * \param ctx Context to process
+ * \return NSERROR_OK on success, appropriate error otherwise
+ */
+static nserror download_context_process_headers(download_context *ctx)
+{
+ const char *http_header;
+ char *mime_type;
+ http_parameter *params;
+ unsigned long length;
+ nserror error;
+
+ /* Retrieve and parse Content-Type */
+ http_header = llcache_handle_get_header(ctx->llcache, "Content-Type");
+ if (http_header == NULL)
+ http_header = "text/plain";
+
+ error = http_parse_content_type(http_header, &mime_type, &params);
+ if (error != NSERROR_OK)
+ return error;
+
+ /* Don't care about parameters */
+ http_parameter_list_destroy(params);
+
+ /* Retrieve and parse Content-Length */
+ http_header = llcache_handle_get_header(ctx->llcache, "Content-Length");
+ if (http_header == NULL)
+ length = 0;
+ else
+ length = strtoul(http_header, NULL, 10);
+
+ ctx->mime_type = mime_type;
+ ctx->total_length = length;
+
+ /* Create the frontend window */
+ ctx->window = gui_download_window_create(ctx, ctx->parent);
+ if (ctx->window == NULL) {
+ free(ctx->mime_type);
+ ctx->mime_type = NULL;
+ return NSERROR_NOMEM;
+ }
+
+ return NSERROR_OK;
+}
+
+/**
+ * Callback for low-level cache events
+ *
+ * \param handle Low-level cache handle
+ * \param event Event object
+ * \param pw Our context
+ * \return NSERROR_OK on success, appropriate error otherwise
+ */
+static nserror download_callback(llcache_handle *handle,
+ const llcache_event *event, void *pw)
+{
+ download_context *ctx = pw;
+ nserror error = NSERROR_OK;
+
+ switch (event->type) {
+ case LLCACHE_EVENT_HAD_HEADERS:
+ error = download_context_process_headers(ctx);
+ if (error != NSERROR_OK) {
+ llcache_handle_abort(handle);
+ download_context_destroy(ctx);
+ }
+
+ break;
+
+ case LLCACHE_EVENT_HAD_DATA:
+ /* If we didn't know up-front that this fetch was for download,
+ * then we won't receive the HAD_HEADERS event. Catch up now.
+ */
+ if (ctx->window == NULL) {
+ error = download_context_process_headers(ctx);
+ if (error != NSERROR_OK) {
+ llcache_handle_abort(handle);
+ download_context_destroy(ctx);
+ }
+ }
+
+ if (error == NSERROR_OK) {
+ /** \todo Lose ugly cast */
+ error = gui_download_window_data(ctx->window,
+ (char *) event->data.data.buf,
+ event->data.data.len);
+ if (error != NSERROR_OK)
+ llcache_handle_abort(handle);
+ }
+
+ break;
+
+ case LLCACHE_EVENT_DONE:
+ assert(ctx->window != NULL);
+
+ gui_download_window_done(ctx->window);
+
+ break;
+
+ case LLCACHE_EVENT_ERROR:
+ if (ctx->window != NULL)
+ gui_download_window_error(ctx->window, event->data.msg);
+
+ break;
+
+ case LLCACHE_EVENT_PROGRESS:
+ break;
+ }
+
+ return error;
+}
+
+/* See download.h for documentation */
+nserror download_context_create(llcache_handle *llcache,
+ struct gui_window *parent)
+{
+ download_context *ctx;
+
+ ctx = malloc(sizeof(*ctx));
+ if (ctx == NULL)
+ return NSERROR_NOMEM;
+
+ ctx->llcache = llcache;
+ ctx->parent = parent;
+ ctx->mime_type = NULL;
+ ctx->total_length = 0;
+ ctx->window = NULL;
+
+ llcache_handle_change_callback(llcache, download_callback, ctx);
+
+ return NSERROR_OK;
+}
+
+/* See download.h for documentation */
+void download_context_destroy(download_context *ctx)
+{
+ llcache_handle_release(ctx->llcache);
+
+ free(ctx->mime_type);
+
+ /* Window is not owned by us, so don't attempt to destroy it */
+
+ free(ctx);
+}
+
+/* See download.h for documentation */
+void download_context_abort(download_context *ctx)
+{
+ llcache_handle_abort(ctx->llcache);
+}
+
+/* See download.h for documentation */
+const char *download_context_get_url(const download_context *ctx)
+{
+ return llcache_handle_get_url(ctx->llcache);
+}
+
+/* See download.h for documentation */
+const char *download_context_get_mime_type(const download_context *ctx)
+{
+ return ctx->mime_type;
+}
+
+/* See download.h for documentation */
+unsigned long download_context_get_total_length(const download_context *ctx)
+{
+ return ctx->total_length;
+}
+
diff --git a/desktop/download.h b/desktop/download.h
new file mode 100644
index 000000000..206253602
--- /dev/null
+++ b/desktop/download.h
@@ -0,0 +1,90 @@
+/*
+ * Copyright 2010 John-Mark Bell <jmb@netsurf-browser.org>
+ *
+ * This file is part of NetSurf, http://www.netsurf-browser.org/
+ *
+ * NetSurf is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ * NetSurf is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+/**
+ * \file Core download context (interface)
+ */
+
+#ifndef NETSURF_DESKTOP_DOWNLOAD_H_
+#define NETSURF_DESKTOP_DOWNLOAD_H_
+
+#include "utils/errors.h"
+
+struct gui_window;
+struct llcache_handle;
+
+/** Type of a download context */
+typedef struct download_context download_context;
+
+/**
+ * Create a download context
+ *
+ * \param llcache Low-level cache handle for download
+ * \param parent Parent window, for UI
+ * \return NSERROR_OK on success, appropriate error otherwise
+ *
+ * This must only be called by the core browser window fetch infrastructure.
+ * Ownership of the download context object created is passed to the frontend.
+ */
+nserror download_context_create(struct llcache_handle *llcache,
+ struct gui_window *parent);
+
+/**
+ * Destroy a download context
+ *
+ * \param ctx Context to destroy
+ *
+ * Called by the frontend when it has finished with a download context
+ */
+void download_context_destroy(download_context *ctx);
+
+/**
+ * Abort a download fetch
+ *
+ * \param ctx Context to abort
+ *
+ * Called by the frontend to abort a download.
+ * The context must be destroyed independently.
+ */
+void download_context_abort(download_context *ctx);
+
+/**
+ * Retrieve the URL for a download
+ *
+ * \param ctx Context to retrieve URL from
+ * \return URL string
+ */
+const char *download_context_get_url(const download_context *ctx);
+
+/**
+ * Retrieve the MIME type for a download
+ *
+ * \param ctx Context to retrieve MIME type from
+ * \return MIME type string
+ */
+const char *download_context_get_mime_type(const download_context *ctx);
+
+/**
+ * Retrieve total byte length of download
+ *
+ * \param ctx Context to retrieve byte length from
+ * \return Total length, in bytes, or 0 if unknown
+ */
+unsigned long download_context_get_total_length(const download_context *ctx);
+
+#endif
diff --git a/desktop/gui.h b/desktop/gui.h
index 95301d1c1..80ba33cc8 100644
--- a/desktop/gui.h
+++ b/desktop/gui.h
@@ -41,7 +41,6 @@ typedef enum {
GUI_SAVE_CLIPBOARD_CONTENTS
} gui_save_type;
-struct fetch;
struct gui_window;
struct gui_download_window;
@@ -58,7 +57,9 @@ typedef enum { GUI_POINTER_DEFAULT, GUI_POINTER_POINT, GUI_POINTER_CARET,
#include "content/content.h"
#include "content/hlcache.h"
#include "desktop/browser.h"
+#include "desktop/download.h"
#include "desktop/search.h"
+#include "utils/errors.h"
void gui_stdout(void);
void gui_multitask(void);
@@ -102,11 +103,10 @@ void gui_window_save_link(struct gui_window *g, const char *url,
const char *title);
void gui_window_set_scale(struct gui_window *g, float scale);
-struct gui_download_window *gui_download_window_create(const char *url,
- const char *mime_type, struct fetch *fetch,
- unsigned int total_size, struct gui_window *gui);
-void gui_download_window_data(struct gui_download_window *dw, const char *data,
- unsigned int size);
+struct gui_download_window *gui_download_window_create(download_context *ctx,
+ struct gui_window *parent);
+nserror gui_download_window_data(struct gui_download_window *dw,
+ const char *data, unsigned int size);
void gui_download_window_error(struct gui_download_window *dw,
const char *error_msg);
void gui_download_window_done(struct gui_download_window *dw);