Review: Review: branches/vince/netsurf-file-fetcher
by John-Mark Bell
Added files
Index: content/fetchers/fetch_file.c
===================================================================
--- /dev/null 2009-04-16 19:17:07.000000000 +0100
+++ content/fetchers/fetch_file.c 2010-09-09 19:47:22.000000000 +0100
@@ -0,0 +1,651 @@
+/*
+ * Copyright 2010 Vincent Sanders <vince(a)netsurf-browser.org>
+ *
+ * This file is part of NetSurf.
+ *
+ * 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: URL handling. Based on the data fetcher by Rob Kendrik */
+
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <assert.h>
+#include <errno.h>
+#include <stdbool.h>
+#include <inttypes.h>
+#include <string.h>
+#include <strings.h>
+#include <time.h>
+#include <stdio.h>
+#include <dirent.h>
+#include <limits.h>
+#include <stdarg.h>
+
+#include "utils/config.h"
+#include "content/dirlist.h"
+#include "content/fetch.h"
+#include "content/fetchers/fetch_file.h"
+#include "content/urldb.h"
+#include "desktop/netsurf.h"
+#include "desktop/options.h"
+#include "utils/log.h"
+#include "utils/messages.h"
+#include "utils/url.h"
+#include "utils/utils.h"
+#include "utils/ring.h"
+
+/* Maximum size of read buffer */
+#define FETCH_FILE_MAX_BUF_SIZE (1024 * 1024)
+
+/** Context for a fetch */
+struct fetch_file_context {
+ struct fetch_file_context *r_next, *r_prev;
+
+ struct fetch *fetchh; /**< Handle for this fetch */
+
+ bool aborted; /**< Flag indicating fetch has been aborted */
+ bool locked; /**< Flag indicating entry is already entered */
+
+ char *url; /**< The full url the fetch refers to */
+ char *path; /**< The actual path to be used with open() */
+
+ int fd; /**< The file descriptor of the object */
+ struct stat fstat; /**< The objects stat */
+};
+
+static struct fetch_file_context *ring = NULL;
+
+/** issue fetch callbacks with locking */
+static bool fetch_file_send_callback(fetch_msg msg,
+ struct fetch_file_context *ctx, const void *data,
+ unsigned long size, fetch_error_code errorcode)
+{
+ ctx->locked = true;
+ fetch_send_callback(msg, ctx->fetchh, data, size, errorcode);
+ ctx->locked = false;
+
+ return ctx->aborted;
+}
+
+static bool fetch_file_send_header(struct fetch_file_context *ctx, const char *fmt, ...)
+{
+ char header[64];
+ va_list ap;
+
+ va_start(ap, fmt);
+
+ vsnprintf(header, sizeof header, fmt, ap);
+
+ va_end(ap);
+
+ LOG(("%s", header));
+
+ ctx->locked = true;
+ fetch_send_callback(FETCH_HEADER, ctx->fetchh, header, strlen(header), FETCH_ERROR_NO_ERROR);
+ ctx->locked = false;
+
+ return ctx->aborted;
+}
+
+static bool fetch_file_send_time(struct fetch_file_context *ctx, const char *fmt, const time_t *val)
+{
+ char header[64];
+ struct tm btm;
+
+ gmtime_r(val, &btm);
+
+ strftime(header, sizeof header, fmt, &btm);
+
+ LOG(("%s", header));
+
+ ctx->locked = true;
+ fetch_send_callback(FETCH_HEADER, ctx->fetchh, header, strlen(header), FETCH_ERROR_NO_ERROR);
+ ctx->locked = false;
+
+ return ctx->aborted;
+}
+
+/** callback to initialise the file fetcher. */
+static bool fetch_file_initialise(const char *scheme)
+{
+ LOG(("fetch_file_initialise called for %s", scheme));
+ return true;
+}
+
+/** callback to initialise the file fetcher. */
+static void fetch_file_finalise(const char *scheme)
+{
+ LOG(("fetch_file_finalise called for %s", scheme));
+}
+
+/** callback to set up a file fetch context. */
+static void *
+fetch_file_setup(struct fetch *fetchh,
+ const char *url,
+ bool only_2xx,
+ const char *post_urlenc,
+ const struct fetch_multipart_data *post_multipart,
+ const char **headers)
+{
+ struct fetch_file_context *ctx = calloc(1, sizeof(*ctx));
+ char *path;
+
+ if (ctx == NULL)
+ return NULL;
+
+ ctx->fetchh = fetchh;
+
+ ctx->url = strdup(url);
+
+ url_path(url, &path);
+ if (path == NULL) {
+ free(ctx);
+ return NULL;
+ }
+
+ url_unescape(path, &ctx->path);
+ if (ctx->path == NULL) {
+ free(path);
+ free(ctx);
+ return NULL;
+ }
+
+ free(path);
+
+ RING_INSERT(ring, ctx);
+
+ LOG(("new context %p for fetch handle %p, url %s, path %s",
+ ctx, fetchh, ctx->url, ctx->path));
+ LOG(("only_2xx %d, post_urlenc %s, post_multipart %p, headers %p",
+ only_2xx, post_urlenc, post_multipart, headers));
+
+ return ctx;
+}
+
+/** callback to free a file fetch */
+static void fetch_file_free(void *ctx)
+{
+ struct fetch_file_context *c = ctx;
+ LOG(("context %p",ctx));
+
+ free(c->url);
+ free(c->path);
+ RING_REMOVE(ring, c);
+ free(ctx);
+}
+
+/** callback to start a file fetch */
+static bool fetch_file_start(void *ctx)
+{
+ LOG(("context %p",ctx));
+ return true;
+}
+
+/** callback to abort a file fetch */
+static void fetch_file_abort(void *ctx)
+{
+ struct fetch_file_context *c = ctx;
+ LOG(("context %p",ctx));
+
+ /* To avoid the poll loop having to deal with the fetch context
+ * disappearing from under it, we simply flag the abort here.
+ * The poll loop itself will perform the appropriate cleanup.
+ */
+ c->aborted = true;
+}
+
+
+/** Process object as a regular file */
+static void fetch_file_process_plain(struct fetch_file_context *ctx)
+{
+ char *buf;
+ size_t buf_size;
+
+ size_t tot_read = 0;
+ ssize_t res;
+
+ size_t size;
+
+ size = ctx->fstat.st_size;
+
+ /* set buffer size */
+ buf_size = size;
+ if (buf_size > FETCH_FILE_MAX_BUF_SIZE)
+ buf_size = FETCH_FILE_MAX_BUF_SIZE;
+
+ /* allocate the buffer storage */
+ buf = malloc(buf_size);
+ if (buf == NULL) {
+ fetch_file_send_callback(FETCH_ERROR, ctx,
+ "Unable to allocate memory for file data buffer",
+ 0, FETCH_ERROR_MEMORY);
+ return;
+ }
+
+ /* fetch is going to be successful */
+ fetch_set_http_code(ctx->fetchh, 200);
+
+ /* Any callback can result in the fetch being aborted.
+ * Therefore, we _must_ check for this after _every_ call to
+ * fetch_file_send_callback().
+ */
+
+ /* content type */
+ if (fetch_file_send_header(ctx, "Content-Type: %s", fetch_filetype(ctx->path)))
+ goto fetch_file_process_aborted;
+
+ /* content length */
+ if (fetch_file_send_header(ctx, "Content-Length: %zd", size))
+ goto fetch_file_process_aborted;
+
+ /* Set Last modified header */
+ if (fetch_file_send_time(ctx, "Last-Modified: %a, %d %b %Y %H:%M:%S GMT", &ctx->fstat.st_mtime))
+ goto fetch_file_process_aborted;
+
+ /* create etag */
+ if (fetch_file_send_header(ctx, "ETag: \"%10" PRId64 "\"", (int64_t) ctx->fstat.st_mtime))
+ goto fetch_file_process_aborted;
+
+ /* main data loop */
+ do {
+ res = read(ctx->fd, buf, buf_size);
+ if (res == -1) {
+ fetch_file_send_callback(FETCH_ERROR, ctx, "Error reading file", 0, FETCH_ERROR_PARTIAL_FILE);
+ return;
+ }
+
+
+ if (res == 0) {
+ fetch_file_send_callback(FETCH_ERROR, ctx, "Unexpected EOF reading file", 0, FETCH_ERROR_PARTIAL_FILE);
+ return;
+ }
+
+ tot_read += res;
+
+ if (fetch_file_send_callback(FETCH_DATA, ctx, buf, res, FETCH_ERROR_NO_ERROR))
+ break;
+
+ } while (tot_read < size);
+
+ if (!ctx->aborted)
+ fetch_file_send_callback(FETCH_FINISHED, ctx, 0, 0, FETCH_ERROR_NO_ERROR);
+
+fetch_file_process_aborted:
+
+ close(ctx->fd);
+ free(buf);
+ return;
+}
+
+static char *gen_nice_title(char *path)
+{
+ char *nice_path, *cnv, *tmp;
+ char *title;
+ int title_length;
+
+ /* Convert path for display */
+ nice_path = malloc(strlen(path) * 4 + 1);
+ if (!nice_path) {
+ return NULL;
+ }
+
+ /* Escape special HTML characters */
+ for (cnv = nice_path, tmp = path; *tmp != '\0'; tmp++) {
+ if (*tmp == '<') {
+ *cnv++ = '&';
+ *cnv++ = 'l';
+ *cnv++ = 't';
+ *cnv++ = ';';
+ } else if (*tmp == '>') {
+ *cnv++ = '&';
+ *cnv++ = 'g';
+ *cnv++ = 't';
+ *cnv++ = ';';
+ } else {
+ *cnv++ = *tmp;
+ }
+ }
+ *cnv = '\0';
+
+ /* Construct a localised title string */
+ title_length = strlen(nice_path) + strlen(messages_get("FileIndex"));
+ title = malloc(title_length);
+
+ if (title == NULL) {
+ return NULL;
+ }
+
+ /* Set title to localised "Index of <nice_path>" */
+ snprintf(title, title_length, messages_get("FileIndex"), nice_path);
+
+ free(nice_path);
+
+ return title;
+}
+
+static void fetch_file_process_error(struct fetch_file_context *ctx, int code)
+{
+ char buffer[1024];
+ const char *title;
+
+ /* content is going to return error code */
+ fetch_set_http_code(ctx->fetchh, code);
+
+ /* content type */
+ if (fetch_file_send_header(ctx, "Content-Type: text/html"))
+ goto fetch_file_process_error_aborted;
+
+ switch (code) {
+ case 401:
+ title = "Permission Denied";
+ break;
+
+ case 404:
+ title = "File not found";
+ break;
+
+ default:
+ title = "Internal Error";
+ }
+
+ snprintf(buffer, sizeof buffer, "<html><head><title>%s</title></head><body><h1>%s</h1><p>Error %d while fetching file %s</p></body></html>", title, title, code,ctx->url);
+
+ if (fetch_file_send_callback(FETCH_DATA, ctx, buffer, strlen(buffer), FETCH_ERROR_NO_ERROR))
+ goto fetch_file_process_error_aborted;
+
+ fetch_file_send_callback(FETCH_FINISHED, ctx, 0, 0, FETCH_ERROR_NO_ERROR);
+
+fetch_file_process_error_aborted:
+ return;
+}
+
+static void fetch_file_process_dir(struct fetch_file_context *ctx)
+{
+ char buffer[1024]; /* Output buffer */
+ bool even = false; /* formatting flag */
+ char *title; /* pretty printed title */
+ url_func_result res; /* result from url routines */
+ char *up; /* url of parent */
+ bool compare; /* result of url compare */
+
+ DIR *scandir; /* handle for enumerating the directory */
+ struct dirent* ent; /* leaf directory entry */
+ struct stat ent_stat; /* stat result of leaf entry */
+ char datebuf[64]; /* buffer for date text */
+ char timebuf[64]; /* buffer for time text */
+ char urlpath[PATH_MAX]; /* buffer for leaf entry path */
+
+#if defined(HAVE_FDOPENDIR)
+ scandir = fdopendir(ctx->fd);
+#else
+ /* this poses the possibility of a race where the directory
+ * has been removed from the namespace or resources for more
+ * fd are now unavailable between the previous open() and this
+ * call.
+ */
+ close(ctx->fd);
+ scandir = opendir(ctx->path);
+#endif
+
+ if (scandir == NULL) {
+ fetch_file_process_error(ctx, 500);
+ return;
+ }
+
+ /* fetch is going to be successful */
+ fetch_set_http_code(ctx->fetchh, 200);
+
+ /* content type */
+ if (fetch_file_send_header(ctx, "Content-Type: text/html"))
+ goto fetch_file_process_dir_aborted;
+
+ /* directory listing top */
+ dirlist_generate_top(buffer, sizeof buffer);
+ if (fetch_file_send_callback(FETCH_DATA, ctx, buffer, strlen(buffer), FETCH_ERROR_NO_ERROR))
+ goto fetch_file_process_dir_aborted;
+
+ /* directory listing title */
+ title = gen_nice_title(ctx->path);
+ dirlist_generate_title(title, buffer, sizeof buffer);
+ free(title);
+ if (fetch_file_send_callback(FETCH_DATA, ctx, buffer, strlen(buffer), FETCH_ERROR_NO_ERROR))
+ goto fetch_file_process_dir_aborted;
+
+ /* Print parent directory link */
+ res = url_parent(ctx->url, &up);
+ if (res == URL_FUNC_OK) {
+ res = url_compare(ctx->url, up, false, &compare);
+ if ((res == URL_FUNC_OK) && !compare) {
+ dirlist_generate_parent_link(up, buffer, sizeof buffer);
+
+ fetch_file_send_callback(FETCH_DATA, ctx,
+ buffer,
+ strlen(buffer),
+ FETCH_ERROR_NO_ERROR);
+
+ }
+ free(up);
+
+ if (ctx->aborted)
+ goto fetch_file_process_dir_aborted;
+
+ }
+
+ /* directory list headings */
+ dirlist_generate_headings(buffer, sizeof buffer);
+ if (fetch_file_send_callback(FETCH_DATA, ctx, buffer, strlen(buffer), FETCH_ERROR_NO_ERROR))
+ goto fetch_file_process_dir_aborted;
+
+ while ((ent = readdir(scandir)) != NULL) {
+
+ if (ent->d_name[0] == '.')
+ continue;
+
+ snprintf(urlpath,
+ sizeof urlpath,
+ "%s%s%s",
+ ctx->path,
+ (ctx->path[strlen(ctx->path) - 1] == '/')?"":"/" ,
+ ent->d_name);
+
+ if (stat(urlpath, &ent_stat) != 0) {
+ ent_stat.st_mode = 0;
+ datebuf[0] = 0;
+ timebuf[0] = 0;
+ } else {
+ /* Get date in output format */
+ if (strftime((char *)&datebuf, sizeof datebuf,
+ "%a %d %b %Y",
+ localtime(&ent_stat.st_mtime)) == 0) {
+ strncpy(datebuf, "-", sizeof datebuf);
+ }
+
+ /* Get time in output format */
+ if (strftime((char *)&timebuf, sizeof timebuf,
+ "%H:%M",
+ localtime(&ent_stat.st_mtime)) == 0) {
+ strncpy(timebuf, "-", sizeof timebuf);
+ }
+ }
+
+ if (S_ISREG(ent_stat.st_mode)) {
+ /* regular file */
+ dirlist_generate_row(even,
+ false,
+ urlpath,
+ ent->d_name,
+ fetch_filetype(urlpath),
+ ent_stat.st_size,
+ datebuf, timebuf,
+ buffer, sizeof(buffer));
+ } else if (S_ISDIR(ent_stat.st_mode)) {
+ /* directory */
+ dirlist_generate_row(even,
+ true,
+ urlpath,
+ ent->d_name,
+ messages_get("FileDirectory"),
+ -1,
+ datebuf, timebuf,
+ buffer, sizeof(buffer));
+ } else {
+ /* something else */
+ dirlist_generate_row(even,
+ false,
+ urlpath,
+ ent->d_name,
+ "",
+ -1,
+ datebuf, timebuf,
+ buffer, sizeof(buffer));
+ }
+
+ if (fetch_file_send_callback(FETCH_DATA, ctx,
+ buffer,
+ strlen(buffer),
+ FETCH_ERROR_NO_ERROR))
+ goto fetch_file_process_dir_aborted;
+
+ even = !even;
+ }
+
+ /* directory listing bottom */
+ dirlist_generate_bottom(buffer, sizeof buffer);
+ if (fetch_file_send_callback(FETCH_DATA, ctx, buffer, strlen(buffer), FETCH_ERROR_NO_ERROR))
+ goto fetch_file_process_dir_aborted;
+
+
+ fetch_file_send_callback(FETCH_FINISHED, ctx, 0, 0, FETCH_ERROR_NO_ERROR);
+
+fetch_file_process_dir_aborted:
+
+ closedir(scandir);
+}
+
+
+/* process a file fetch */
+static void fetch_file_process(struct fetch_file_context *ctx)
+{
+ ctx->fd = open(ctx->path, O_RDONLY);
+ if (ctx->fd < 0) {
+ /* process errors as appropriate */
+ switch (errno) {
+ case EACCES:
+ fetch_file_process_error(ctx, 401);
+ break;
+
+ case ENOENT:
+ fetch_file_process_error(ctx, 404);
+ break;
+
+ default:
+ fetch_file_process_error(ctx, 500);
+ break;
+ }
+ return;
+ }
+
+ if (fstat(ctx->fd, &ctx->fstat) != 0) {
+ /* process errors as appropriate */
+ close(ctx->fd);
+ fetch_file_process_error(ctx, 500);
+ return;
+ }
+
+#ifdef fetch_curl_modified_check
+ /* f was fetch_curl context and I cannot determine where f->last_modified was set */
+
+ /* Report not modified, if appropriate */
+ if (f->last_modified && f->file_etag &&
+ f->last_modified > s.st_mtime &&
+ f->file_etag == s.st_mtime) {
+ fetch_send_callback(FETCH_NOTMODIFIED,
+ f->fetch_handle, 0, 0,
+ FETCH_ERROR_NO_ERROR);
+ return true;
+ }
+#endif
+
+ if (S_ISDIR(ctx->fstat.st_mode)) {
+ /* directory listing */
+ fetch_file_process_dir(ctx);
+ return;
+ }
+
+ if (S_ISREG(ctx->fstat.st_mode)) {
+ /* not a file respose */
+ fetch_file_process_plain(ctx);
+ return;
+ }
+
+ close(ctx->fd);
+
+ return;
+}
+
+/** callback to poll for additional file fetch contents */
+static void fetch_file_poll(const char *scheme)
+{
+ struct fetch_file_context *c, *next;
+
+ if (ring == NULL) return;
+
+ /* Iterate over ring, processing each pending fetch */
+ c = ring;
+ do {
+ /* Take a copy of the next pointer as we may destroy
+ * the ring item we're currently processing */
+ next = c->r_next;
+
+ /* Ignore fetches that have been flagged as locked.
+ * This allows safe re-entrant calls to this function.
+ * Re-entrancy can occur if, as a result of a callback,
+ * the interested party causes fetch_poll() to be called
+ * again.
+ */
+ if (c->locked == true) {
+ continue;
+ }
+
+ LOG(("polling unlocked context %p",c));
+
+ /* Only process non-aborted fetches */
+ if (!c->aborted) {
+ /* file fetchs can be processed in one go */
+ fetch_file_process(c);
+ }
+
+
+ fetch_remove_from_queues(c->fetchh);
+ fetch_free(c->fetchh);
+
+ /* Advance to next ring entry, exiting if we've reached
+ * the start of the ring or the ring has become empty
+ */
+ } while ( (c = next) != ring && ring != NULL);
+}
+
+void fetch_file_register(void)
+{
+ fetch_add_fetcher("file",
+ fetch_file_initialise,
+ fetch_file_setup,
+ fetch_file_start,
+ fetch_file_abort,
+ fetch_file_free,
+ fetch_file_poll,
+ fetch_file_finalise);
+}
Index: content/fetchers/fetch_file.h
===================================================================
--- /dev/null 2009-04-16 19:17:07.000000000 +0100
+++ content/fetchers/fetch_file.h 2010-09-09 19:47:22.000000000 +0100
@@ -0,0 +1,28 @@
+/*
+ * Copyright 2010 Vincent Sanders <vince(a)netsurf-browser.org>
+ *
+ * This file is part of NetSurf.
+ *
+ * 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
+ * file: URL method handler
+ */
+
+#ifndef NETSURF_CONTENT_FETCHERS_FETCH_FILE_H
+#define NETSURF_CONTENT_FETCHERS_FETCH_FILE_H
+
+void fetch_file_register(void);
+
+#endif
Changed files
Makefile.sources | 4 +-
amiga/filetype.c | 5 ---
content/content.c | 5 ---
content/content_type.h | 1
content/dirlist.c | 46 +++++++++++++++++++++---------
content/dirlist.h | 8 ++---
content/fetch.c | 2 +
content/fetchers/fetch_curl.c | 64 +++---------------------------------------
render/box.c | 1
utils/config.h | 16 ++++++++++
utils/url.c | 21 +++++++++++++
utils/url.h | 1
12 files changed, 84 insertions(+), 90 deletions(-)
Index: render/box.c
===================================================================
--- render/box.c (revision 10746)
+++ render/box.c (working copy)
@@ -1169,7 +1169,6 @@
#ifdef WITH_PLUGIN
content_get_type(box->object) == CONTENT_PLUGIN ||
#endif
- content_get_type(box->object) == CONTENT_DIRECTORY ||
#ifdef WITH_THEME_INSTALL
content_get_type(box->object) == CONTENT_THEME ||
#endif
Index: Makefile.sources
===================================================================
--- Makefile.sources (revision 10746)
+++ Makefile.sources (working copy)
@@ -6,9 +6,9 @@
#
S_CONTENT := content.c dirlist.c fetch.c hlcache.c llcache.c urldb.c \
- fetchers/fetch_curl.c fetchers/fetch_data.c
+ fetchers/fetch_curl.c fetchers/fetch_data.c fetchers/fetch_file.c
S_CSS := css.c dump.c internal.c select.c utils.c
-S_RENDER := box.c box_construct.c box_normalise.c directory.c favicon.c \
+S_RENDER := box.c box_construct.c box_normalise.c favicon.c \
font.c form.c html.c html_interaction.c html_redraw.c \
hubbub_binding.c imagemap.c layout.c list.c table.c textplain.c
S_UTILS := base64.c filename.c hashtable.c http.c locale.c messages.c \
Index: utils/config.h
===================================================================
--- utils/config.h (revision 10746)
+++ utils/config.h (working copy)
@@ -20,6 +20,7 @@
#define _NETSURF_UTILS_CONFIG_H_
#include <stddef.h>
+#include <dirent.h>
/* Try to detect which features the target OS supports */
@@ -37,6 +38,21 @@
char *strcasestr(const char *haystack, const char *needle);
#endif
+/* fdopendir is actually present on most unix systems but unless
+ * _POSIX_C_SOURCE is set to 2008 it is not declared in the system
+ * headers. It is unavailable on RISC OS which requires fallback code
+ */
+#if (_POSIX_C_SOURCE - 0) >= 200809L
+#define HAVE_FDOPENDIR
+#else
+#if defined(riscos)
+#undef HAVE_FDOPENDIR
+#else
+#define HAVE_FDOPENDIR
+DIR *fdopendir(int fd);
+#endif
+#endif
+
/* For some reason, UnixLib defines this unconditionally.
* Assume we're using UnixLib if building for RISC OS. */
#if (defined(_GNU_SOURCE) || defined(riscos))
Index: utils/url.c
===================================================================
--- utils/url.c (revision 10746)
+++ utils/url.c (working copy)
@@ -902,7 +902,28 @@
return URL_FUNC_FAILED;
}
+/**
+ * Convert an escaped string to plain.
+ * \param result unescaped string owned by caller must be freed with free()
+ * \return URL_FUNC_OK on success
+ */
+url_func_result url_unescape(const char *str, char **result)
+{
+ char *curlstr;
+ char *retstr;
+ curlstr = curl_unescape(str, 0);
+ retstr = strdup(curlstr);
+ curl_free(curlstr);
+
+ if (retstr == NULL) {
+ return URL_FUNC_FAILED;
+ }
+
+ *result = retstr;
+ return URL_FUNC_OK;
+}
+
/**
* Escape a string suitable for inclusion in an URL.
*
Index: utils/url.h
===================================================================
--- utils/url.h (revision 10746)
+++ utils/url.h (working copy)
@@ -53,6 +53,7 @@
bool remove_extensions);
url_func_result url_escape(const char *unescaped, size_t toskip,
bool sptoplus, const char *escexceptions, char **result);
+url_func_result url_unescape(const char *str, char **result);
url_func_result url_canonical_root(const char *url, char **result);
url_func_result url_parent(const char *url, char **result);
url_func_result url_plq(const char *url, char **result);
Index: content/content.c
===================================================================
--- content/content.c (revision 10746)
+++ content/content.c (working copy)
@@ -38,7 +38,6 @@
#include "image/bitmap.h"
#include "desktop/browser.h"
#include "desktop/options.h"
-#include "render/directory.h"
#include "render/html.h"
#include "render/textplain.h"
#ifdef WITH_JPEG
@@ -109,7 +108,6 @@
#ifdef WITH_BMP
{"application/x-ico", CONTENT_ICO},
#endif
- {"application/x-netsurf-directory", CONTENT_DIRECTORY},
#ifdef WITH_THEME_INSTALL
{"application/x-netsurf-theme", CONTENT_THEME},
#endif
@@ -344,9 +342,6 @@
plugin_open, plugin_close, plugin_clone,
true},
#endif
- {directory_create, 0, directory_convert,
- 0, directory_destroy, 0, 0, 0, 0, 0, 0, 0, directory_clone,
- true},
#ifdef WITH_THEME_INSTALL
{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, false},
#endif
Index: content/dirlist.c
===================================================================
--- content/dirlist.c (revision 10746)
+++ content/dirlist.c (working copy)
@@ -51,9 +51,10 @@
* dirlist_generate_bottom()
*/
-const char* dirlist_generate_top(void)
+bool dirlist_generate_top(char *buffer, int buffer_length)
{
- return "<html>\n"
+ int error = snprintf(buffer, buffer_length,
+ "<html>\n"
"<head>\n"
"<style>\n"
"html, body { margin: 0; padding: 0; }\n"
@@ -61,7 +62,7 @@
"h1 { padding: 5mm; margin: 0; "
"border-bottom: 2px solid #bcf; }\n"
"p { padding: 2px 5mm; margin: 0; }\n"
- "div { display: table; width: 94%; margin: 5mm auto 0 auto; "
+ "div { display: table; width: 94%%; margin: 5mm auto 0 auto; "
"padding: 0; }\n"
"a, strong { display: table-row; margin: 0; padding: 0; }\n"
"a.odd { background-color: #bcf; }\n"
@@ -74,7 +75,14 @@
"a.dir > span.type { font-weight: bold; }\n"
"span.size { text-align: right; padding-right: 0.3em; }\n"
"span.size + span.size { text-align: left; "
- "padding-right: 0; }\n";
+ "padding-right: 0; }\n");
+ if (error < 0 || error >= buffer_length)
+ /* Error or buffer too small */
+ return false;
+ else
+ /* OK */
+ return true;
+
}
@@ -142,9 +150,14 @@
* dirlist_generate_bottom()
*/
-bool dirlist_generate_title(char *title, char *buffer, int buffer_length)
+bool dirlist_generate_title(const char *title, char *buffer, int buffer_length)
{
- int error = snprintf(buffer, buffer_length,
+ int error;
+
+ if (title == NULL)
+ title = "";
+
+ error = snprintf(buffer, buffer_length,
"</style>\n"
"<title>%s</title>\n"
"</head>\n"
@@ -245,7 +258,7 @@
* \param directory whether this row is for a directory (or a file)
* \param url url for row entry
* \param name name of row entry
- * \param type MIME type of row entry
+ * \param mimetype MIME type of row entry
* \param size size of row entry. If negative, size is left blank
* \param date date row entry was last modified
* \param time time row entry was last modified
@@ -266,7 +279,7 @@
*/
bool dirlist_generate_row(bool even, bool directory, char *url, char *name,
- char *type, long long size, char *date, char *time,
+ const char *mimetype, long long size, char *date, char *time,
char *buffer, int buffer_length)
{
const char *unit;
@@ -292,7 +305,7 @@
"<span class=\"time\">%s</span></a>\n",
url, even ? "even" : "odd",
directory ? "dir" : "file",
- name, type, size_string, unit, date, time);
+ name, mimetype, size_string, unit, date, time);
if (error < 0 || error >= buffer_length)
/* Error or buffer too small */
return false;
@@ -319,11 +332,18 @@
* dirlist_generate_bottom()
*/
-const char* dirlist_generate_bottom(void)
+bool dirlist_generate_bottom(char *buffer, int buffer_length)
{
- return "</div>\n"
- "</body>\n"
- "</html>\n";
+ int error = snprintf(buffer, buffer_length,
+ "</div>\n"
+ "</body>\n"
+ "</html>\n");
+ if (error < 0 || error >= buffer_length)
+ /* Error or buffer too small */
+ return false;
+ else
+ /* OK */
+ return true;
}
Index: content/dirlist.h
===================================================================
--- content/dirlist.h (revision 10746)
+++ content/dirlist.h (working copy)
@@ -33,15 +33,15 @@
#define DIRLIST_NO_DATE_COLUMN 1 << 3
#define DIRLIST_NO_TIME_COLUMN 1 << 4
-const char* dirlist_generate_top(void);
+bool dirlist_generate_top(char *buffer, int buffer_length);
bool dirlist_generate_hide_columns(int flags, char *buffer, int buffer_length);
-bool dirlist_generate_title(char *title, char *buffer, int buffer_length);
+bool dirlist_generate_title(const char *title, char *buffer, int buffer_length);
bool dirlist_generate_parent_link(char *parent, char *buffer,
int buffer_length);
bool dirlist_generate_headings(char *buffer, int buffer_length);
bool dirlist_generate_row(bool even, bool directory, char *url, char *name,
- char *type, long long size, char *date, char *time,
+ const char *mimetype, long long size, char *date, char *time,
char *buffer, int buffer_length);
-const char* dirlist_generate_bottom(void);
+bool dirlist_generate_bottom(char *buffer, int buffer_length);
#endif
Index: content/content_type.h
===================================================================
--- content/content_type.h (revision 10746)
+++ content/content_type.h (working copy)
@@ -59,7 +59,6 @@
#ifdef WITH_PLUGIN
CONTENT_PLUGIN,
#endif
- CONTENT_DIRECTORY,
#ifdef WITH_THEME_INSTALL
CONTENT_THEME,
#endif
Index: content/fetchers/fetch_curl.c
===================================================================
--- content/fetchers/fetch_curl.c (revision 10746)
+++ content/fetchers/fetch_curl.c (working copy)
@@ -217,7 +217,10 @@
data = curl_version_info(CURLVERSION_NOW);
- for (i = 0; data->protocols[i]; i++)
+ for (i = 0; data->protocols[i]; i++) {
+ if (strcmp(data->protocols[i], "file") == 0)
+ continue; /* do not use curl for file: */
+
if (!fetch_add_fetcher(data->protocols[i],
fetch_curl_initialise,
fetch_curl_setup,
@@ -229,6 +232,7 @@
LOG(("Unable to register cURL fetcher for %s",
data->protocols[i]));
}
+ }
return;
curl_easy_setopt_failed:
@@ -1155,64 +1159,6 @@
return true;
}
- /* find MIME type from filetype for local files */
- if (strncmp(f->url, FILE_SCHEME_PREFIX, FILE_SCHEME_PREFIX_LEN) == 0) {
- struct stat s;
- char *url_path = url_to_path(f->url);
-
- LOG(("Obtaining mime type for file %s", url_path));
-
- if (url_path != NULL && stat(url_path, &s) == 0) {
- /* file: URL and file exists */
- char header[64];
- const char *type;
-
- /* create etag */
- snprintf(header, sizeof header,
- "ETag: \"%10" PRId64 "\"",
- (int64_t) s.st_mtime);
- /* And send it to the header handler */
- fetch_send_callback(FETCH_HEADER, f->fetch_handle,
- header, strlen(header),
- FETCH_ERROR_NO_ERROR);
-
- /* create Content-Type */
- type = fetch_filetype(url_path);
- snprintf(header, sizeof header,
- "Content-Type: %s", type);
- /* Send it to the header handler */
- fetch_send_callback(FETCH_HEADER, f->fetch_handle,
- header, strlen(header),
- FETCH_ERROR_NO_ERROR);
-
- /* create Content-Length */
- snprintf(header, sizeof header,
- "Content-Length: %" PRId64,
- (int64_t) s.st_size);
- /* Send it to the header handler */
- fetch_send_callback(FETCH_HEADER, f->fetch_handle,
- header, strlen(header),
- FETCH_ERROR_NO_ERROR);
-
- /* don't set last modified time so as to ensure that
- * local files are revalidated at all times. */
-
- /* Report not modified, if appropriate */
- if (f->last_modified && f->file_etag &&
- f->last_modified > s.st_mtime &&
- f->file_etag == s.st_mtime) {
- fetch_send_callback(FETCH_NOTMODIFIED,
- f->fetch_handle, 0, 0,
- FETCH_ERROR_NO_ERROR);
- free(url_path);
- return true;
- }
- }
-
- if (url_path != NULL)
- free(url_path);
- }
-
if (f->abort)
return true;
Index: content/fetch.c
===================================================================
--- content/fetch.c (revision 10746)
+++ content/fetch.c (working copy)
@@ -38,6 +38,7 @@
#include "content/fetch.h"
#include "content/fetchers/fetch_curl.h"
#include "content/fetchers/fetch_data.h"
+#include "content/fetchers/fetch_file.h"
#include "content/urldb.h"
#include "desktop/netsurf.h"
#include "desktop/options.h"
@@ -106,6 +107,7 @@
{
fetch_curl_register();
fetch_data_register();
+ fetch_file_register();
fetch_active = false;
}
Index: amiga/filetype.c
===================================================================
--- amiga/filetype.c (revision 10746)
+++ amiga/filetype.c (working copy)
@@ -186,11 +186,6 @@
return "rosprite";
break;
#endif
-
- case CONTENT_DIRECTORY:
- return "drawer";
- break;
-
#if defined(WITH_NS_SVG) || defined(WITH_RSVG)
case CONTENT_SVG:
return "svg";
Conflicted files
Removed files
render/directory.c
render/directory.h
12 years, 4 months
Re: Font height in pixels
by m0n0
Am Samstag, den 11.09.2010, 11:10 +0200 schrieb Michael Drake
<tlsa(a)netsurf-browser.org>:
> Screen DPI is assumed to be 90, unless the front end sets it differently.
> The value is stored in nscss_screen_dpi in LibCSS's fixed point format.
>
> In css/utils.c:
>
> /** Screen DPI in fixed point units: defaults to 90, which RISC OS uses */
> css_fixed nscss_screen_dpi = INTTOFIX(90);
OK, thanks for the info.
Greets,
Ole
12 years, 4 months
Re: Font height in pixels
by Michael Drake
In article
<5df64e00b6996dc50cae5decc8bca706-EhVcX1lFRQVaRwYcDTpQCEFddQZLVF5dQUNBAjBTXF5bVkYJXV9oBlI6XF1XRUQEXV5bRA==-webmailer2@s,
m0n0 <ole(a)monochrom.net> wrote:
> I expect them to be specified by CSS, but mostly not in pixels....
> probably in points or EM or something like that, but not in pixels. And
> NetSurf doesn't know anything about my screen DPI, so there is no way to
> calculate the pixel size, isn't it?
Screen DPI is assumed to be 90, unless the front end sets it differently.
The value is stored in nscss_screen_dpi in LibCSS's fixed point format.
In css/utils.c:
/** Screen DPI in fixed point units: defaults to 90, which RISC OS uses */
css_fixed nscss_screen_dpi = INTTOFIX(90);
--
Michael Drake (tlsa) http://www.netsurf-browser.org/
12 years, 4 months
Plotter <-> browser window relation question
by m0n0
Hello to the list...
I'm currently looking at the implementation of the plotters. One thing
that makes me curious is the fact that all the plotter functions are
not chained to any window.
But how does NetSurf plotter calls distinguish between the different
browser windows? I mean, for example I'm opening page 1 in the first
window, then I open another Page 2 in another window. NetSurf will
render them both at the same time, but how do I know if the call to the
plotter is for Window 1 oder Window 2?
Or... if NetSurf just renders one single window (the window on
top),... how would I tell netsurf which browser window is topped?
Greets and Thanks for reading,
m
12 years, 4 months
Re: Drag Operations
by Chris Young
On Fri, 03 Sep 2010 12:54:23 +0200, m0n0 wrote:
> I'm currently implementing mouse events and I'm a bit confused by the
> amounts of dragging states... :
>
> BROWSER_MOUSE_DRAG_1
> BROWSER_MOUSE_DRAG_ON
> BROWSER_MOUSE_HOLDING_1
>
> Esepecially I can't see the difference between BROWSER_MOUSE_DRAG_ON
> and BROWSER_MOUSE_HOLDING_1 ...
You need to keep both of them set throughout the drag. Note there is
a MOUSE_HOLDING_2 as well for the second button.
MOUSE_DRAG_1 only needs to be set once at the start of the drag
operation.
> How do I report that an dragging operation has ended, does Netsurf
> recognize this automatically if none of the dragging flags are set?
Call browser_window_mouse_drag_end()
Chris
12 years, 5 months
Drag Operations
by m0n0
Hello to the list!
I'm currently implementing mouse events and I'm a bit confused by the
amounts of dragging states... :
BROWSER_MOUSE_DRAG_1
BROWSER_MOUSE_DRAG_ON
BROWSER_MOUSE_HOLDING_1
Esepecially I can't see the difference between BROWSER_MOUSE_DRAG_ON
and BROWSER_MOUSE_HOLDING_1 ...
The comment for DRAG_ON says:
/* a drag operation was started and a mouse button is still pressed */
Isn't an drag operation ALWAYS in conjuction with an mouse button
still pressed? otherwise it wouldn't be an dragging operation, or is
that wrong?
Comment for MOUSE_HOLDING_1:
/* while button 1 drag is in progress */
To me this sounds this has to be reported when: a mouse button is
still pressed.
How do I report that an dragging operation has ended, does Netsurf
recognize this automatically if none of the dragging flags are set?
Thanks & Greets,
Ole
12 years, 5 months