Bug 22803 - Make header conform to implementation
[swfdec.git] / swfdec / swfdec_policy_file.c
blob32f74d033747c5437abeb31d1e55cded5cff409b
1 /* Swfdec
2 * Copyright (C) 2007-2008 Benjamin Otte <otte@gnome.org>
3 * 2007 Pekka Lampila <pekka.lampila@iki.fi>
5 * This library is free software; you can redistribute it and/or
6 * modify it under the terms of the GNU Lesser General Public
7 * License as published by the Free Software Foundation; either
8 * version 2.1 of the License, or (at your option) any later version.
9 *
10 * This library is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 * Lesser General Public License for more details.
15 * You should have received a copy of the GNU Lesser General Public
16 * License along with this library; if not, write to the Free Software
17 * Foundation, Inc., 51 Franklin Street, Fifth Floor,
18 * Boston, MA 02110-1301 USA
21 #ifdef HAVE_CONFIG_H
22 #include "config.h"
23 #endif
25 #include <string.h>
27 #include "swfdec_policy_file.h"
28 #include "swfdec_resource.h"
29 #include "swfdec_as_strings.h"
30 #include "swfdec_debug.h"
31 #include "swfdec_internal.h"
32 #include "swfdec_loader_internal.h"
33 #include "swfdec_player_internal.h"
34 #include "swfdec_sandbox.h"
35 #include "swfdec_xml.h"
36 #include "swfdec_xml_node.h"
38 typedef struct _SwfdecPolicyFileRequest SwfdecPolicyFileRequest;
39 struct _SwfdecPolicyFileRequest {
40 SwfdecURL * from; /* URL we are supposed to check */
41 SwfdecURL * url; /* URL we are supposed to check */
42 SwfdecPolicyFunc func; /* function to call when we know if access is (not) allowed */
43 gpointer data; /* data to pass to func */
46 static void
47 swfdec_policy_file_request_free (SwfdecPolicyFileRequest *request)
49 swfdec_url_free (request->from);
50 swfdec_url_free (request->url);
51 g_slice_free (SwfdecPolicyFileRequest, request);
54 /*** PARSING THE FILE ***/
56 static void
57 swfdec_policy_file_parse (SwfdecPolicyFile *file, const char *text)
59 SwfdecXml *xml;
60 gint32 i, j;
62 g_return_if_fail (SWFDEC_IS_POLICY_FILE (file));
63 g_return_if_fail (text != NULL);
65 /* FIXME: the sandboxes are a HACK */
66 swfdec_sandbox_use (SWFDEC_MOVIE (file->player->priv->roots->data)->resource->sandbox);
67 xml = swfdec_xml_new_no_properties (SWFDEC_AS_CONTEXT (file->player), text, TRUE);
68 swfdec_sandbox_unuse (SWFDEC_MOVIE (file->player->priv->roots->data)->resource->sandbox);
70 if (xml == NULL) {
71 SWFDEC_ERROR ("failed to create an XML object for crossdomain policy");
72 return;
75 if (SWFDEC_XML_NODE (xml)->type != SWFDEC_XML_NODE_ELEMENT) {
76 SWFDEC_LOG ("empty crossdomain policy file");
77 return;
80 for (i = 0; i < swfdec_xml_node_num_children (SWFDEC_XML_NODE (xml)); i++) {
81 SwfdecXmlNode *node_cdp =
82 swfdec_xml_node_get_child (SWFDEC_XML_NODE (xml), i);
84 if (node_cdp->type != SWFDEC_XML_NODE_ELEMENT)
85 continue;
87 if (g_ascii_strcasecmp (node_cdp->name, "cross-domain-policy") != 0)
88 continue;
90 for (j = 0; j < swfdec_xml_node_num_children (node_cdp); j++) {
91 SwfdecXmlNode *node_aaf = swfdec_xml_node_get_child (node_cdp, j);
92 const char *value;
93 GPatternSpec *pattern;
94 char *value_lower;
96 if (node_aaf->type != SWFDEC_XML_NODE_ELEMENT)
97 continue;
99 if (g_ascii_strcasecmp (node_aaf->name, "allow-access-from") != 0)
100 continue;
102 // FIXME: secure attribute?
104 value = swfdec_xml_node_get_attribute (node_aaf, SWFDEC_AS_STR_domain);
105 if (value == NULL)
106 continue;
108 if (strchr (value, '?') != NULL) {
109 SWFDEC_WARNING ("'?' in allowed domain attribute for %s", value);
110 continue;
113 value_lower = g_ascii_strdown (value, -1);
114 pattern = g_pattern_spec_new (value_lower);
115 g_free (value_lower);
117 file->allowed_hosts = g_slist_prepend (file->allowed_hosts, pattern);
122 /*** SWFDEC_STREAM_TARGET ***/
124 static SwfdecPlayer *
125 swfdec_policy_file_target_get_player (SwfdecStreamTarget *target)
127 return SWFDEC_POLICY_FILE (target)->player;
130 static void
131 swfdec_policy_file_finished_loading (SwfdecPolicyFile *file, const char *text)
133 SwfdecPlayerPrivate *priv;
134 SwfdecPolicyFile *next;
135 GList *link;
137 swfdec_stream_set_target (file->stream, NULL);
138 file->stream = NULL;
140 if (text)
141 swfdec_policy_file_parse (file, text);
143 priv = file->player->priv;
144 link = g_list_find (priv->loading_policy_files, file);
145 next = link->next ? link->next->data : NULL;
146 priv->loading_policy_files = g_list_delete_link (priv->loading_policy_files, link);
147 priv->policy_files = g_slist_prepend (priv->policy_files, file);
148 if (next) {
149 next->requests = g_slist_concat (next->requests, file->requests);
150 } else {
151 GSList *walk;
153 for (walk = file->requests; walk; walk = walk->next) {
154 SwfdecPolicyFileRequest *request = walk->data;
155 gboolean allow = swfdec_player_allow_now (file->player, request->from, request->url);
156 request->func (file->player, allow, request->data);
157 swfdec_policy_file_request_free (request);
159 g_slist_free (file->requests);
161 file->requests = NULL;
164 static void
165 swfdec_policy_file_target_open (SwfdecStreamTarget *target,
166 SwfdecStream *stream)
168 if (SWFDEC_IS_SOCKET (stream)) {
169 SwfdecBuffer *buffer = swfdec_buffer_new_static (
170 "<policy-file-request/>", 23);
171 swfdec_socket_send (SWFDEC_SOCKET (stream), buffer);
175 static void
176 swfdec_policy_file_target_error (SwfdecStreamTarget *target,
177 SwfdecStream *stream)
179 SwfdecPolicyFile *file = SWFDEC_POLICY_FILE (target);
181 swfdec_policy_file_finished_loading (file, NULL);
184 static void
185 swfdec_policy_file_target_close (SwfdecStreamTarget *target,
186 SwfdecStream *stream)
188 SwfdecPolicyFile *file = SWFDEC_POLICY_FILE (target);
189 char *text;
191 text = swfdec_buffer_queue_pull_text (swfdec_stream_get_queue (stream), 8);
193 if (text == NULL) {
194 SWFDEC_ERROR ("couldn't get text from crossdomain policy file %s",
195 swfdec_url_get_url (file->load_url));
197 swfdec_policy_file_finished_loading (file, text);
198 g_free (text);
201 static void
202 swfdec_policy_file_stream_target_init (SwfdecStreamTargetInterface *iface)
204 iface->get_player = swfdec_policy_file_target_get_player;
205 iface->open = swfdec_policy_file_target_open;
206 iface->close = swfdec_policy_file_target_close;
207 iface->error = swfdec_policy_file_target_error;
210 /*** SWFDEC_POLICY_FILE ***/
212 G_DEFINE_TYPE_WITH_CODE (SwfdecPolicyFile, swfdec_policy_file, G_TYPE_OBJECT,
213 G_IMPLEMENT_INTERFACE (SWFDEC_TYPE_STREAM_TARGET, swfdec_policy_file_stream_target_init))
215 static void
216 swfdec_policy_file_dispose (GObject *object)
218 SwfdecPolicyFile *file = SWFDEC_POLICY_FILE (object);
220 if (file->stream) {
221 swfdec_stream_set_target (file->stream, NULL);
222 g_object_unref (file->stream);
223 file->stream = NULL;
224 g_slist_foreach (file->requests, (GFunc) swfdec_policy_file_request_free, NULL);
225 g_slist_free (file->requests);
226 file->requests = NULL;
227 } else {
228 g_assert (file->requests == NULL);
230 swfdec_url_free (file->load_url);
231 swfdec_url_free (file->url);
233 G_OBJECT_CLASS (swfdec_policy_file_parent_class)->dispose (object);
236 static void
237 swfdec_policy_file_class_init (SwfdecPolicyFileClass *klass)
239 GObjectClass *object_class = G_OBJECT_CLASS (klass);
241 object_class->dispose = swfdec_policy_file_dispose;
244 static void
245 swfdec_policy_file_init (SwfdecPolicyFile *policy_file)
249 SwfdecPolicyFile *
250 swfdec_policy_file_new (SwfdecPlayer *player, const SwfdecURL *url)
252 SwfdecPolicyFile *file;
254 g_return_val_if_fail (SWFDEC_IS_PLAYER (player), NULL);
255 g_return_val_if_fail (url != NULL, NULL);
257 file = g_object_new (SWFDEC_TYPE_POLICY_FILE, NULL);
258 file->player = player;
259 file->load_url = swfdec_url_copy (url);
260 file->url = swfdec_url_new_parent (url);
261 if (swfdec_url_has_protocol (url, "xmlsocket")) {
262 file->stream = SWFDEC_STREAM (swfdec_player_create_socket (player,
263 swfdec_url_get_host (url), swfdec_url_get_port (url)));
264 } else {
265 file->stream = SWFDEC_STREAM (swfdec_player_load (player,
266 swfdec_url_get_url (url), NULL));
268 swfdec_stream_set_target (file->stream, SWFDEC_STREAM_TARGET (file));
269 player->priv->loading_policy_files =
270 g_list_prepend (player->priv->loading_policy_files, file);
272 return file;
275 gboolean
276 swfdec_policy_file_is_loading (SwfdecPolicyFile *file)
278 g_return_val_if_fail (SWFDEC_IS_POLICY_FILE (file), FALSE);
280 return file->stream != NULL;
283 gboolean
284 swfdec_policy_file_allow (SwfdecPolicyFile *file, const SwfdecURL *from, const SwfdecURL *url)
286 GSList *walk;
287 gsize len;
288 char *emantsoh;
289 const char *hostname;
291 g_return_val_if_fail (SWFDEC_IS_POLICY_FILE (file), FALSE);
292 g_return_val_if_fail (from != NULL, FALSE);
293 g_return_val_if_fail (url != NULL, FALSE);
295 /* first check if the policy file is allowing the following url */
296 if (!swfdec_url_is_parent (file->url, url))
297 return FALSE;
299 /* then try to find the from url in the allowed hosts */
300 hostname = swfdec_url_get_host (from);
301 /* This is a hack that simplifies the following code. As the pattern can not
302 * contain any ?, the only pattern that matches the string "?" is the pattern
303 * "*"
305 if (hostname == NULL)
306 hostname = "?";
307 len = strlen (hostname);
308 emantsoh = g_utf8_strreverse (hostname, len);
309 for (walk = file->allowed_hosts; walk; walk = walk->next) {
310 GPatternSpec *pattern = walk->data;
311 if (g_pattern_match (pattern, len, hostname, emantsoh)) {
312 g_free (emantsoh);
313 return TRUE;
316 g_free (emantsoh);
317 return FALSE;
320 /*** PLAYER API ***/
322 gboolean
323 swfdec_player_allow_now (SwfdecPlayer *player, const SwfdecURL *from, const SwfdecURL *url)
325 GSList *walk;
327 g_return_val_if_fail (SWFDEC_IS_PLAYER (player), FALSE);
328 g_return_val_if_fail (url != NULL, FALSE);
330 for (walk = player->priv->policy_files; walk; walk = walk->next) {
331 if (swfdec_policy_file_allow (walk->data, from, url))
332 return TRUE;
334 return FALSE;
337 void
338 swfdec_player_allow_or_load (SwfdecPlayer *player, const SwfdecURL *from,
339 const SwfdecURL *url, const SwfdecURL *crossdomain, SwfdecPolicyFunc func, gpointer data)
341 SwfdecPlayerPrivate *priv;
342 SwfdecPolicyFileRequest *request;
343 SwfdecPolicyFile *file;
345 g_return_if_fail (SWFDEC_IS_PLAYER (player));
346 g_return_if_fail (url != NULL);
347 g_return_if_fail (func);
349 if (swfdec_player_allow_now (player, from, url)) {
350 func (player, TRUE, data);
351 return;
353 if (crossdomain)
354 swfdec_policy_file_new (player, crossdomain);
356 priv = player->priv;
357 if (priv->loading_policy_files == NULL) {
358 func (player, FALSE, data);
359 return;
361 request = g_slice_new (SwfdecPolicyFileRequest);
362 request->from = swfdec_url_copy (from);
363 request->url = swfdec_url_copy (url);
364 request->func = func;
365 request->data = data;
367 file = priv->loading_policy_files->data;
368 file->requests = g_slist_append (file->requests, request);