mirror of
https://github.com/netsurf-browser/netsurf
synced 2024-11-22 22:41:30 +03:00
Merge branches/vince/netsurf-file-fetcher to trunk
r=jmb svn path=/trunk/netsurf/; revision=10750
This commit is contained in:
parent
b9773d34bb
commit
2077918805
@ -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 \
|
||||
|
@ -186,11 +186,6 @@ const char *ami_content_type_to_file_type(content_type type)
|
||||
return "rosprite";
|
||||
break;
|
||||
#endif
|
||||
|
||||
case CONTENT_DIRECTORY:
|
||||
return "drawer";
|
||||
break;
|
||||
|
||||
#if defined(WITH_NS_SVG) || defined(WITH_RSVG)
|
||||
case CONTENT_SVG:
|
||||
return "svg";
|
||||
|
@ -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 @@ static const struct mime_entry mime_map[] = {
|
||||
#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 @@ static const struct handler_entry handler_map[] = {
|
||||
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
|
||||
|
@ -59,7 +59,6 @@ typedef enum {
|
||||
#ifdef WITH_PLUGIN
|
||||
CONTENT_PLUGIN,
|
||||
#endif
|
||||
CONTENT_DIRECTORY,
|
||||
#ifdef WITH_THEME_INSTALL
|
||||
CONTENT_THEME,
|
||||
#endif
|
||||
|
@ -51,9 +51,10 @@ static char* dirlist_filesize_unit(unsigned long bytesize);
|
||||
* 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 @@ const char* dirlist_generate_top(void)
|
||||
"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 @@ const char* dirlist_generate_top(void)
|
||||
"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 @@ bool dirlist_generate_hide_columns(int flags, char *buffer, int buffer_length)
|
||||
* 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 @@ bool dirlist_generate_headings(char *buffer, int buffer_length)
|
||||
* \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_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 *unit;
|
||||
@ -292,7 +305,7 @@ bool dirlist_generate_row(bool even, bool directory, char *url, char *name,
|
||||
"<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 @@ bool dirlist_generate_row(bool even, bool directory, char *url, char *name,
|
||||
* 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;
|
||||
}
|
||||
|
||||
|
||||
|
@ -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
|
||||
|
@ -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 @@ void fetch_init(void)
|
||||
{
|
||||
fetch_curl_register();
|
||||
fetch_data_register();
|
||||
fetch_file_register();
|
||||
fetch_active = false;
|
||||
}
|
||||
|
||||
|
@ -217,7 +217,10 @@ void fetch_curl_register(void)
|
||||
|
||||
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 @@ void fetch_curl_register(void)
|
||||
LOG(("Unable to register cURL fetcher for %s",
|
||||
data->protocols[i]));
|
||||
}
|
||||
}
|
||||
return;
|
||||
|
||||
curl_easy_setopt_failed:
|
||||
@ -1155,64 +1159,6 @@ bool fetch_curl_process_headers(struct curl_fetch_info *f)
|
||||
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;
|
||||
|
||||
|
617
content/fetchers/fetch_file.c
Normal file
617
content/fetchers/fetch_file.c
Normal file
@ -0,0 +1,617 @@
|
||||
/*
|
||||
* Copyright 2010 Vincent Sanders <vince@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 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() */
|
||||
};
|
||||
|
||||
static struct fetch_file_context *ring = NULL;
|
||||
|
||||
/** issue fetch callbacks with locking */
|
||||
static inline 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);
|
||||
|
||||
fetch_file_send_callback(FETCH_HEADER, ctx, header, strlen(header), FETCH_ERROR_NO_ERROR);
|
||||
|
||||
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);
|
||||
|
||||
fetch_file_send_callback(FETCH_HEADER, ctx, header, strlen(header), FETCH_ERROR_NO_ERROR);
|
||||
|
||||
return ctx->aborted;
|
||||
}
|
||||
|
||||
/** callback to initialise the file fetcher. */
|
||||
static bool fetch_file_initialise(const char *scheme)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
/** callback to initialise the file fetcher. */
|
||||
static void fetch_file_finalise(const char *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;
|
||||
char *path;
|
||||
url_func_result res; /* result from url routines */
|
||||
|
||||
ctx = calloc(1, sizeof(*ctx));
|
||||
if (ctx == NULL)
|
||||
return NULL;
|
||||
|
||||
res = url_path(url, &path);
|
||||
if (res != URL_FUNC_OK) {
|
||||
free(ctx);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
res = url_unescape(path, &ctx->path);
|
||||
free(path);
|
||||
if (res != URL_FUNC_OK) {
|
||||
free(ctx);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
ctx->url = strdup(url);
|
||||
if (ctx->url == NULL) {
|
||||
free(ctx->path);
|
||||
free(ctx);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
ctx->fetchh = fetchh;
|
||||
|
||||
RING_INSERT(ring, ctx);
|
||||
|
||||
return ctx;
|
||||
}
|
||||
|
||||
/** callback to free a file fetch */
|
||||
static void fetch_file_free(void *ctx)
|
||||
{
|
||||
struct fetch_file_context *c = 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)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
/** callback to abort a file fetch */
|
||||
static void fetch_file_abort(void *ctx)
|
||||
{
|
||||
struct fetch_file_context *c = 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;
|
||||
}
|
||||
|
||||
static void fetch_file_process_error(struct fetch_file_context *ctx, int code)
|
||||
{
|
||||
char buffer[1024];
|
||||
const char *title;
|
||||
char key[8];
|
||||
|
||||
/* 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;
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
|
||||
/** Process object as a regular file */
|
||||
static void fetch_file_process_plain(struct fetch_file_context *ctx,
|
||||
int fd, struct stat *fdstat)
|
||||
{
|
||||
char *buf;
|
||||
size_t buf_size;
|
||||
|
||||
ssize_t tot_read = 0;
|
||||
ssize_t res;
|
||||
|
||||
/* set buffer size */
|
||||
buf_size = fdstat->st_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", fdstat->st_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", &fdstat->st_mtime))
|
||||
goto fetch_file_process_aborted;
|
||||
|
||||
/* create etag */
|
||||
if (fetch_file_send_header(ctx, "ETag: \"%10" PRId64 "\"", (int64_t) fdstat->st_mtime))
|
||||
goto fetch_file_process_aborted;
|
||||
|
||||
/* main data loop */
|
||||
do {
|
||||
res = read(fd, buf, buf_size);
|
||||
if (res == -1) {
|
||||
fetch_file_send_callback(FETCH_ERROR, ctx, "Error reading file", 0, FETCH_ERROR_PARTIAL_FILE);
|
||||
goto fetch_file_process_aborted;
|
||||
}
|
||||
|
||||
if (res == 0) {
|
||||
fetch_file_send_callback(FETCH_ERROR, ctx, "Unexpected EOF reading file", 0, FETCH_ERROR_PARTIAL_FILE);
|
||||
goto fetch_file_process_aborted;
|
||||
}
|
||||
|
||||
tot_read += res;
|
||||
|
||||
if (fetch_file_send_callback(FETCH_DATA, ctx, buf, res, FETCH_ERROR_NO_ERROR))
|
||||
break;
|
||||
|
||||
} while (tot_read < fdstat->st_size);
|
||||
|
||||
if (!ctx->aborted)
|
||||
fetch_file_send_callback(FETCH_FINISHED, ctx, 0, 0, FETCH_ERROR_NO_ERROR);
|
||||
|
||||
fetch_file_process_aborted:
|
||||
|
||||
close(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) * SLEN("&") + 1);
|
||||
if (nice_path == NULL) {
|
||||
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 if (*tmp == '&') {
|
||||
*cnv++ = '&';
|
||||
*cnv++ = 'a';
|
||||
*cnv++ = 'm';
|
||||
*cnv++ = 'p';
|
||||
*cnv++ = ';';
|
||||
} else {
|
||||
*cnv++ = *tmp;
|
||||
}
|
||||
}
|
||||
*cnv = '\0';
|
||||
|
||||
/* Construct a localised title string */
|
||||
title_length = (cnv - nice_path) + strlen(messages_get("FileIndex"));
|
||||
title = malloc(title_length + 1);
|
||||
|
||||
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_dir(struct fetch_file_context *ctx,
|
||||
int fd, struct stat *fdstat)
|
||||
{
|
||||
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(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(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)
|
||||
{
|
||||
int fd; /**< The file descriptor of the object */
|
||||
struct stat fdstat; /**< The objects stat */
|
||||
|
||||
fd = open(ctx->path, O_RDONLY);
|
||||
if (fd < 0) {
|
||||
/* process errors as appropriate */
|
||||
switch (errno) {
|
||||
case EACCES:
|
||||
fetch_file_process_error(ctx, 403);
|
||||
break;
|
||||
|
||||
case ENOENT:
|
||||
fetch_file_process_error(ctx, 404);
|
||||
break;
|
||||
|
||||
default:
|
||||
fetch_file_process_error(ctx, 500);
|
||||
break;
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
if (fstat(fd, &fdstat) != 0) {
|
||||
/* process errors as appropriate */
|
||||
close(fd);
|
||||
fetch_file_process_error(ctx, 500);
|
||||
return;
|
||||
}
|
||||
|
||||
if (S_ISDIR(fdstat.st_mode)) {
|
||||
/* directory listing */
|
||||
fetch_file_process_dir(ctx, fd, &fdstat);
|
||||
return;
|
||||
} else if (S_ISREG(fdstat.st_mode)) {
|
||||
/* regular file */
|
||||
fetch_file_process_plain(ctx, fd, &fdstat);
|
||||
return;
|
||||
} else {
|
||||
/* unhandled type of file */
|
||||
close(fd);
|
||||
fetch_file_process_error(ctx, 501);
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
/* Only process non-aborted fetches */
|
||||
if (!c->aborted) {
|
||||
/* file fetches 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);
|
||||
}
|
28
content/fetchers/fetch_file.h
Normal file
28
content/fetchers/fetch_file.h
Normal file
@ -0,0 +1,28 @@
|
||||
/*
|
||||
* Copyright 2010 Vincent Sanders <vince@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
|
@ -1169,7 +1169,6 @@ bool box_duplicate_main_tree(struct box *box, struct content *c, int *count)
|
||||
#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
|
||||
|
@ -1,291 +0,0 @@
|
||||
/*
|
||||
* Copyright 2006 Richard Wilson <info@tinct.net>
|
||||
* Copyright 2010 Chris Young <chris@unsatisfactorysoftware.co.uk>
|
||||
* Copyright 2010 Michael Drake <tlsa@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
|
||||
* Content for directory listings (implementation).
|
||||
*/
|
||||
|
||||
#include <sys/types.h>
|
||||
#include <dirent.h>
|
||||
#include <stdbool.h>
|
||||
#include <string.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <sys/stat.h>
|
||||
#include <time.h>
|
||||
#include "content/content_protected.h"
|
||||
#include "content/dirlist.h"
|
||||
#include "content/fetch.h"
|
||||
#include "render/directory.h"
|
||||
#include "render/html.h"
|
||||
#include "utils/messages.h"
|
||||
#include "utils/url.h"
|
||||
#include "utils/utils.h"
|
||||
|
||||
#define MAX_LENGTH 2048
|
||||
|
||||
bool directory_create(struct content *c, const struct http_parameter *params) {
|
||||
if (!html_create(c, params))
|
||||
/* html_create() must have broadcast MSG_ERROR already, so we
|
||||
* don't need to. */
|
||||
return false;
|
||||
|
||||
binding_parse_chunk(c->data.html.parser_binding,
|
||||
(uint8_t *) dirlist_generate_top(),
|
||||
strlen(dirlist_generate_top()));
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool directory_convert(struct content *c) {
|
||||
char *path;
|
||||
DIR *parent;
|
||||
struct dirent *entry;
|
||||
union content_msg_data msg_data;
|
||||
char buffer[MAX_LENGTH];
|
||||
char *nice_path, *cnv, *tmp;
|
||||
url_func_result res;
|
||||
bool compare, directory;
|
||||
char *up;
|
||||
struct stat filestat;
|
||||
char *filepath, *mimetype = NULL;
|
||||
int filepath_size;
|
||||
char *urlpath;
|
||||
int urlpath_size;
|
||||
char moddate[100];
|
||||
char modtime[100];
|
||||
long long filesize;
|
||||
bool extendedinfo, evenrow = false;
|
||||
char *title;
|
||||
int title_length;
|
||||
|
||||
/* Get directory path from URL */
|
||||
path = url_to_path(content__get_url(c));
|
||||
if (!path) {
|
||||
msg_data.error = messages_get("NoMemory");
|
||||
content_broadcast(c, CONTENT_MSG_ERROR, msg_data);
|
||||
return false;
|
||||
}
|
||||
|
||||
/* Convert path for display */
|
||||
nice_path = malloc(strlen(path) * 4 + 1);
|
||||
if (!nice_path) {
|
||||
msg_data.error = messages_get("MiscErr");
|
||||
content_broadcast(c, CONTENT_MSG_ERROR, msg_data);
|
||||
return false;
|
||||
}
|
||||
/* 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';
|
||||
|
||||
/* Set which columns to suppress */
|
||||
dirlist_generate_hide_columns(0, buffer, MAX_LENGTH);
|
||||
|
||||
binding_parse_chunk(c->data.html.parser_binding,
|
||||
(uint8_t *) buffer, strlen(buffer));
|
||||
|
||||
/* Construct a localised title string */
|
||||
title_length = strlen(nice_path) + strlen(messages_get("FileIndex"));
|
||||
title = malloc(title_length);
|
||||
|
||||
if(title == NULL) {
|
||||
msg_data.error = messages_get("NoMemory");
|
||||
content_broadcast(c, CONTENT_MSG_ERROR, msg_data);
|
||||
return false;
|
||||
}
|
||||
|
||||
/* Set title to localised "Index of <nice_path>" */
|
||||
snprintf(title, title_length, messages_get("FileIndex"), nice_path);
|
||||
|
||||
/* Print document title and heading */
|
||||
dirlist_generate_title(title, buffer, MAX_LENGTH);
|
||||
free(nice_path);
|
||||
free(title);
|
||||
|
||||
binding_parse_chunk(c->data.html.parser_binding,
|
||||
(uint8_t *) buffer, strlen(buffer));
|
||||
|
||||
/* Print parent directory link */
|
||||
res = url_parent(content__get_url(c), &up);
|
||||
if (res == URL_FUNC_OK) {
|
||||
res = url_compare(content__get_url(c), up, false, &compare);
|
||||
if ((res == URL_FUNC_OK) && !compare) {
|
||||
dirlist_generate_parent_link(up, buffer, MAX_LENGTH);
|
||||
|
||||
binding_parse_chunk(c->data.html.parser_binding,
|
||||
(uint8_t *) buffer, strlen(buffer));
|
||||
}
|
||||
free(up);
|
||||
}
|
||||
|
||||
/* Print directory contents table column headings */
|
||||
dirlist_generate_headings(buffer, MAX_LENGTH);
|
||||
|
||||
binding_parse_chunk(c->data.html.parser_binding,
|
||||
(uint8_t *) buffer, strlen(buffer));
|
||||
|
||||
if ((parent = opendir(path)) == NULL) {
|
||||
msg_data.error = messages_get("EmptyErr");
|
||||
content_broadcast(c, CONTENT_MSG_ERROR, msg_data);
|
||||
return false;
|
||||
}
|
||||
|
||||
/* Print a row for each item in the directory */
|
||||
while ((entry = readdir(parent)) != NULL) {
|
||||
if (!strcmp(entry->d_name, ".") ||
|
||||
!strcmp(entry->d_name, ".."))
|
||||
/* Skip . and .. entries */
|
||||
continue;
|
||||
|
||||
filepath_size = strlen(path) + strlen(entry->d_name) + 2;
|
||||
filepath = malloc(filepath_size);
|
||||
if (filepath != NULL) {
|
||||
strcpy(filepath, path);
|
||||
if (path_add_part(filepath, filepath_size,
|
||||
entry->d_name) == false) {
|
||||
msg_data.error = messages_get("MiscErr");
|
||||
content_broadcast(c, CONTENT_MSG_ERROR,
|
||||
msg_data);
|
||||
return false;
|
||||
}
|
||||
if (stat(filepath, &filestat) == 0)
|
||||
extendedinfo = true;
|
||||
else
|
||||
extendedinfo = false;
|
||||
} else {
|
||||
msg_data.error = messages_get("MiscErr");
|
||||
content_broadcast(c, CONTENT_MSG_ERROR, msg_data);
|
||||
return false;
|
||||
}
|
||||
|
||||
if (S_ISDIR(filestat.st_mode))
|
||||
directory = true;
|
||||
else
|
||||
directory = false;
|
||||
|
||||
urlpath_size = strlen(content__get_url(c)) +
|
||||
strlen(entry->d_name) + 2;
|
||||
urlpath = malloc(urlpath_size);
|
||||
if (urlpath != NULL) {
|
||||
strcpy(urlpath, content__get_url(c));
|
||||
if(urlpath[strlen(urlpath) - 1] != '/')
|
||||
strncat(urlpath, "/", urlpath_size);
|
||||
strncat(urlpath, entry->d_name, urlpath_size);
|
||||
|
||||
if (extendedinfo == true) {
|
||||
/* Get date in output format */
|
||||
if (strftime((char *)&moddate, sizeof moddate,
|
||||
"%a %d %b %Y",
|
||||
localtime(
|
||||
&filestat.st_mtime)) == 0)
|
||||
strncpy(moddate, "-", sizeof moddate);
|
||||
/* Get time in output format */
|
||||
if (strftime((char *)&modtime, sizeof modtime,
|
||||
"%H:%M",
|
||||
localtime(
|
||||
&filestat.st_mtime)) == 0)
|
||||
strncpy(modtime, "-", sizeof modtime);
|
||||
|
||||
if (directory) {
|
||||
mimetype = strdup((char*)messages_get(
|
||||
"FileDirectory"));
|
||||
filesize = -1;
|
||||
} else {
|
||||
mimetype = fetch_mimetype(filepath);
|
||||
filesize = (long long)
|
||||
filestat.st_size;
|
||||
}
|
||||
} else {
|
||||
strncpy(moddate, "", sizeof moddate);
|
||||
strncpy(modtime, "", sizeof modtime);
|
||||
filesize = -1;
|
||||
}
|
||||
/* Print row */
|
||||
dirlist_generate_row(evenrow, directory,
|
||||
urlpath, entry->d_name,
|
||||
mimetype ? mimetype : (char*)"",
|
||||
filesize,
|
||||
moddate, modtime,
|
||||
buffer, MAX_LENGTH);
|
||||
|
||||
binding_parse_chunk(c->data.html.parser_binding,
|
||||
(uint8_t *) buffer, strlen(buffer));
|
||||
|
||||
free(urlpath);
|
||||
}
|
||||
|
||||
if (evenrow == false)
|
||||
evenrow = true;
|
||||
else
|
||||
evenrow = false;
|
||||
|
||||
if (mimetype != NULL) {
|
||||
free(mimetype);
|
||||
mimetype = NULL;
|
||||
}
|
||||
free(filepath);
|
||||
}
|
||||
closedir(parent);
|
||||
|
||||
binding_parse_chunk(c->data.html.parser_binding,
|
||||
(uint8_t *) dirlist_generate_bottom(),
|
||||
strlen(dirlist_generate_bottom()));
|
||||
|
||||
c->type = CONTENT_HTML;
|
||||
return html_convert(c);
|
||||
}
|
||||
|
||||
void directory_destroy(struct content *c)
|
||||
{
|
||||
/* This will only get called if the content is destroyed before
|
||||
* content_convert() is called. Simply force the type to HTML and
|
||||
* delegate the cleanup to html_destroy() */
|
||||
|
||||
c->type = CONTENT_HTML;
|
||||
|
||||
html_destroy(c);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
bool directory_clone(const struct content *old, struct content *new_content)
|
||||
{
|
||||
/* This will only get called if the content is cloned before
|
||||
* content_convert() is called. Simply replay creation. */
|
||||
if (directory_create(new_content, NULL) == false)
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
@ -1,38 +0,0 @@
|
||||
/*
|
||||
* Copyright 2006 Richard Wilson <info@tinct.net>
|
||||
*
|
||||
* 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
|
||||
* Content for directory listings (interface).
|
||||
*
|
||||
* These functions should in general be called via the content interface.
|
||||
*/
|
||||
|
||||
#ifndef _NETSURF_RENDER_DIRECTORY_H_
|
||||
#define _NETSURF_RENDER_DIRECTORY_H_
|
||||
|
||||
#include <stdbool.h>
|
||||
#include "content/content_type.h"
|
||||
|
||||
struct http_parameter;
|
||||
|
||||
bool directory_create(struct content *c, const struct http_parameter *params);
|
||||
bool directory_convert(struct content *c);
|
||||
void directory_destroy(struct content *c);
|
||||
bool directory_clone(const struct content *old, struct content *new_content);
|
||||
|
||||
#endif
|
@ -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 *strndup(const char *s, size_t n);
|
||||
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))
|
||||
|
25
utils/url.c
25
utils/url.c
@ -902,6 +902,31 @@ no_path:
|
||||
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_NOMEM;
|
||||
}
|
||||
|
||||
*result = retstr;
|
||||
return URL_FUNC_OK;
|
||||
}
|
||||
|
||||
/**
|
||||
* Escape a string suitable for inclusion in an URL.
|
||||
|
@ -53,6 +53,7 @@ url_func_result url_nice(const char *url, char **result,
|
||||
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);
|
||||
|
Loading…
Reference in New Issue
Block a user