OLD | NEW |
---|---|
1 /* | 1 /* |
2 * Copyright (C) 2011 Google Inc. All rights reserved. | 2 * Copyright (C) 2011 Google Inc. All rights reserved. |
3 * | 3 * |
4 * Redistribution and use in source and binary forms, with or without | 4 * Redistribution and use in source and binary forms, with or without |
5 * modification, are permitted provided that the following conditions are | 5 * modification, are permitted provided that the following conditions are |
6 * met: | 6 * met: |
7 * | 7 * |
8 * * Redistributions of source code must retain the above copyright | 8 * * Redistributions of source code must retain the above copyright |
9 * notice, this list of conditions and the following disclaimer. | 9 * notice, this list of conditions and the following disclaimer. |
10 * * Redistributions in binary form must reproduce the above | 10 * * Redistributions in binary form must reproduce the above |
(...skipping 27 matching lines...) Expand all Loading... | |
38 #include "platform/mhtml/MHTMLParser.h" | 38 #include "platform/mhtml/MHTMLParser.h" |
39 #include "platform/text/QuotedPrintable.h" | 39 #include "platform/text/QuotedPrintable.h" |
40 #include "platform/weborigin/SchemeRegistry.h" | 40 #include "platform/weborigin/SchemeRegistry.h" |
41 #include "wtf/Assertions.h" | 41 #include "wtf/Assertions.h" |
42 #include "wtf/CryptographicallyRandomNumber.h" | 42 #include "wtf/CryptographicallyRandomNumber.h" |
43 #include "wtf/CurrentTime.h" | 43 #include "wtf/CurrentTime.h" |
44 #include "wtf/DateMath.h" | 44 #include "wtf/DateMath.h" |
45 #include "wtf/text/Base64.h" | 45 #include "wtf/text/Base64.h" |
46 #include "wtf/text/StringBuilder.h" | 46 #include "wtf/text/StringBuilder.h" |
47 | 47 |
48 namespace blink { | 48 |
49 namespace { | |
49 | 50 |
50 const char* const quotedPrintable = "quoted-printable"; | 51 const char* const quotedPrintable = "quoted-printable"; |
51 const char* const base64 = "base64"; | 52 const char* const base64 = "base64"; |
52 const char* const binary = "binary"; | 53 const char* const binary = "binary"; |
53 | 54 |
55 enum class Encoding { | |
56 QuotedPrintable, | |
57 Base64, | |
58 Binary, | |
59 }; | |
60 | |
61 } | |
62 | |
63 namespace blink { | |
64 | |
54 static String replaceNonPrintableCharacters(const String& text) | 65 static String replaceNonPrintableCharacters(const String& text) |
55 { | 66 { |
56 StringBuilder stringBuilder; | 67 StringBuilder stringBuilder; |
57 for (size_t i = 0; i < text.length(); ++i) { | 68 for (size_t i = 0; i < text.length(); ++i) { |
58 if (isASCIIPrintable(text[i])) | 69 if (isASCIIPrintable(text[i])) |
59 stringBuilder.append(text[i]); | 70 stringBuilder.append(text[i]); |
60 else | 71 else |
61 stringBuilder.append('?'); | 72 stringBuilder.append('?'); |
62 } | 73 } |
63 return stringBuilder.toString(); | 74 return stringBuilder.toString(); |
(...skipping 37 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
101 return true; | 112 return true; |
102 #if OS(ANDROID) | 113 #if OS(ANDROID) |
103 if (url.protocolIs("content")) | 114 if (url.protocolIs("content")) |
104 return true; | 115 return true; |
105 #endif | 116 #endif |
106 return false; | 117 return false; |
107 } | 118 } |
108 | 119 |
109 void MHTMLArchive::generateMHTMLHeader( | 120 void MHTMLArchive::generateMHTMLHeader( |
110 const String& boundary, const String& title, const String& mimeType, | 121 const String& boundary, const String& title, const String& mimeType, |
111 SharedBuffer& outputBuffer) | 122 std::vector<char>& outputBuffer) |
112 { | 123 { |
113 ASSERT(!boundary.isEmpty()); | 124 ASSERT(!boundary.isEmpty()); |
114 ASSERT(!mimeType.isEmpty()); | 125 ASSERT(!mimeType.isEmpty()); |
115 | 126 |
116 DateComponents now; | 127 DateComponents now; |
117 now.setMillisecondsSinceEpochForDateTime(currentTimeMS()); | 128 now.setMillisecondsSinceEpochForDateTime(currentTimeMS()); |
118 // TODO(lukasza): Passing individual date/time components seems fragile. | 129 // TODO(lukasza): Passing individual date/time components seems fragile. |
119 String dateString = makeRFC2822DateString( | 130 String dateString = makeRFC2822DateString( |
120 now.weekDay(), now.monthDay(), now.month(), now.fullYear(), | 131 now.weekDay(), now.monthDay(), now.month(), now.fullYear(), |
121 now.hour(), now.minute(), now.second(), 0); | 132 now.hour(), now.minute(), now.second(), 0); |
(...skipping 12 matching lines...) Expand all Loading... | |
134 stringBuilder.append("\";\r\n"); | 145 stringBuilder.append("\";\r\n"); |
135 stringBuilder.append("\tboundary=\""); | 146 stringBuilder.append("\tboundary=\""); |
136 stringBuilder.append(boundary); | 147 stringBuilder.append(boundary); |
137 stringBuilder.append("\"\r\n\r\n"); | 148 stringBuilder.append("\"\r\n\r\n"); |
138 | 149 |
139 // We use utf8() below instead of ascii() as ascii() replaces CRLFs with ?? | 150 // We use utf8() below instead of ascii() as ascii() replaces CRLFs with ?? |
140 // (we still only have put ASCII characters in it). | 151 // (we still only have put ASCII characters in it). |
141 ASSERT(stringBuilder.toString().containsOnlyASCII()); | 152 ASSERT(stringBuilder.toString().containsOnlyASCII()); |
142 CString asciiString = stringBuilder.toString().utf8(); | 153 CString asciiString = stringBuilder.toString().utf8(); |
143 | 154 |
144 outputBuffer.append(asciiString.data(), asciiString.length()); | 155 outputBuffer.reserve(outputBuffer.size() + asciiString.length()); |
156 outputBuffer.insert(outputBuffer.end(), asciiString.data(), asciiString.data () + asciiString.length()); | |
145 } | 157 } |
146 | 158 |
147 void MHTMLArchive::generateMHTMLPart( | 159 void MHTMLArchive::generateMHTMLPart( |
148 const String& boundary, | 160 const String& boundary, |
149 const String& contentID, | 161 const String& contentID, |
150 EncodingPolicy encodingPolicy, | 162 EncodingPolicy encodingPolicy, |
151 const SerializedResource& resource, | 163 const SerializedResource& resource, |
152 SharedBuffer& outputBuffer) | 164 std::vector<char>& outputBuffer) |
153 { | 165 { |
154 ASSERT(!boundary.isEmpty()); | 166 ASSERT(!boundary.isEmpty()); |
155 ASSERT(contentID.isEmpty() || contentID[0] == '<'); | 167 ASSERT(contentID.isEmpty() || contentID[0] == '<'); |
156 | 168 |
157 StringBuilder stringBuilder; | 169 StringBuilder stringBuilder; |
158 stringBuilder.append("--"); | 170 stringBuilder.append("--"); |
159 stringBuilder.append(boundary); | 171 stringBuilder.append(boundary); |
160 stringBuilder.append("\r\n"); | 172 stringBuilder.append("\r\n"); |
161 | 173 |
162 stringBuilder.append("Content-Type: "); | 174 stringBuilder.append("Content-Type: "); |
163 stringBuilder.append(resource.mimeType); | 175 stringBuilder.append(resource.mimeType); |
164 stringBuilder.append("\r\n"); | 176 stringBuilder.append("\r\n"); |
165 | 177 |
166 if (!contentID.isEmpty()) { | 178 if (!contentID.isEmpty()) { |
167 stringBuilder.append("Content-ID: "); | 179 stringBuilder.append("Content-ID: "); |
168 stringBuilder.append(contentID); | 180 stringBuilder.append(contentID); |
169 stringBuilder.append("\r\n"); | 181 stringBuilder.append("\r\n"); |
170 } | 182 } |
171 | 183 |
172 const char* contentEncoding = 0; | 184 const char* contentEncodingText = 0; |
173 if (encodingPolicy == UseBinaryEncoding) | 185 Encoding encoding = Encoding::Base64; |
174 contentEncoding = binary; | 186 if (encodingPolicy == UseBinaryEncoding) { |
175 else if (MIMETypeRegistry::isSupportedJavaScriptMIMEType(resource.mimeType) || MIMETypeRegistry::isSupportedNonImageMIMEType(resource.mimeType)) | 187 contentEncodingText = binary; |
176 contentEncoding = quotedPrintable; | 188 encoding = Encoding::Binary; |
177 else | 189 } else if (MIMETypeRegistry::isSupportedJavaScriptMIMEType(resource.mimeType ) || MIMETypeRegistry::isSupportedNonImageMIMEType(resource.mimeType)) { |
178 contentEncoding = base64; | 190 contentEncodingText = quotedPrintable; |
191 encoding = Encoding::QuotedPrintable; | |
192 } else { | |
193 contentEncodingText = base64; | |
194 } | |
179 | 195 |
180 stringBuilder.append("Content-Transfer-Encoding: "); | 196 stringBuilder.append("Content-Transfer-Encoding: "); |
181 stringBuilder.append(contentEncoding); | 197 stringBuilder.append(contentEncodingText); |
182 stringBuilder.append("\r\n"); | 198 stringBuilder.append("\r\n"); |
183 | 199 |
184 if (!resource.url.protocolIsAbout()) { | 200 if (!resource.url.protocolIsAbout()) { |
185 stringBuilder.append("Content-Location: "); | 201 stringBuilder.append("Content-Location: "); |
186 stringBuilder.append(resource.url.getString()); | 202 stringBuilder.append(resource.url.getString()); |
187 stringBuilder.append("\r\n"); | 203 stringBuilder.append("\r\n"); |
188 } | 204 } |
189 | 205 |
190 stringBuilder.append("\r\n"); | 206 stringBuilder.append("\r\n"); |
191 | 207 |
192 CString asciiString = stringBuilder.toString().utf8(); | 208 CString asciiString = stringBuilder.toString().utf8(); |
193 outputBuffer.append(asciiString.data(), asciiString.length()); | |
194 | 209 |
195 if (!strcmp(contentEncoding, binary)) { | 210 // Best guess for a reserved size. It should work well for binary and base64 |
211 // (see https://en.wikipedia.org/wiki/Base64#MIME); not so much for | |
212 // quoted-printable which is harder to estimate. | |
213 std::size_t expectedFinalSize = outputBuffer.size() + asciiString.length(); | |
214 if (encoding == Encoding::Base64) | |
215 expectedFinalSize += static_cast<std::size_t>(resource.data->size() * 1. 37); | |
216 else | |
217 expectedFinalSize += resource.data->size(); | |
218 outputBuffer.reserve(expectedFinalSize); | |
219 | |
220 outputBuffer.insert(outputBuffer.end(), asciiString.data(), asciiString.data () + asciiString.length()); | |
221 | |
222 if (encoding == Encoding::Binary) { | |
196 const char* data; | 223 const char* data; |
197 size_t position = 0; | 224 size_t position = 0; |
198 while (size_t length = resource.data->getSomeData(data, position)) { | 225 while (size_t length = resource.data->getSomeData(data, position)) { |
199 outputBuffer.append(data, length); | 226 outputBuffer.insert(outputBuffer.end(), data, data + length); |
200 position += length; | 227 position += length; |
201 } | 228 } |
202 } else { | 229 } else { |
203 // FIXME: ideally we would encode the content as a stream without having to fetch it all. | 230 // FIXME: ideally we would encode the content as a stream without having to fetch it all. |
204 const char* data = resource.data->data(); | 231 const char* data = resource.data->data(); |
205 size_t dataLength = resource.data->size(); | 232 size_t dataLength = resource.data->size(); |
206 Vector<char> encodedData; | 233 Vector<char> encodedData; |
207 if (!strcmp(contentEncoding, quotedPrintable)) { | 234 if (encoding == Encoding::QuotedPrintable) { |
208 quotedPrintableEncode(data, dataLength, encodedData); | 235 quotedPrintableEncode(data, dataLength, encodedData); |
209 outputBuffer.append(encodedData.data(), encodedData.size()); | 236 outputBuffer.insert(outputBuffer.end(), encodedData.data(), encodedD ata.data() + encodedData.size()); |
210 outputBuffer.append("\r\n", 2u); | 237 outputBuffer.push_back('\r'); |
238 outputBuffer.push_back('\n'); | |
211 } else { | 239 } else { |
212 ASSERT(!strcmp(contentEncoding, base64)); | 240 DCHECK(encoding == Encoding::Base64); |
carlosk
2016/10/03 23:51:05
I replaced ASSERT with DCHECK here as I understand
| |
213 // We are not specifying insertLFs = true below as it would cut the lines with LFs and MHTML requires CRLFs. | 241 // We are not specifying insertLFs = true below as it would cut the lines with LFs and MHTML requires CRLFs. |
214 base64Encode(data, dataLength, encodedData); | 242 base64Encode(data, dataLength, encodedData); |
215 const size_t maximumLineLength = 76; | 243 const size_t maximumLineLength = 76; |
216 size_t index = 0; | 244 size_t index = 0; |
217 size_t encodedDataLength = encodedData.size(); | 245 size_t encodedDataLength = encodedData.size(); |
218 do { | 246 do { |
219 size_t lineLength = std::min(encodedDataLength - index, maximumL ineLength); | 247 size_t lineLength = std::min(encodedDataLength - index, maximumL ineLength); |
220 outputBuffer.append(encodedData.data() + index, lineLength); | 248 outputBuffer.insert(outputBuffer.end(), encodedData.data() + ind ex, encodedData.data() + index + lineLength); |
221 outputBuffer.append("\r\n", 2u); | 249 outputBuffer.push_back('\r'); |
250 outputBuffer.push_back('\n'); | |
222 index += maximumLineLength; | 251 index += maximumLineLength; |
223 } while (index < encodedDataLength); | 252 } while (index < encodedDataLength); |
224 } | 253 } |
225 } | 254 } |
226 } | 255 } |
227 | 256 |
228 void MHTMLArchive::generateMHTMLFooter( | 257 void MHTMLArchive::generateMHTMLFooter( |
229 const String& boundary, | 258 const String& boundary, |
230 SharedBuffer& outputBuffer) | 259 std::vector<char>& outputBuffer) |
231 { | 260 { |
232 ASSERT(!boundary.isEmpty()); | 261 ASSERT(!boundary.isEmpty()); |
233 CString asciiString = String("--" + boundary + "--\r\n").utf8(); | 262 CString asciiString = String("--" + boundary + "--\r\n").utf8(); |
234 outputBuffer.append(asciiString.data(), asciiString.length()); | 263 outputBuffer.reserve(outputBuffer.size() + asciiString.length()); |
264 outputBuffer.insert(outputBuffer.end(), asciiString.data(), asciiString.data () + asciiString.length()); | |
235 } | 265 } |
236 | 266 |
237 void MHTMLArchive::setMainResource(ArchiveResource* mainResource) | 267 void MHTMLArchive::setMainResource(ArchiveResource* mainResource) |
238 { | 268 { |
239 m_mainResource = mainResource; | 269 m_mainResource = mainResource; |
240 } | 270 } |
241 | 271 |
242 void MHTMLArchive::addSubresource(ArchiveResource* resource) | 272 void MHTMLArchive::addSubresource(ArchiveResource* resource) |
243 { | 273 { |
244 const KURL& url = resource->url(); | 274 const KURL& url = resource->url(); |
245 m_subresources.set(url, resource); | 275 m_subresources.set(url, resource); |
246 KURL cidURI = MHTMLParser::convertContentIDToURI(resource->contentID()); | 276 KURL cidURI = MHTMLParser::convertContentIDToURI(resource->contentID()); |
247 if (cidURI.isValid()) | 277 if (cidURI.isValid()) |
248 m_subresources.set(cidURI, resource); | 278 m_subresources.set(cidURI, resource); |
249 } | 279 } |
250 | 280 |
251 ArchiveResource* MHTMLArchive::subresourceForURL(const KURL& url) const | 281 ArchiveResource* MHTMLArchive::subresourceForURL(const KURL& url) const |
252 { | 282 { |
253 return m_subresources.get(url.getString()); | 283 return m_subresources.get(url.getString()); |
254 } | 284 } |
255 | 285 |
256 DEFINE_TRACE(MHTMLArchive) | 286 DEFINE_TRACE(MHTMLArchive) |
257 { | 287 { |
258 visitor->trace(m_mainResource); | 288 visitor->trace(m_mainResource); |
259 visitor->trace(m_subresources); | 289 visitor->trace(m_subresources); |
260 } | 290 } |
261 | 291 |
262 } // namespace blink | 292 } // namespace blink |
OLD | NEW |