On Thu, 2010-09-09 at 20:19 +0100, John-Mark Bell wrote:
> 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 <[email protected]>
> + *
> + * 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 */

Kendrick.

> +
> +#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;

Call fetch_file_send_callback, instead?

> +     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));

Presumably redundant now?

> +     ctx->locked = true;
> +     fetch_send_callback(FETCH_HEADER, ctx->fetchh, header, strlen(header), 
> FETCH_ERROR_NO_ERROR);
> +     ctx->locked = false;

fetch_file_send_callback?

> +     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));
> +}

This logging is probably unnecessary now.

> +/** 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) {

Ensure URL_FUNC_OK here

free(ctx->url);

> +             free(ctx);
> +             return NULL;
> +     }
> +
> +     url_unescape(path, &ctx->path);
> +     if (ctx->path == NULL) {

Ensure URL_FUNC_OK here

> +             free(path);

free(ctx->url);

> +             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));

Lose this logging?
        
> +     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));

Ditto

fd?

> +     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));

Lose logging

> +     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));

Ditto

> +     /* 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);          

free(buf);

> +                     return;
> +             }
> +
> +
> +             if (res == 0) {
> +                     fetch_file_send_callback(FETCH_ERROR, ctx, "Unexpected 
> EOF reading file", 0, FETCH_ERROR_PARTIAL_FILE); 

free(buf);

> +                     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);

Where is this opened? Does it also need closing in the error cases,
above?

> +     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) {

nice_path == NULL is preferable

> +             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;
> +             }

Also, '&' -> "&amp;", to be safe.

> +     }
> +     *cnv = '\0';
> +
> +     /* Construct a localised title string */
> +     title_length = strlen(nice_path) + strlen(messages_get("FileIndex"));

strlen(nice_path) == cnv - nice_path

> +     title = malloc(title_length);

Add 1 for the trailing NUL?

> +     if (title == NULL) {

free(nice_path);

> +             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";
> +     }

You can simplify this by doing this:

char key[8];

snprintf(key, sizeof key, "HTTP%03d", code);

title = messages_get(key);

> +     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;

Lose an indent level here.

> +     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;

403 is a better response code for this case

> +             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       

Lose this?

> +     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 */

What?

> +             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));

Lose this logging

> +             /* Only process non-aborted fetches */
> +             if (!c->aborted) {
> +                     /* file fetchs can be processed in one go */

fetches

> +                     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 <[email protected]>
> + *
> + * 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

We can't provide this ourselves. Therefore, should this non-POSIX 2008
case simply be #undef HAVE_FDOPENDIR?

> +#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);

if (curlstr == NULL)
        return URL_FUNC_NOMEM;

> +     retstr = strdup(curlstr);
> +     curl_free(curlstr);
> +
> +     if (retstr == NULL) {
> +             return URL_FUNC_FAILED;

URL_FUNC_NOMEM

> +     }
> +
> +     *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
> 


Reply via email to