1 /*
2 * Copyright (C) 2008 Apple Inc. All Rights Reserved.
3 *
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions
6 * are met:
7 * 1. Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer.
9 * 2. Redistributions in binary form must reproduce the above copyright
10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution.
12 *
13 * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
14 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
15 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
16 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR
17 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
18 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
19 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
20 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
21 * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
22 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
23 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
24 */
25
26 #include "config.h"
27 #include "ManifestParser.h"
28
29 #if ENABLE(OFFLINE_WEB_APPLICATIONS)
30
31 #include "CharacterNames.h"
32 #include "KURL.h"
33 #include "TextResourceDecoder.h"
34
35 using namespace std;
36
37 namespace WebCore {
38
39 enum Mode { Explicit, Fallback, OnlineWhitelist, Unknown };
40
parseManifest(const KURL & manifestURL,const char * data,int length,Manifest & manifest)41 bool parseManifest(const KURL& manifestURL, const char* data, int length, Manifest& manifest)
42 {
43 ASSERT(manifest.explicitURLs.isEmpty());
44 ASSERT(manifest.onlineWhitelistedURLs.isEmpty());
45 ASSERT(manifest.fallbackURLs.isEmpty());
46
47 Mode mode = Explicit;
48
49 RefPtr<TextResourceDecoder> decoder = TextResourceDecoder::create("text/cache-manifest", "UTF-8");
50 String s = decoder->decode(data, length);
51 s += decoder->flush();
52
53 // Look for the magic signature: "^\xFEFF?CACHE MANIFEST[ \t]?" (the BOM is removed by TextResourceDecoder).
54 // Example: "CACHE MANIFEST #comment" is a valid signature.
55 // Example: "CACHE MANIFEST;V2" is not.
56 if (!s.startsWith("CACHE MANIFEST"))
57 return false;
58
59 const UChar* end = s.characters() + s.length();
60 const UChar* p = s.characters() + 14; // "CACHE MANIFEST" is 14 characters.
61
62 if (p < end && *p != ' ' && *p != '\t' && *p != '\n' && *p != '\r')
63 return false;
64
65 // Skip to the end of the line.
66 while (p < end && *p != '\r' && *p != '\n')
67 p++;
68
69 while (1) {
70 // Skip whitespace
71 while (p < end && (*p == '\n' || *p == '\r' || *p == ' ' || *p == '\t'))
72 p++;
73
74 if (p == end)
75 break;
76
77 const UChar* lineStart = p;
78
79 // Find the end of the line
80 while (p < end && *p != '\r' && *p != '\n')
81 p++;
82
83 // Check if we have a comment
84 if (*lineStart == '#')
85 continue;
86
87 // Get rid of trailing whitespace
88 const UChar* tmp = p - 1;
89 while (tmp > lineStart && (*tmp == ' ' || *tmp == '\t'))
90 tmp--;
91
92 String line(lineStart, tmp - lineStart + 1);
93
94 if (line == "CACHE:")
95 mode = Explicit;
96 else if (line == "FALLBACK:")
97 mode = Fallback;
98 else if (line == "NETWORK:")
99 mode = OnlineWhitelist;
100 else if (line.endsWith(":"))
101 mode = Unknown;
102 else if (mode == Unknown)
103 continue;
104 else if (mode == Explicit || mode == OnlineWhitelist) {
105 const UChar* p = line.characters();
106 const UChar* lineEnd = p + line.length();
107
108 // Look for whitespace separating the URL from subsequent ignored tokens.
109 while (p < lineEnd && *p != '\t' && *p != ' ')
110 p++;
111
112 KURL url(manifestURL, String(line.characters(), p - line.characters()));
113
114 if (!url.isValid())
115 continue;
116
117 if (url.hasFragmentIdentifier())
118 url.removeFragmentIdentifier();
119
120 if (!equalIgnoringCase(url.protocol(), manifestURL.protocol()))
121 continue;
122
123 if (mode == Explicit)
124 manifest.explicitURLs.add(url.string());
125 else
126 manifest.onlineWhitelistedURLs.append(url);
127
128 } else if (mode == Fallback) {
129 const UChar* p = line.characters();
130 const UChar* lineEnd = p + line.length();
131
132 // Look for whitespace separating the two URLs
133 while (p < lineEnd && *p != '\t' && *p != ' ')
134 p++;
135
136 if (p == lineEnd) {
137 // There was no whitespace separating the URLs.
138 continue;
139 }
140
141 KURL namespaceURL(manifestURL, String(line.characters(), p - line.characters()));
142 if (!namespaceURL.isValid())
143 continue;
144 if (namespaceURL.hasFragmentIdentifier())
145 namespaceURL.removeFragmentIdentifier();
146
147 if (!protocolHostAndPortAreEqual(manifestURL, namespaceURL))
148 continue;
149
150 // Skip whitespace separating fallback namespace from URL.
151 while (p < lineEnd && (*p == '\t' || *p == ' '))
152 p++;
153
154 // Look for whitespace separating the URL from subsequent ignored tokens.
155 const UChar* fallbackStart = p;
156 while (p < lineEnd && *p != '\t' && *p != ' ')
157 p++;
158
159 KURL fallbackURL(manifestURL, String(fallbackStart, p - fallbackStart));
160 if (!fallbackURL.isValid())
161 continue;
162 if (fallbackURL.hasFragmentIdentifier())
163 fallbackURL.removeFragmentIdentifier();
164
165 if (!protocolHostAndPortAreEqual(manifestURL, fallbackURL))
166 continue;
167
168 manifest.fallbackURLs.append(make_pair(namespaceURL, fallbackURL));
169 } else
170 ASSERT_NOT_REACHED();
171 }
172
173 return true;
174 }
175
176 }
177
178 #endif // ENABLE(OFFLINE_WEB_APPLICATIONS)
179