Bug 951: Lock the cache entry while the hook runs.
[elinks.git] / src / scripting / smjs / load_uri.c
blobf9c7e09fcdd644311fd4700f95c5c77e51edc361
1 /* ECMAScript browser scripting module */
3 #ifdef HAVE_CONFIG_H
4 #include "config.h"
5 #endif
7 #include "elinks.h"
9 #include "ecmascript/spidermonkey/util.h"
10 #include "network/connection.h"
11 #include "protocol/uri.h"
12 #include "scripting/smjs/core.h"
13 #include "scripting/smjs/cache_object.h"
14 #include "scripting/smjs/elinks_object.h"
15 #include "session/download.h"
18 struct smjs_load_uri_hop {
19 struct session *ses;
20 JSFunction *callback;
23 static void
24 smjs_loading_callback(struct download *download, void *data)
26 struct session *saved_smjs_ses = smjs_ses;
27 struct smjs_load_uri_hop *hop = data;
28 jsval args[1], rval;
29 JSObject *cache_entry_object;
31 if (is_in_progress_state(download->state)) return;
33 if (!download->cached) goto end;
35 /* download->cached->object.refcount is typically 0 here
36 * because no struct document uses the cache entry. Because
37 * the connection is no longer using the cache entry either,
38 * it can be garbage collected. Don't let that happen while
39 * the script is using it. */
40 object_lock(download->cached);
42 assert(hop->callback);
44 smjs_ses = hop->ses;
46 cache_entry_object = smjs_get_cache_entry_object(download->cached);
47 if (!cache_entry_object) goto end;
49 args[0] = OBJECT_TO_JSVAL(cache_entry_object);
51 JS_CallFunction(smjs_ctx, NULL, hop->callback, 1, args, &rval);
53 end:
54 if (download->cached)
55 object_unlock(download->cached);
56 mem_free(download->data);
57 mem_free(download);
59 smjs_ses = saved_smjs_ses;
62 static JSBool
63 smjs_load_uri(JSContext *ctx, JSObject *obj, uintN argc, jsval *argv,
64 jsval *rval)
66 struct smjs_load_uri_hop *hop;
67 struct download *download;
68 JSString *jsstr;
69 unsigned char *uri_string;
70 struct uri *uri;
72 if (argc < 2) return JS_FALSE;
74 jsstr = JS_ValueToString(smjs_ctx, argv[0]);
75 uri_string = JS_GetStringBytes(jsstr);
77 uri = get_uri(uri_string, 0);
78 if (!uri) return JS_FALSE;
80 download = mem_alloc(sizeof(*download));
81 if (!download) {
82 done_uri(uri);
83 return JS_FALSE;
86 hop = mem_alloc(sizeof(*hop));
87 if (!hop) {
88 done_uri(uri);
89 mem_free(download);
90 return JS_FALSE;
93 hop->callback = JS_ValueToFunction(smjs_ctx, argv[1]);
94 hop->ses = smjs_ses;
96 download->data = hop;
97 download->callback = (download_callback_T *) smjs_loading_callback;
99 load_uri(uri, NULL, download, PRI_MAIN, CACHE_MODE_NORMAL, -1);
101 done_uri(uri);
103 return JS_TRUE;
106 void
107 smjs_init_load_uri_interface(void)
109 if (!smjs_ctx || !smjs_elinks_object)
110 return;
112 JS_DefineFunction(smjs_ctx, smjs_elinks_object, "load_uri",
113 &smjs_load_uri, 2, 0);