From 2748fe4f6483f8cfb3c4f91a01e8d897b7d1ac47 Mon Sep 17 00:00:00 2001 From: John Mark Bell Date: Mon, 5 Apr 2010 21:35:38 +0000 Subject: Make downloads work again. svn path=/trunk/netsurf/; revision=10243 --- desktop/browser.c | 124 ++++++++++-------------------- desktop/download.c | 215 +++++++++++++++++++++++++++++++++++++++++++++++++++++ desktop/download.h | 90 ++++++++++++++++++++++ desktop/gui.h | 12 +-- 4 files changed, 349 insertions(+), 92 deletions(-) create mode 100644 desktop/download.c create mode 100644 desktop/download.h (limited to 'desktop') 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); @@ -1340,64 +1350,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. * 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 + * + * 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 . + */ + +/** + * \file Core download context (implementation) + */ + +#include +#include + +#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, ¶ms); + 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 + * + * 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 . + */ + +/** + * \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); -- cgit v1.2.3