/[suikacvs]/markup/html/whatpm/Whatpm/CacheManifest.pm
Suika

Contents of /markup/html/whatpm/Whatpm/CacheManifest.pm

Parent Directory Parent Directory | Revision Log Revision Log


Revision 1.3 - (show annotations) (download)
Sat Feb 16 03:47:33 2008 UTC (16 years, 8 months ago) by wakaba
Branch: MAIN
Changes since 1.2: +63 -24 lines
++ whatpm/Whatpm/ChangeLog	16 Feb 2008 03:47:07 -0000
2008-02-16  Wakaba  <wakaba@suika.fam.cx>

	* CacheManifest.pm: HTML5 revision 1211 implemented.

	* CacheManifest.pod: Updated.

1 package Whatpm::CacheManifest;
2 use strict;
3 our $VERSION=do{my @r=(q$Revision: 1.2 $=~/\d+/g);sprintf "%d."."%02d" x $#r,@r};
4 require Message::URI::URIReference;
5
6 sub parse_byte_string ($$$$$) {
7 require Encode;
8 my $s = Encode::decode ('utf-8', $_[1]);
9 return $_[0]->_parse (\$s, $_[2], $_[3], $_[4] || sub {
10 my %err = @_;
11 warn $err{type}, "\n";
12 });
13 } # parse_byte_string
14
15 sub parse_char_string ($$$$$) {
16 return $_[0]->_parse (\($_[1]), $_[2], $_[3], $_[4] || sub {
17 my %err = @_;
18 warn $err{type}, "\n";
19 });
20 } # parse_char_string
21
22 sub _parse ($$$$$) {
23 #my (undef, $input, $manifest_uri, $base_uri, $onerror) = @_;
24
25 ## NOTE: A manifest MUST be labeled as text/cache-manifest. (This should
26 ## be checked in upper-level).
27 ## NOTE: No "MUST" for being UTF-8.
28 ## NOTE: A |text/cache-manifest| MUST be a cache manifest.
29 ## NOTE: Newlines MUST be CR/CRLF/LF. (We don't and can't check this.)
30
31 ## ISSUE: In RFC 2046: "The specification for any future subtypes of "text" must specify whether or not they will also utilize a "charset" parameter"
32
33 my $m_uri = Message::DOM::DOMImplementation->create_uri_reference ($_[2]);
34 my $m_scheme = $m_uri->uri_scheme;
35
36 my $onerror = $_[4];
37 my $must_level = 'm';
38 my $warn_level = 'w';
39 my $line_number = 1;
40
41 ## Same scheme/host/port
42 my $same_shp = sub {
43 ## TODO: implement this algorithm correctly!
44
45 my $u1 = shift;
46
47 unless (lc $u1->uri_scheme eq lc $m_scheme) { ## TODO: case
48 return 0;
49 }
50
51 return 0 unless defined $u1->uri_authority;
52 return 0 unless defined $m_uri->uri_authority;
53
54 return 0 unless $u1->uri_host eq $m_uri->uri_host;
55 return 0 unless $u1->uri_port eq $m_uri->uri_port;
56
57 return 1;
58 }; # $same_shp
59
60 ## Step 5
61 my $input = $_[1];
62
63 ## Step 1: MUST bytes --UTF-8--> characters.
64 ## NOTE: illegal(s) -> U+FFFD, U+0000 -> U+FFFD
65 $$input =~ tr/\x00/\x{FFFD}/;
66
67 ## Step 2
68 my $explicit_uris = [];
69
70 ## Step 3
71 my $fallback_uris = {};
72
73 ## Step 4
74 my $online_whitelist_uris = [];
75
76 ## Step 6
77 pos ($$input) = 0;
78
79 ## Step 7
80 ## Skip BOM ## NOTE: MAY in syntax.
81
82 ## Step 8-10
83 unless ($$input =~ /^CACHE MANIFEST[\x20\x09]*(?![^\x0D\x0A])/gc) {
84 $onerror->(type => 'not manifest', level => $must_level,
85 line => $line_number, column => 1); ## NOTE: MUST in syntax.
86 return; ## Not a manifest.
87 }
88
89 ## Step 11
90 ## This is a cache manifest.
91
92 ## Step 12
93 my $mode = 'explicit';
94
95 ## NOTE: MUST be (blank line|comment|section head|data for the current
96 ## section)*.
97
98 ## Step 13
99 START_OF_LINE: while (pos $$input < length $$input) {
100 $$input =~ /([\x0A\x0D\x20\x09]+)/gc;
101 my $v = $1;
102 $line_number++ for $v =~ /\x0D\x0A?|\x0D/g;
103
104 ## Step 14
105 $$input =~ /([^\x0A\x0D]*)/gc;
106 my $line = $1;
107
108 ## Step 15
109 $line =~ s/[\x20\x09]+\z//;
110
111 ## Step 16-17
112 if ($line eq '' or $line =~ /^#/) {
113 next START_OF_LINE;
114 }
115
116 if ($line eq 'CACHE:') {
117 ## Step 18
118 $mode = 'explicit';
119 next START_OF_LINE;
120 } elsif ($line eq 'FALLBACK:') {
121 ## Step 19
122 $mode = 'fallback';
123 next START_OF_LINE;
124 } elsif ($line eq 'NETWORK:') {
125 ## Step 20
126 $mode = 'online whitelist';
127 next START_OF_LINE;
128 }
129
130 ## NOTE: "URIs that are to be fallback pages associated with
131 ## opportunistic caching namespaces, and those namespaces themselves,
132 ## MUST be given in fallback sections, with the namespace being the
133 ## first URI of the data line, and the corresponding fallback page
134 ## being the second URI. All the other pages to be cached MUST be
135 ## listed in explicit sections." in writing section can't be tested.
136 ## NOTE: "URIs that the user agent is to put into the online whitelist
137 ## MUST all be specified in online whitelist sections." in writing
138 ## section can't be tested.
139
140 ## NOTE: "Relative URIs MUST be given relative to the manifest's own URI."
141 ## requirement in writing section can't be tested.
142
143 ## Step 21
144 if ($mode eq 'explicit') {
145 my $uri = Message::DOM::DOMImplementation->create_uri_reference ($line);
146
147 unless ($uri->is_iri_reference_3987) {
148 $onerror->(type => 'URI::syntax error:iriref3987',
149 level => $must_level, line => $line_number, column => 1,
150 value => $line);
151 next START_OF_LINE; ## NOTE: MUST in syntax.
152 }
153
154 $uri = $uri->get_absolute_reference ($_[3]);
155
156 if (defined $uri->uri_fragment) {
157 $uri->uri_fragment (undef);
158 $onerror->(type => 'URI fragment not allowed',
159 level => $must_level, line => $line_number, column => 1,
160 value => $line);
161 ## NOTE: MUST in writing section.
162 }
163
164 my $scheme = $uri->uri_scheme;
165 unless (defined $scheme and $scheme eq $m_scheme) {
166 $onerror->(type => 'different scheme from manifest',
167 level => $warn_level, line => $line_number, column => 1,
168 value => $uri->uri_reference);
169 next START_OF_LINE;
170 }
171
172 push @$explicit_uris, $uri->uri_reference;
173 } elsif ($mode eq 'fallback') {
174 my ($p1, $p2) = split /[\x20\x09]+/, $line, 2;
175
176 unless (defined $p2) {
177 $onerror->(type => 'no fallback entry URI',
178 level => $must_level, line => $line_number, column => 1,
179 value => $line);
180 next START_OF_LINE; ## NOTE: MUST in syntax.
181 }
182
183 my $u1 = Message::DOM::DOMImplementation->create_uri_reference ($p1);
184
185 unless ($u1->is_iri_reference_3987) {
186 $onerror->(type => 'URI::syntax error:iriref3987',
187 level => $must_level, line => $line_number, column => 1,
188 index => 0, value => $p1);
189 next START_OF_LINE; ## NOTE: MUST in syntax.
190 }
191
192 my $u2 = Message::DOM::DOMImplementation->create_uri_reference ($p2);
193
194 unless ($u2->is_iri_reference_3987) {
195 $onerror->(type => 'URI::syntax error:iriref3987',
196 level => $must_level, line => $line_number, column => 1,
197 index => 1, value => $p2);
198 next START_OF_LINE; ## NOTE: MUST in syntax.
199 }
200
201 if (defined $u1->uri_fragment) {
202 $onerror->(type => 'URI fragment not allowed',
203 level => $must_level, line => $line_number, column => 1,
204 index => 0, value => $p1);
205 ## NOTE: MUST in writing section.
206 ## ISSUE: Not dropped
207 }
208
209 if (defined $u2->uri_fragment) {
210 $onerror->(type => 'URI fragment not allowed',
211 level => $must_level, line => $line_number, column => 1,
212 index => 1, value => $p2);
213 ## NOTE: MUST in writing section.
214 ## ISSUE: Not dropped
215 }
216
217 $u1 = $u1->get_absolute_reference ($_[3]);
218 $u2 = $u2->get_absolute_reference ($_[3]);
219
220 if (exists $fallback_uris->{$u1->uri_reference}) {
221 $onerror->(type => 'duplicate oc namespace',
222 level => $must_level, line => $line_number, column => 1,
223 index => 0, value => $u1->uri_reference);
224 next START_OF_LINE; ## NOTE: MUST in syntax.
225 }
226
227 unless ($same_shp->($u1)) {
228 $onerror->(type => 'different shp from manifest',
229 level => $must_level, line => $line_number, column => 1,
230 index => 0, value => $u1->uri_reference);
231 next START_OF_LINE; ## NOTE: MUST in syntax.
232 }
233
234 my $u2_scheme = $u2->uri_scheme;
235 unless (defined $u2_scheme and $u2_scheme eq $m_scheme) {
236 $onerror->(type => 'different scheme from manifest',
237 level => $warn_level, line => $line_number, column => 1,
238 index => 1, value => $u2->uri_reference);
239 next START_OF_LINE;
240 }
241
242 $fallback_uris->{$u1->uri_reference} = $u2->uri_reference;
243 } elsif ($mode eq 'online whitelist') {
244 my $uri = Message::DOM::DOMImplementation->create_uri_reference ($line);
245
246 unless ($uri->is_iri_reference_3987) {
247 $onerror->(type => 'URI::syntax error:iriref3987',
248 level => $must_level, line => $line_number, column => 1,
249 value => $line);
250 next START_OF_LINE; ## NOTE: MUST in syntax.
251 }
252
253 $uri = $uri->get_absolute_reference ($_[3]);
254
255 if (defined $uri->uri_fragment) {
256 $uri->uri_fragment (undef);
257 $onerror->(type => 'URI fragment not allowed',
258 level => $must_level, line => $line_number, column => 1,
259 value => $line);
260 ## NOTE: MUST in writing section.
261 }
262
263 my $scheme = $uri->uri_scheme;
264 unless (defined $scheme and $scheme eq $m_scheme) {
265 $onerror->(type => 'different scheme from manifest',
266 level => $warn_level, line => $line_number, column => 1,
267 value => $uri->uri_reference);
268 next START_OF_LINE;
269 }
270
271 push @$online_whitelist_uris, $uri->uri_reference;
272 }
273
274 ## Step 22
275 #next START_OF_LINE;
276 } # START_OF_LINE
277
278 ## Step 23
279 return [$explicit_uris, $fallback_uris, $online_whitelist_uris,
280 $m_uri->uri_reference];
281 } # _parse
282
283 sub check_manifest ($$$) {
284 my (undef, $manifest, $onerror) = @_;
285
286 my $listed = {};
287 my $must_level = 'm';
288
289 require Whatpm::URIChecker;
290
291 my $i = 0;
292 for my $uri (@{$manifest->[0]}) {
293 $listed->{$uri} = 1;
294
295 Whatpm::URIChecker->check_iri_reference ($uri, sub {
296 my %opt = @_;
297 $onerror->(level => $opt{level}, value => $uri,
298 index => $i,
299 type => 'URI::'.$opt{type}.
300 (defined $opt{position} ? ':'.$opt{position} : ''));
301 });
302
303 ## ISSUE: Literal equivalence, right?
304 if ($uri eq $manifest->[3]) {
305 $onerror->(level => $must_level, value => $uri,
306 index => $i,
307 type => 'manifest URI');
308 }
309
310 $i++;
311 }
312
313 for my $uri1 (sort {$a cmp $b} keys %{$manifest->[1]}) {
314 Whatpm::URIChecker->check_iri_reference ($uri1, sub {
315 my %opt = @_;
316 $onerror->(level => $opt{level}, index => 0, value => $uri1,
317 type => 'URI::'.$opt{type}.
318 (defined $opt{position} ? ':'.$opt{position} : ''));
319 });
320
321 if ($uri1 eq $manifest->[3]) {
322 $onerror->(level => $must_level, value => $uri1,
323 index => $i,
324 type => 'manifest URI');
325 }
326
327 $i++;
328
329 my $uri2 = $manifest->[1]->{$uri1};
330 $listed->{$uri2} = 1;
331
332 Whatpm::URIChecker->check_iri_reference ($uri2, sub {
333 my %opt = @_;
334 $onerror->(level => $opt{level}, index => 1, value => $uri2,
335 index => $i,
336 type => 'URI::'.$opt{type}.
337 (defined $opt{position} ? ':'.$opt{position} : ''));
338 });
339
340 if ($uri2 eq $manifest->[3]) {
341 $onerror->(level => $must_level, value => $uri2,
342 index => $i,
343 type => 'manifest URI');
344 }
345
346 $i++;
347 }
348
349 for my $uri (@{$manifest->[2]}) {
350 if ($listed->{$uri}) {
351 $onerror->(type => 'both in entries and whitelist',
352 index => $i,
353 level => $must_level, value => $uri);
354 ## NOTE: MUST in writing section.
355 }
356
357 Whatpm::URIChecker->check_iri_reference ($uri, sub {
358 my %opt = @_;
359 $onerror->(level => $opt{level}, value => $uri,
360 index => $i,
361 type => 'URI::'.$opt{type}.
362 (defined $opt{position} ? ':'.$opt{position} : ''));
363 });
364
365 if ($uri eq $manifest->[3]) {
366 $onerror->(level => $must_level, value => $uri,
367 index => $i,
368 type => 'manifest URI');
369 }
370
371 $i++;
372 }
373 } # check_manifest
374
375
376 =head1 LICENSE
377
378 Copyright 2007-2008 Wakaba <w@suika.fam.cx>
379
380 This library is free software; you can redistribute it
381 and/or modify it under the same terms as Perl itself.
382
383 =cut
384
385 1;
386 # $Date: 2007/11/23 14:47:49 $

admin@suikawiki.org
ViewVC Help
Powered by ViewVC 1.1.24