summaryrefslogtreecommitdiff
path: root/content/content_factory.c
blob: 44fc333c87e177e3dbbddf78a09aeb0cc530a139 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
/*
 * Copyright 2011 John-Mark Bell <jmb@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 factory implementation
 */

#include <assert.h>
#include <stdlib.h>
#include <string.h>

#include "utils/http.h"

#include "content/content.h"
#include "content/content_factory.h"
#include "content/content_protected.h"
#include "content/llcache.h"

/**
 * Entry in list of content handlers
 */
typedef struct content_handler_entry {
	/** Next entry */
	struct content_handler_entry *next;

	/** MIME type handled by handler */
	lwc_string *mime_type;
	/** Content handler object */
	const content_handler *handler;
} content_handler_entry;

static content_handler_entry *content_handlers;

/**
 * Clean up after the content factory
 */
void content_factory_fini(void)
{
	content_handler_entry *victim;

	while (content_handlers != NULL) {
		victim = content_handlers;

		content_handlers = content_handlers->next;

		if (victim->handler->fini != NULL)
			victim->handler->fini();

		lwc_string_unref(victim->mime_type);

		free(victim);
	}
}

/**
 * Register a handler with the content factory
 *
 * \param mime_type  MIME type to handle
 * \param handler    Content handler for MIME type
 * \return NSERROR_OK on success, appropriate error otherwise
 *
 * \note Latest registration for a MIME type wins
 */
nserror content_factory_register_handler(const char *mime_type,
		const content_handler *handler)
{
	lwc_string *imime_type;
	lwc_error lerror;
	content_handler_entry *entry;
	bool match;

	lerror = lwc_intern_string(mime_type, strlen(mime_type), &imime_type);
	if (lerror != lwc_error_ok)
		return NSERROR_NOMEM;

	for (entry = content_handlers; entry != NULL; entry = entry->next) {
		if (lwc_string_caseless_isequal(imime_type, entry->mime_type,
				&match) == lwc_error_ok && match)
			break;
	}

	if (entry == NULL) {
		entry = malloc(sizeof(content_handler_entry));
		if (entry == NULL)
			return NSERROR_NOMEM;

		entry->next = content_handlers;
		content_handlers = entry;

		entry->mime_type = imime_type;
	} else {
		lwc_string_unref(imime_type);
	}

	entry->handler = handler;

	return NSERROR_OK;
}

/**
 * Find a handler for a MIME type.
 *
 * \param mime_type  MIME type to search for
 * \return Associated handler, or NULL if none
 */
static const content_handler *content_lookup(lwc_string *mime_type)
{
	content_handler_entry *entry;
	bool match;

	for (entry = content_handlers; entry != NULL; entry = entry->next) {
		if (lwc_string_caseless_isequal(mime_type, entry->mime_type,
					&match) == lwc_error_ok && match) {
			break;
		}
	}

	if (entry != NULL) {
		return entry->handler;
	}

	return NULL;
}

/**
 * Compute the generic content type for a MIME type
 *
 * \param mime_type  MIME type to consider
 * \return Generic content type
 */
content_type content_factory_type_from_mime_type(lwc_string *mime_type)
{
	const content_handler *handler;
	content_type type = CONTENT_NONE;

	handler = content_lookup(mime_type);
	if (handler != NULL) {
		type = handler->type();
	}

	return type;
}

/**
 * Create a content object
 *
 * \param llcache           Underlying source data handle
 * \param fallback_charset  Character set to fall back to if none specified
 * \param quirks            Quirkiness of containing document
 * \param effective_type    Effective MIME type of content
 * \return Pointer to content object, or NULL on failure
 */
struct content *content_factory_create_content(llcache_handle *llcache,
		const char *fallback_charset, bool quirks,
		lwc_string *effective_type)
{
	struct content *c;
	const char *content_type_header;
	const content_handler *handler;
	http_content_type *ct = NULL;
	nserror error;

	handler = content_lookup(effective_type);
	if (handler == NULL)
		return NULL;

	assert(handler->create != NULL);

	/* Use the parameters from the declared Content-Type header */
	content_type_header = 
			llcache_handle_get_header(llcache, "Content-Type");
	if (content_type_header != NULL) {
		/* We don't care if this fails */
		http_parse_content_type(content_type_header, &ct);
	}

	error = handler->create(handler, effective_type, 
			ct != NULL ? ct->parameters : NULL, 
			llcache, fallback_charset, quirks, 
			&c);

	if (ct != NULL)
		http_content_type_destroy(ct);

	if (error != NSERROR_OK)
		return NULL;

	return c;
}