Chromium Code Reviews| 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 |