NetSurf
fetch.c
Go to the documentation of this file.
1/*
2 * Copyright 2007, 2014 Vincent Sanders <vince@netsurf-browser.org>
3 * Copyright 2007 Rob Kendrick <rjek@netsurf-browser.org>
4 *
5 * This file is part of NetSurf, http://www.netsurf-browser.org/
6 *
7 * NetSurf is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation; version 2 of the License.
10 *
11 * NetSurf is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License
17 * along with this program. If not, see <http://www.gnu.org/licenses/>.
18 */
19
20/**
21 * \file
22 * file extension to mimetype mapping for the GTK frontend
23 *
24 * allows GTK frontend to map file extension to mime types using a
25 * default builtin list and /etc/mime.types file if present.
26 *
27 * mime type and content type handling is derived from the BNF in
28 * RFC822 section 3.3, RFC2045 section 5.1 and RFC6838 section
29 * 4.2. Upshot is their charset and parsing is all a strict subset of
30 * ASCII hence not using locale dependant ctype functions for parsing.
31 */
32
33#include <stdint.h>
34#include <stdio.h>
35#include <stdlib.h>
36#include <sys/types.h>
37#include <sys/stat.h>
38#include <unistd.h>
39#include <string.h>
40#include <strings.h>
41#include <gtk/gtk.h>
42
43#include "utils/log.h"
44#include "utils/hashtable.h"
45#include "utils/filepath.h"
46#include "utils/file.h"
47#include "utils/nsurl.h"
48#include "utils/ascii.h"
49#include "netsurf/fetch.h"
50
51#include "gtk/gui.h"
52#include "gtk/resources.h"
53#include "gtk/fetch.h"
54
55#define HASH_SIZE 117
56#define MAX_LINE_LEN 256
57
58static struct hash_table *mime_hash = NULL;
59
60void gtk_fetch_filetype_init(const char *mimefile)
61{
62 struct stat statbuf;
63 FILE *fh = NULL;
64
66
67 /* Some OSes (mentioning no Solarises) have a worthlessly tiny
68 * /etc/mime.types that don't include essential things, so we
69 * pre-seed our hash with the essentials. These will get
70 * over-ridden if they are mentioned in the mime.types file.
71 */
72
73 hash_add(mime_hash, "css", "text/css");
74 hash_add(mime_hash, "htm", "text/html");
75 hash_add(mime_hash, "html", "text/html");
76 hash_add(mime_hash, "jpg", "image/jpeg");
77 hash_add(mime_hash, "jpeg", "image/jpeg");
78 hash_add(mime_hash, "jxl", "image/jxl");
79 hash_add(mime_hash, "gif", "image/gif");
80 hash_add(mime_hash, "png", "image/png");
81 hash_add(mime_hash, "jng", "image/jng");
82 hash_add(mime_hash, "mng", "image/mng");
83 hash_add(mime_hash, "webp", "image/webp");
84 hash_add(mime_hash, "spr", "image/x-riscos-sprite");
85 hash_add(mime_hash, "bmp", "image/bmp");
86
87 /* first, check to see if /etc/mime.types in preference */
88 if ((stat("/etc/mime.types", &statbuf) == 0) &&
89 S_ISREG(statbuf.st_mode)) {
90 mimefile = "/etc/mime.types";
91 }
92
93 fh = fopen(mimefile, "r");
94 if (fh == NULL) {
95 NSLOG(netsurf, INFO,
96 "Unable to open a mime.types file, so using a minimal one for you.");
97 return;
98 }
99
100 while (feof(fh) == 0) {
101 char line[MAX_LINE_LEN], *ptr, *type, *ext;
102
103 if (fgets(line, sizeof(line), fh) == NULL)
104 break;
105
106 if ((feof(fh) == 0) && line[0] != '#') {
107 ptr = line;
108
109 /* search for the first non-whitespace character */
110 while (ascii_is_space(*ptr)) {
111 ptr++;
112 }
113
114 /* is this line empty other than leading whitespace? */
115 if (*ptr == '\n' || *ptr == '\0') {
116 continue;
117 }
118
119 type = ptr;
120
121 /* search for the first whitespace char or NUL or
122 * NL */
123 while (*ptr && (!ascii_is_space(*ptr))) {
124 ptr++;
125 }
126
127 if (*ptr == '\0' || *ptr == '\n') {
128 /* this mimetype has no extensions - read next
129 * line.
130 */
131 continue;
132 }
133
134 *ptr++ = '\0';
135
136 /* search for the first non-whitespace character which
137 * will be the first filename extenion */
138 while (ascii_is_space(*ptr)) {
139 ptr++;
140 }
141
142 while (true) {
143 ext = ptr;
144
145 /* search for the first whitespace char or
146 * NUL or NL which is the end of the ext.
147 */
148 while (*ptr && (!ascii_is_space(*ptr))) {
149 ptr++;
150 }
151
152 if (*ptr == '\0' || *ptr == '\n') {
153 /* special case for last extension on
154 * the line
155 */
156 *ptr = '\0';
157 hash_add(mime_hash, ext, type);
158 break;
159 }
160
161 *ptr++ = '\0';
162 hash_add(mime_hash, ext, type);
163
164 /* search for the first non-whitespace char or
165 * NUL or NL, to find start of next ext.
166 */
167 while (*ptr &&
168 (ascii_is_space(*ptr)) &&
169 *ptr != '\n') {
170 ptr++;
171 }
172 }
173 }
174 }
175
176 fclose(fh);
177}
178
180{
182}
183
184const char *fetch_filetype(const char *unix_path)
185{
186 struct stat statbuf;
187 char *ext;
188 const char *ptr;
189 char *lowerchar;
190 const char *type;
191 int l;
192
193 /* stat the path to attempt to determine if the file is special */
194 if (stat(unix_path, &statbuf) == 0) {
195 /* stat suceeded so can check for directory */
196
197 if (S_ISDIR(statbuf.st_mode)) {
198 return "application/x-netsurf-directory";
199 }
200 }
201
202 l = strlen(unix_path);
203
204 /* Hacky RISC OS compatibility */
205 if ((3 < l) && (strcasecmp(unix_path + l - 4, ",f79") == 0)) {
206 return "text/css";
207 } else if ((3 < l) && (strcasecmp(unix_path + l - 4, ",faf") == 0)) {
208 return "text/html";
209 } else if ((3 < l) && (strcasecmp(unix_path + l - 4, ",b60") == 0)) {
210 return "image/png";
211 } else if ((3 < l) && (strcasecmp(unix_path + l - 4, ",ff9") == 0)) {
212 return "image/x-riscos-sprite";
213 }
214
215 if (strchr(unix_path, '.') == NULL) {
216 /* no extension anywhere! */
217 return "text/plain";
218 }
219
220 ptr = unix_path + strlen(unix_path);
221 while (*ptr != '.' && *ptr != '/') {
222 ptr--;
223 }
224
225 if (*ptr != '.') {
226 return "text/plain";
227 }
228
229 ext = strdup(ptr + 1); /* skip the . */
230
231 /* the hash table only contains lower-case versions - make sure this
232 * copy is lower case too.
233 */
234 lowerchar = ext;
235 while (*lowerchar) {
236 *lowerchar = ascii_to_lower(*lowerchar);
237 lowerchar++;
238 }
239
240 type = hash_get(mime_hash, ext);
241 free(ext);
242
243 if (type == NULL) {
244 type = "text/plain";
245 }
246
247 return type;
248}
249
250
252{
253 char buf[PATH_MAX];
254 nsurl *url = NULL;
255
256 /* favicon.ico -> favicon.png */
257 if (strcmp(path, "favicon.ico") == 0) {
258 nsurl_create("resource:favicon.png", &url);
259 } else {
261 }
262
263 return url;
264}
265
268
269 .get_resource_url = nsgtk_get_resource_url,
270 .get_resource_data = nsgtk_data_from_resname,
271};
272
Helpers for ASCII string handling.
static char ascii_to_lower(char c)
Convert an upper case character to lower case.
Definition: ascii.h:212
static bool ascii_is_space(char c)
Test whether a character is a whitespace character.
Definition: ascii.h:40
#define PATH_MAX
Definition: gui.h:31
char * filepath_sfind(char **respathv, char *filepath, const char *filename)
Searches an array of resource paths for a file.
Definition: filepath.c:109
Utility routines to obtain paths to file resources.
const char * type
Definition: filetype.cpp:44
static struct gui_fetch_table fetch_table
Definition: fetch.c:266
#define MAX_LINE_LEN
Definition: fetch.c:56
static struct hash_table * mime_hash
Definition: fetch.c:58
void gtk_fetch_filetype_fin(void)
Definition: fetch.c:179
const char * fetch_filetype(const char *unix_path)
filetype – determine the MIME type of a local file
Definition: fetch.c:184
#define HASH_SIZE
Definition: fetch.c:55
static nsurl * nsgtk_get_resource_url(const char *path)
Definition: fetch.c:251
void gtk_fetch_filetype_init(const char *mimefile)
Definition: fetch.c:60
struct gui_fetch_table * nsgtk_fetch_table
Definition: fetch.c:273
char ** respaths
resource search path vector
Definition: findfile.c:28
struct hash_table * hash_create(unsigned int chains)
Create a new hash table.
Definition: hashtable.c:254
bool hash_add(struct hash_table *ht, const char *key, const char *value)
Adds a key/value pair to a hash table.
Definition: hashtable.c:303
void hash_destroy(struct hash_table *ht)
Destroys a hash table.
Definition: hashtable.c:278
const char * hash_get(struct hash_table *ht, const char *key)
Looks up a the value associated with with a key from a specific hash table.
Definition: hashtable.c:339
Interface to Write-Once hash table for string to string mapping.
Interface to platform-specific fetcher operations.
#define NSLOG(catname, level, logmsg, args...)
Definition: log.h:116
NetSurf URL handling (interface).
nserror nsurl_create(const char *const url_s, nsurl **url)
Create a NetSurf URL object from a URL string.
struct nsurl nsurl
NetSurf URL object.
Definition: nsurl.h:31
nserror nsgtk_data_from_resname(const char *resname, const uint8_t **data_out, size_t *data_size_out)
Get direct pointer to resource data.
Definition: resources.c:574
Interface to gtk builtin resource handling.
Interface to utility string handling.
function table for fetcher operations.
Definition: fetch.h:33
const char *(* filetype)(const char *unix_path)
Determine the MIME type of a local file.
Definition: fetch.h:45
nserror netsurf_path_to_nsurl(const char *path, struct nsurl **url)
Create a nsurl from a path.
Definition: file.c:307
Default operations table for files.
static nserror path(const struct redraw_context *ctx, const plot_style_t *pstyle, const float *p, unsigned int n, const float transform[6])
Plots a path.
Definition: plot.c:821
static nserror line(const struct redraw_context *ctx, const plot_style_t *style, const struct rect *line)
Plots a line.
Definition: plot.c:579