| 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 namespace { |
| 49 | 49 |
| 50 const char* const quotedPrintable = "quoted-printable"; | 50 const char* const quotedPrintable = "quoted-printable"; |
| 51 const char* const base64 = "base64"; | 51 const char* const base64 = "base64"; |
| 52 const char* const binary = "binary"; | 52 const char* const binary = "binary"; |
| 53 | 53 |
| 54 enum class Encoding { |
| 55 QuotedPrintable, |
| 56 Base64, |
| 57 Binary, |
| 58 }; |
| 59 } |
| 60 |
| 61 namespace blink { |
| 62 |
| 54 static String replaceNonPrintableCharacters(const String& text) { | 63 static String replaceNonPrintableCharacters(const String& text) { |
| 55 StringBuilder stringBuilder; | 64 StringBuilder stringBuilder; |
| 56 for (size_t i = 0; i < text.length(); ++i) { | 65 for (size_t i = 0; i < text.length(); ++i) { |
| 57 if (isASCIIPrintable(text[i])) | 66 if (isASCIIPrintable(text[i])) |
| 58 stringBuilder.append(text[i]); | 67 stringBuilder.append(text[i]); |
| 59 else | 68 else |
| 60 stringBuilder.append('?'); | 69 stringBuilder.append('?'); |
| 61 } | 70 } |
| 62 return stringBuilder.toString(); | 71 return stringBuilder.toString(); |
| 63 } | 72 } |
| (...skipping 39 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 103 #if OS(ANDROID) | 112 #if OS(ANDROID) |
| 104 if (url.protocolIs("content")) | 113 if (url.protocolIs("content")) |
| 105 return true; | 114 return true; |
| 106 #endif | 115 #endif |
| 107 return false; | 116 return false; |
| 108 } | 117 } |
| 109 | 118 |
| 110 void MHTMLArchive::generateMHTMLHeader(const String& boundary, | 119 void MHTMLArchive::generateMHTMLHeader(const String& boundary, |
| 111 const String& title, | 120 const String& title, |
| 112 const String& mimeType, | 121 const String& mimeType, |
| 113 SharedBuffer& outputBuffer) { | 122 std::vector<char>& outputBuffer) { |
| 114 ASSERT(!boundary.isEmpty()); | 123 ASSERT(!boundary.isEmpty()); |
| 115 ASSERT(!mimeType.isEmpty()); | 124 ASSERT(!mimeType.isEmpty()); |
| 116 | 125 |
| 117 DateComponents now; | 126 DateComponents now; |
| 118 now.setMillisecondsSinceEpochForDateTime(currentTimeMS()); | 127 now.setMillisecondsSinceEpochForDateTime(currentTimeMS()); |
| 119 // TODO(lukasza): Passing individual date/time components seems fragile. | 128 // TODO(lukasza): Passing individual date/time components seems fragile. |
| 120 String dateString = makeRFC2822DateString( | 129 String dateString = makeRFC2822DateString( |
| 121 now.weekDay(), now.monthDay(), now.month(), now.fullYear(), now.hour(), | 130 now.weekDay(), now.monthDay(), now.month(), now.fullYear(), now.hour(), |
| 122 now.minute(), now.second(), 0); | 131 now.minute(), now.second(), 0); |
| 123 | 132 |
| (...skipping 11 matching lines...) Expand all Loading... |
| 135 stringBuilder.append("\";\r\n"); | 144 stringBuilder.append("\";\r\n"); |
| 136 stringBuilder.append("\tboundary=\""); | 145 stringBuilder.append("\tboundary=\""); |
| 137 stringBuilder.append(boundary); | 146 stringBuilder.append(boundary); |
| 138 stringBuilder.append("\"\r\n\r\n"); | 147 stringBuilder.append("\"\r\n\r\n"); |
| 139 | 148 |
| 140 // We use utf8() below instead of ascii() as ascii() replaces CRLFs with ?? | 149 // We use utf8() below instead of ascii() as ascii() replaces CRLFs with ?? |
| 141 // (we still only have put ASCII characters in it). | 150 // (we still only have put ASCII characters in it). |
| 142 ASSERT(stringBuilder.toString().containsOnlyASCII()); | 151 ASSERT(stringBuilder.toString().containsOnlyASCII()); |
| 143 CString asciiString = stringBuilder.toString().utf8(); | 152 CString asciiString = stringBuilder.toString().utf8(); |
| 144 | 153 |
| 145 outputBuffer.append(asciiString.data(), asciiString.length()); | 154 outputBuffer.reserve(outputBuffer.size() + asciiString.length()); |
| 155 outputBuffer.insert(outputBuffer.end(), asciiString.data(), |
| 156 asciiString.data() + asciiString.length()); |
| 146 } | 157 } |
| 147 | 158 |
| 148 void MHTMLArchive::generateMHTMLPart(const String& boundary, | 159 void MHTMLArchive::generateMHTMLPart(const String& boundary, |
| 149 const String& contentID, | 160 const String& contentID, |
| 150 EncodingPolicy encodingPolicy, | 161 EncodingPolicy encodingPolicy, |
| 151 const SerializedResource& resource, | 162 const SerializedResource& resource, |
| 152 SharedBuffer& outputBuffer) { | 163 std::vector<char>& outputBuffer) { |
| 153 ASSERT(!boundary.isEmpty()); | 164 ASSERT(!boundary.isEmpty()); |
| 154 ASSERT(contentID.isEmpty() || contentID[0] == '<'); | 165 ASSERT(contentID.isEmpty() || contentID[0] == '<'); |
| 155 | 166 |
| 156 StringBuilder stringBuilder; | 167 StringBuilder stringBuilder; |
| 157 stringBuilder.append("--"); | 168 stringBuilder.append("--"); |
| 158 stringBuilder.append(boundary); | 169 stringBuilder.append(boundary); |
| 159 stringBuilder.append("\r\n"); | 170 stringBuilder.append("\r\n"); |
| 160 | 171 |
| 161 stringBuilder.append("Content-Type: "); | 172 stringBuilder.append("Content-Type: "); |
| 162 stringBuilder.append(resource.mimeType); | 173 stringBuilder.append(resource.mimeType); |
| 163 stringBuilder.append("\r\n"); | 174 stringBuilder.append("\r\n"); |
| 164 | 175 |
| 165 if (!contentID.isEmpty()) { | 176 if (!contentID.isEmpty()) { |
| 166 stringBuilder.append("Content-ID: "); | 177 stringBuilder.append("Content-ID: "); |
| 167 stringBuilder.append(contentID); | 178 stringBuilder.append(contentID); |
| 168 stringBuilder.append("\r\n"); | 179 stringBuilder.append("\r\n"); |
| 169 } | 180 } |
| 170 | 181 |
| 171 const char* contentEncoding = 0; | 182 const char* contentEncodingText = 0; |
| 172 if (encodingPolicy == UseBinaryEncoding) | 183 Encoding encoding = Encoding::Base64; |
| 173 contentEncoding = binary; | 184 if (encodingPolicy == UseBinaryEncoding) { |
| 174 else if (MIMETypeRegistry::isSupportedJavaScriptMIMEType(resource.mimeType) || | 185 contentEncodingText = binary; |
| 175 MIMETypeRegistry::isSupportedNonImageMIMEType(resource.mimeType)) | 186 encoding = Encoding::Binary; |
| 176 contentEncoding = quotedPrintable; | 187 } else if (MIMETypeRegistry::isSupportedJavaScriptMIMEType( |
| 177 else | 188 resource.mimeType) || |
| 178 contentEncoding = base64; | 189 MIMETypeRegistry::isSupportedNonImageMIMEType(resource.mimeType)) { |
| 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(), |
| 221 asciiString.data() + asciiString.length()); |
| 222 |
| 223 if (encoding == Encoding::Binary) { |
| 196 const char* data; | 224 const char* data; |
| 197 size_t position = 0; | 225 size_t position = 0; |
| 198 while (size_t length = resource.data->getSomeData(data, position)) { | 226 while (size_t length = resource.data->getSomeData(data, position)) { |
| 199 outputBuffer.append(data, length); | 227 outputBuffer.insert(outputBuffer.end(), data, data + length); |
| 200 position += length; | 228 position += length; |
| 201 } | 229 } |
| 202 } else { | 230 } else { |
| 203 // FIXME: ideally we would encode the content as a stream without having to | 231 // FIXME: ideally we would encode the content as a stream without having to |
| 204 // fetch it all. | 232 // fetch it all. |
| 205 const char* data = resource.data->data(); | 233 const char* data = resource.data->data(); |
| 206 size_t dataLength = resource.data->size(); | 234 size_t dataLength = resource.data->size(); |
| 207 Vector<char> encodedData; | 235 Vector<char> encodedData; |
| 208 if (!strcmp(contentEncoding, quotedPrintable)) { | 236 if (encoding == Encoding::QuotedPrintable) { |
| 209 quotedPrintableEncode(data, dataLength, encodedData); | 237 quotedPrintableEncode(data, dataLength, encodedData); |
| 210 outputBuffer.append(encodedData.data(), encodedData.size()); | 238 outputBuffer.insert(outputBuffer.end(), encodedData.data(), |
| 211 outputBuffer.append("\r\n", 2u); | 239 encodedData.data() + encodedData.size()); |
| 240 outputBuffer.push_back('\r'); |
| 241 outputBuffer.push_back('\n'); |
| 212 } else { | 242 } else { |
| 213 ASSERT(!strcmp(contentEncoding, base64)); | 243 DCHECK(encoding == Encoding::Base64); |
| 214 // We are not specifying insertLFs = true below as it would cut the lines | 244 // We are not specifying insertLFs = true below as it would cut the lines |
| 215 // with LFs and MHTML requires CRLFs. | 245 // with LFs and MHTML requires CRLFs. |
| 216 base64Encode(data, dataLength, encodedData); | 246 base64Encode(data, dataLength, encodedData); |
| 217 const size_t maximumLineLength = 76; | 247 const size_t maximumLineLength = 76; |
| 218 size_t index = 0; | 248 size_t index = 0; |
| 219 size_t encodedDataLength = encodedData.size(); | 249 size_t encodedDataLength = encodedData.size(); |
| 220 do { | 250 do { |
| 221 size_t lineLength = | 251 size_t lineLength = |
| 222 std::min(encodedDataLength - index, maximumLineLength); | 252 std::min(encodedDataLength - index, maximumLineLength); |
| 223 outputBuffer.append(encodedData.data() + index, lineLength); | 253 outputBuffer.insert(outputBuffer.end(), encodedData.data() + index, |
| 224 outputBuffer.append("\r\n", 2u); | 254 encodedData.data() + index + lineLength); |
| 255 outputBuffer.push_back('\r'); |
| 256 outputBuffer.push_back('\n'); |
| 225 index += maximumLineLength; | 257 index += maximumLineLength; |
| 226 } while (index < encodedDataLength); | 258 } while (index < encodedDataLength); |
| 227 } | 259 } |
| 228 } | 260 } |
| 229 } | 261 } |
| 230 | 262 |
| 231 void MHTMLArchive::generateMHTMLFooter(const String& boundary, | 263 void MHTMLArchive::generateMHTMLFooter(const String& boundary, |
| 232 SharedBuffer& outputBuffer) { | 264 std::vector<char>& outputBuffer) { |
| 233 ASSERT(!boundary.isEmpty()); | 265 ASSERT(!boundary.isEmpty()); |
| 234 CString asciiString = String("--" + boundary + "--\r\n").utf8(); | 266 CString asciiString = String("--" + boundary + "--\r\n").utf8(); |
| 235 outputBuffer.append(asciiString.data(), asciiString.length()); | 267 outputBuffer.reserve(outputBuffer.size() + asciiString.length()); |
| 268 outputBuffer.insert(outputBuffer.end(), asciiString.data(), |
| 269 asciiString.data() + asciiString.length()); |
| 236 } | 270 } |
| 237 | 271 |
| 238 void MHTMLArchive::setMainResource(ArchiveResource* mainResource) { | 272 void MHTMLArchive::setMainResource(ArchiveResource* mainResource) { |
| 239 m_mainResource = mainResource; | 273 m_mainResource = mainResource; |
| 240 } | 274 } |
| 241 | 275 |
| 242 void MHTMLArchive::addSubresource(ArchiveResource* resource) { | 276 void MHTMLArchive::addSubresource(ArchiveResource* resource) { |
| 243 const KURL& url = resource->url(); | 277 const KURL& url = resource->url(); |
| 244 m_subresources.set(url, resource); | 278 m_subresources.set(url, resource); |
| 245 KURL cidURI = MHTMLParser::convertContentIDToURI(resource->contentID()); | 279 KURL cidURI = MHTMLParser::convertContentIDToURI(resource->contentID()); |
| 246 if (cidURI.isValid()) | 280 if (cidURI.isValid()) |
| 247 m_subresources.set(cidURI, resource); | 281 m_subresources.set(cidURI, resource); |
| 248 } | 282 } |
| 249 | 283 |
| 250 ArchiveResource* MHTMLArchive::subresourceForURL(const KURL& url) const { | 284 ArchiveResource* MHTMLArchive::subresourceForURL(const KURL& url) const { |
| 251 return m_subresources.get(url.getString()); | 285 return m_subresources.get(url.getString()); |
| 252 } | 286 } |
| 253 | 287 |
| 254 DEFINE_TRACE(MHTMLArchive) { | 288 DEFINE_TRACE(MHTMLArchive) { |
| 255 visitor->trace(m_mainResource); | 289 visitor->trace(m_mainResource); |
| 256 visitor->trace(m_subresources); | 290 visitor->trace(m_subresources); |
| 257 } | 291 } |
| 258 | 292 |
| 259 } // namespace blink | 293 } // namespace blink |
| OLD | NEW |