1 /** The document base functionality
13 #include <sys/types.h>
14 #ifdef HAVE_NETINET_IN_H
15 #include <netinet/in.h> /* OS/2 needs this after sys/types.h */
17 #ifdef HAVE_SYS_SOCKET_H
18 #include <sys/socket.h> /* OS/2 needs this after sys/types.h */
21 #include <fcntl.h> /* OS/2 needs this after sys/types.h */
26 #ifdef HAVE_WS2TCPIP_H
27 #include <ws2tcpip.h> /* socklen_t for MinGW */
30 #ifdef HAVE_GETIFADDRS
38 #include <ifaddrs.h> /* getifaddrs() */
40 #endif /* HAVE_GETIFADDRS */
42 #ifdef HAVE_ARPA_INET_H
43 #include <arpa/inet.h>
48 #include "cache/cache.h"
49 #include "config/options.h"
50 #include "document/document.h"
51 #include "document/forms.h"
52 #include "document/html/frames.h"
53 #include "document/html/parser.h"
54 #include "document/html/parser/parse.h"
55 #include "document/html/renderer.h"
56 #include "document/options.h"
57 #include "document/refresh.h"
58 #include "main/module.h"
59 #include "main/object.h"
60 #include "network/dns.h"
61 #include "protocol/uri.h"
62 #include "terminal/draw.h"
63 #include "util/color.h"
64 #include "util/error.h"
65 #include "util/lists.h"
66 #include "util/memory.h"
67 #include "util/string.h"
68 #include "viewer/text/link.h"
70 static INIT_LIST_OF(struct document
, format_cache
);
75 found_dns(void *data
, struct sockaddr_storage
*addr
, int addrlen
)
77 unsigned char buf
[64];
78 const unsigned char *res
;
80 unsigned char **ip
= (unsigned char **)data
;
83 if (!ip
|| !addr
) return;
84 s
= (struct sockaddr
*)addr
;
85 if (s
->sa_family
== AF_INET6
) {
86 src
= &(((struct sockaddr_in6
*)s
)->sin6_addr
.s6_addr
);
88 src
= &(((struct sockaddr_in
*)s
)->sin_addr
.s_addr
);
90 res
= inet_ntop(s
->sa_family
, src
, buf
, 64);
98 get_ip(struct document
*document
)
100 #ifdef HAVE_INET_NTOP
101 struct uri
*uri
= document
->uri
;
104 if (!uri
|| !uri
->host
|| !uri
->hostlen
) return;
105 tmp
= uri
->host
[uri
->hostlen
];
106 uri
->host
[uri
->hostlen
] = 0;
107 find_host(uri
->host
, &document
->querydns
, found_dns
, &document
->ip
, 0);
108 uri
->host
[uri
->hostlen
] = tmp
;
113 init_document(struct cache_entry
*cached
, struct document_options
*options
)
115 struct document
*document
= mem_calloc(1, sizeof(*document
));
117 if (!document
) return NULL
;
119 document
->uri
= get_uri_reference(cached
->uri
);
124 document
->cache_id
= cached
->cache_id
;
125 document
->cached
= cached
;
127 init_list(document
->forms
);
128 init_list(document
->tags
);
129 init_list(document
->nodes
);
131 #ifdef CONFIG_ECMASCRIPT
132 init_list(document
->onload_snippets
);
135 #ifdef CONFIG_COMBINE
136 document
->comb_x
= -1;
137 document
->comb_y
= -1;
139 object_nolock(document
, "document");
140 object_lock(document
);
142 copy_opt(&document
->options
, options
);
144 add_to_list(format_cache
, document
);
150 free_frameset_desc(struct frameset_desc
*frameset_desc
)
154 for (i
= 0; i
< frameset_desc
->n
; i
++) {
155 struct frame_desc
*frame_desc
= &frameset_desc
->frame_desc
[i
];
157 if (frame_desc
->subframe
)
158 free_frameset_desc(frame_desc
->subframe
);
159 mem_free_if(frame_desc
->name
);
161 done_uri(frame_desc
->uri
);
164 mem_free(frameset_desc
);
168 done_link_members(struct link
*link
)
170 if (link
->event_hooks
) {
171 struct script_event_hook
*evhook
, *safety
;
173 foreachsafe (evhook
, safety
, *link
->event_hooks
) {
174 mem_free_if(evhook
->src
);
177 mem_free(link
->event_hooks
);
179 mem_free_if(get_link_name(link
));
180 mem_free_if(link
->where
);
181 mem_free_if(link
->target
);
182 mem_free_if(link
->title
);
183 mem_free_if(link
->where_img
);
184 mem_free_if(link
->points
);
188 done_document(struct document
*document
)
191 if_assert_failed
return;
193 assertm(!is_object_used(document
), "Attempt to free locked formatted data.");
194 if_assert_failed
return;
196 assert(document
->cached
);
197 object_unlock(document
->cached
);
199 if (document
->uri
) done_uri(document
->uri
);
200 if (document
->querydns
) kill_dns_request(&document
->querydns
);
201 mem_free_if(document
->ip
);
202 mem_free_if(document
->title
);
203 if (document
->frame_desc
) free_frameset_desc(document
->frame_desc
);
204 if (document
->refresh
) done_document_refresh(document
->refresh
);
206 if (document
->links
) {
209 for (pos
= 0; pos
< document
->nlinks
; pos
++)
210 done_link_members(&document
->links
[pos
]);
212 mem_free(document
->links
);
215 if (document
->data
) {
218 for (pos
= 0; pos
< document
->height
; pos
++)
219 mem_free_if(document
->data
[pos
].chars
);
221 mem_free(document
->data
);
224 mem_free_if(document
->lines1
);
225 mem_free_if(document
->lines2
);
226 done_document_options(&document
->options
);
228 while (!list_empty(document
->forms
)) {
229 done_form(document
->forms
.next
);
233 free_uri_list(&document
->css_imports
);
235 #ifdef CONFIG_ECMASCRIPT
236 free_string_list(&document
->onload_snippets
);
237 free_uri_list(&document
->ecmascript_imports
);
238 kill_timer(&document
->timeout
);
241 free_list(document
->tags
);
242 free_list(document
->nodes
);
244 mem_free_if(document
->search
);
245 mem_free_if(document
->slines1
);
246 mem_free_if(document
->slines2
);
248 del_from_list(document
);
253 release_document(struct document
*document
)
256 if_assert_failed
return;
258 if (document
->refresh
) kill_document_refresh(document
->refresh
);
259 #ifdef CONFIG_ECMASCRIPT
260 kill_timer(&document
->timeout
);
262 object_unlock(document
);
263 move_to_top_of_list(format_cache
, document
);
267 find_tag(struct document
*document
, unsigned char *name
, int namelen
)
271 foreach (tag
, document
->tags
)
272 if (!c_strlcasecmp(tag
->name
, -1, name
, namelen
))
278 /* Formatted document cache management */
280 /* ECMAScript doesn't like anything like CSS since it doesn't modify the
281 * formatted document (yet). */
285 get_document_css_magic(struct document
*document
)
287 unsigned long css_magic
= 0;
291 foreach_uri (uri
, index
, &document
->css_imports
) {
292 struct cache_entry
*cached
= find_in_cache(uri
);
294 if (cached
) css_magic
+= cached
->cache_id
+ cached
->data_size
;
300 #define check_document_css_magic(document) \
301 ((document)->css_magic == get_document_css_magic(document))
303 #define check_document_css_magic(document) 1
307 update_cached_document_options(struct session
*ses
)
309 struct document
*document
;
310 struct active_link_options active_link
;
312 memset(&active_link
, 0, sizeof(active_link
)); /* Safer. */
313 active_link
.color
.foreground
= get_opt_color("document.browse.links.active_link.colors.text", ses
);
314 active_link
.color
.background
= get_opt_color("document.browse.links.active_link.colors.background", ses
);
315 active_link
.enable_color
= get_opt_bool("document.browse.links.active_link.enable_color", ses
);
316 active_link
.invert
= get_opt_bool("document.browse.links.active_link.invert", ses
);
317 active_link
.underline
= get_opt_bool("document.browse.links.active_link.underline", ses
);
318 active_link
.bold
= get_opt_bool("document.browse.links.active_link.bold", ses
);
320 foreach (document
, format_cache
) {
321 copy_struct(&document
->options
.active_link
, &active_link
);
326 get_cached_document(struct cache_entry
*cached
, struct document_options
*options
)
328 struct document
*document
, *next
;
330 foreachsafe (document
, next
, format_cache
) {
331 if (!compare_uri(document
->uri
, cached
->uri
, 0)
332 || compare_opt(&document
->options
, options
))
335 if (options
->no_cache
336 || cached
->cache_id
!= document
->cache_id
337 || !check_document_css_magic(document
)) {
338 if (!is_object_used(document
)) {
339 done_document(document
);
345 move_to_top_of_list(format_cache
, document
);
347 object_lock(document
);
356 shrink_format_cache(int whole
)
358 struct document
*document
, *next
;
359 int format_cache_size
= get_opt_int("document.cache.format.size", NULL
);
360 int format_cache_entries
= 0;
362 foreachsafe (document
, next
, format_cache
) {
363 if (is_object_used(document
)) continue;
365 format_cache_entries
++;
367 /* Destroy obsolete renderer documents which are already
369 if (document
->cached
->cache_id
== document
->cache_id
)
372 done_document(document
);
373 format_cache_entries
--;
376 assertm(format_cache_entries
>= 0, "format_cache_entries underflow on entry");
377 if_assert_failed format_cache_entries
= 0;
379 foreachbacksafe (document
, next
, format_cache
) {
380 if (is_object_used(document
)) continue;
382 /* If we are not purging the whole format cache, stop
383 * once we are below the maximum number of entries. */
384 if (!whole
&& format_cache_entries
<= format_cache_size
)
387 done_document(document
);
388 format_cache_entries
--;
391 assertm(format_cache_entries
>= 0, "format_cache_entries underflow");
392 if_assert_failed format_cache_entries
= 0;
396 get_format_cache_size(void)
398 return list_size(&format_cache
);
402 get_format_cache_used_count(void)
404 struct document
*document
;
407 foreach (document
, format_cache
)
408 i
+= is_object_used(document
);
413 get_format_cache_refresh_count(void)
415 struct document
*document
;
418 foreach (document
, format_cache
)
419 if (document
->refresh
420 && document
->refresh
->timer
!= TIMER_ID_UNDEF
)
426 init_documents(struct module
*module
)
432 done_documents(struct module
*module
)
438 struct module document_module
= struct_module(
439 /* Because this module is listed in main_modules rather than
440 * in builtin_modules, its name does not appear in the user
441 * interface and so need not be translatable. */
442 /* name: */ "Document",
445 /* submodules: */ NULL
,
447 /* init: */ init_documents
,
448 /* done: */ done_documents