/[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 - (hide 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 wakaba 1.1 package Whatpm::CacheManifest;
2     use strict;
3 wakaba 1.3 our $VERSION=do{my @r=(q$Revision: 1.2 $=~/\d+/g);sprintf "%d."."%02d" x $#r,@r};
4 wakaba 1.1 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 wakaba 1.2 ## 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 wakaba 1.1 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 wakaba 1.3 unless (lc $u1->uri_scheme eq lc $m_scheme) { ## TODO: case
48 wakaba 1.1 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 wakaba 1.3 $line =~ s/[\x20\x09]+\z//;
110 wakaba 1.1
111 wakaba 1.3 ## Step 16-17
112     if ($line eq '' or $line =~ /^#/) {
113     next START_OF_LINE;
114     }
115 wakaba 1.1
116     if ($line eq 'CACHE:') {
117 wakaba 1.3 ## Step 18
118 wakaba 1.1 $mode = 'explicit';
119     next START_OF_LINE;
120     } elsif ($line eq 'FALLBACK:') {
121 wakaba 1.3 ## Step 19
122 wakaba 1.1 $mode = 'fallback';
123     next START_OF_LINE;
124     } elsif ($line eq 'NETWORK:') {
125 wakaba 1.3 ## Step 20
126 wakaba 1.1 $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 wakaba 1.3 ## Step 21
144 wakaba 1.1 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 wakaba 1.3 ## Step 22
275 wakaba 1.1 #next START_OF_LINE;
276     } # START_OF_LINE
277    
278 wakaba 1.3 ## Step 23
279     return [$explicit_uris, $fallback_uris, $online_whitelist_uris,
280     $m_uri->uri_reference];
281 wakaba 1.1 } # _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 wakaba 1.3 my $i = 0;
292 wakaba 1.1 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 wakaba 1.3 index => $i,
299 wakaba 1.1 type => 'URI::'.$opt{type}.
300     (defined $opt{position} ? ':'.$opt{position} : ''));
301     });
302 wakaba 1.3
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 wakaba 1.1 }
312    
313 wakaba 1.3 for my $uri1 (sort {$a cmp $b} keys %{$manifest->[1]}) {
314     Whatpm::URIChecker->check_iri_reference ($uri1, sub {
315 wakaba 1.1 my %opt = @_;
316 wakaba 1.3 $onerror->(level => $opt{level}, index => 0, value => $uri1,
317 wakaba 1.1 type => 'URI::'.$opt{type}.
318     (defined $opt{position} ? ':'.$opt{position} : ''));
319     });
320    
321 wakaba 1.3 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 wakaba 1.1 my %opt = @_;
334 wakaba 1.3 $onerror->(level => $opt{level}, index => 1, value => $uri2,
335     index => $i,
336 wakaba 1.1 type => 'URI::'.$opt{type}.
337     (defined $opt{position} ? ':'.$opt{position} : ''));
338     });
339 wakaba 1.3
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 wakaba 1.1 }
348    
349     for my $uri (@{$manifest->[2]}) {
350     if ($listed->{$uri}) {
351     $onerror->(type => 'both in entries and whitelist',
352 wakaba 1.3 index => $i,
353 wakaba 1.1 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 wakaba 1.3 index => $i,
361 wakaba 1.1 type => 'URI::'.$opt{type}.
362     (defined $opt{position} ? ':'.$opt{position} : ''));
363     });
364 wakaba 1.3
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 wakaba 1.1 }
373     } # check_manifest
374    
375    
376     =head1 LICENSE
377    
378 wakaba 1.3 Copyright 2007-2008 Wakaba <w@suika.fam.cx>
379 wakaba 1.1
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 wakaba 1.3 # $Date: 2007/11/23 14:47:49 $

admin@suikawiki.org
ViewVC Help
Powered by ViewVC 1.1.24