String XSSAuditor::decodedSnippetForAttribute(const HTMLToken& token, const HTMLToken::Attribute& attribute, AttributeKind treatment) { const size_t kMaximumSnippetLength = 100; // The range doesn't inlcude the character which terminates the value. So, // for an input of |name="value"|, the snippet is |name="value|. For an // unquoted input of |name=value |, the snippet is |name=value|. // FIXME: We should grab one character before the name also. int start = attribute.m_nameRange.m_start - token.startIndex(); int end = attribute.m_valueRange.m_end - token.startIndex(); String decodedSnippet = fullyDecodeString(snippetForRange(token, start, end), m_parser->document()->decoder()); decodedSnippet.truncate(kMaximumSnippetLength); if (treatment == SrcLikeAttribute) { int slashCount; size_t currentLength; // Characters following the first ?, #, or third slash may come from // the page itself and can be merely ignored by an attacker's server // when a remote script or script-like resource is requested. for (slashCount = 0, currentLength = 0; currentLength < decodedSnippet.length(); ++currentLength) { if (decodedSnippet[currentLength] == '?' || decodedSnippet[currentLength] == '#' || ((decodedSnippet[currentLength] == '/' || decodedSnippet[currentLength] == '\\') && ++slashCount > 2)) { decodedSnippet.truncate(currentLength); break; } } } return decodedSnippet; }
String XSSAuditor::decodedSnippetForAttribute(const HTMLToken& token, const HTMLToken::Attribute& attribute, AttributeKind treatment) { // The range doesn't inlcude the character which terminates the value. So, // for an input of |name="value"|, the snippet is |name="value|. For an // unquoted input of |name=value |, the snippet is |name=value|. // FIXME: We should grab one character before the name also. int start = attribute.m_nameRange.m_start - token.startIndex(); int end = attribute.m_valueRange.m_end - token.startIndex(); String decodedSnippet = fullyDecodeString(m_parser->sourceForToken(token).substring(start, end - start), m_parser->document()->decoder()); decodedSnippet.truncate(kMaximumFragmentLengthTarget); if (treatment == SrcLikeAttribute) { int slashCount = 0; bool commaSeen = false; // In HTTP URLs, characters following the first ?, #, or third slash may come from // the page itself and can be merely ignored by an attacker's server when a remote // script or script-like resource is requested. In DATA URLS, the payload starts at // the first comma, and the the first /*, //, or <!-- may introduce a comment. Characters // following this may come from the page itself and may be ignored when the script is // executed. For simplicity, we don't differentiate based on URL scheme, and stop at // the first # or ?, the third slash, or the first slash or < once a comma is seen. for (size_t currentLength = 0; currentLength < decodedSnippet.length(); ++currentLength) { UChar currentChar = decodedSnippet[currentLength]; if (currentChar == '?' || currentChar == '#' || ((currentChar == '/' || currentChar == '\\') && (commaSeen || ++slashCount > 2)) || (currentChar == '<' && commaSeen)) { decodedSnippet.truncate(currentLength); break; } if (currentChar == ',') commaSeen = true; } } else if (treatment == ScriptLikeAttribute) { // Beware of trailing characters which came from the page itself, not the // injected vector. Excluding the terminating character covers common cases // where the page immediately ends the attribute, but doesn't cover more // complex cases where there is other page data following the injection. // Generally, these won't parse as javascript, so the injected vector // typically excludes them from consideration via a single-line comment or // by enclosing them in a string literal terminated later by the page's own // closing punctuation. Since the snippet has not been parsed, the vector // may also try to introduce these via entities. As a result, we'd like to // stop before the first "//", the first <!--, the first entity, or the first // quote not immediately following the first equals sign (taking whitespace // into consideration). To keep things simpler, we don't try to distinguish // between entity-introducing amperands vs. other uses, nor do we bother to // check for a second slash for a comment, nor do we bother to check for // !-- following a less-than sign. We stop instead on any ampersand // slash, or less-than sign. size_t position = 0; if ((position = decodedSnippet.find("=")) != notFound && (position = decodedSnippet.find(isNotHTMLSpace, position + 1)) != notFound && (position = decodedSnippet.find(isTerminatingCharacter, isHTMLQuote(decodedSnippet[position]) ? position + 1 : position)) != notFound) { decodedSnippet.truncate(position); } } return decodedSnippet; }
String getConfigDir(void) { String path; char *buf = path.buf(MAX_PATH); HRESULT hr = SHGetFolderPathA(NULL, CSIDL_LOCAL_APPDATA, NULL, 0, buf); if (SUCCEEDED(hr)) { path.truncate(); } else { path.truncate(0); } return path; }
//////////////// // Pretty float String String::prettyFloat(String src) { if (src.contains(".")) { size_t len = src.length(); while (src.endsWith("0")) { len--; src.truncate(len); } if (src.endsWith(".")) { len--; src.truncate(len); } } return src; }
void Resource::onMemoryDump(WebMemoryDumpLevelOfDetail levelOfDetail, WebProcessMemoryDump* memoryDump) const { static const size_t kMaxURLReportLength = 128; const String dumpName = getMemoryDumpName(); WebMemoryAllocatorDump* dump = memoryDump->createMemoryAllocatorDump(dumpName); dump->addScalar("encoded_size", "bytes", m_encodedSize); if (canDelete()) { dump->addScalar("dead_size", "bytes", m_encodedSize); } else { dump->addScalar("live_size", "bytes", m_encodedSize); } if (m_data) { dump->addScalar("purgeable_size", "bytes", isPurgeable() && !wasPurged() ? encodedSize() + overheadSize() : 0); m_data->onMemoryDump(dumpName, memoryDump); } if (levelOfDetail == WebMemoryDumpLevelOfDetail::Detailed) { String urlToReport = url().string(); if (urlToReport.length() > kMaxURLReportLength) { urlToReport.truncate(kMaxURLReportLength); urlToReport = urlToReport + "..."; } dump->addString("url", "", urlToReport); } const String overheadName = dumpName + "/metadata"; WebMemoryAllocatorDump* overheadDump = memoryDump->createMemoryAllocatorDump(overheadName); overheadDump->addScalar("size", "bytes", overheadSize()); memoryDump->addSuballocation(overheadDump->guid(), String(WTF::Partitions::kAllocatedObjectPoolName)); }
String getCurrentDir(void) { String path; size_t size = PATH_MAX; char *buf = path.buf(size); if (getcwd(buf, size)) { buf[size - 1] = 0; path.truncate(); } else { path.truncate(0); } return path; }
static bool typefacesHasWeightSuffix(const AtomicString& family, AtomicString& adjustedName, FontWeight& variantWeight) { struct FamilyWeightSuffix { const wchar_t* suffix; size_t length; FontWeight weight; }; // Mapping from suffix to weight from the DirectWrite documentation. // http://msdn.microsoft.com/en-us/library/windows/desktop/dd368082.aspx const static FamilyWeightSuffix variantForSuffix[] = { {L" thin", 5, FontWeight100}, {L" extralight", 11, FontWeight200}, {L" ultralight", 11, FontWeight200}, {L" light", 6, FontWeight300}, {L" regular", 8, FontWeight400}, {L" medium", 7, FontWeight500}, {L" demibold", 9, FontWeight600}, {L" semibold", 9, FontWeight600}, {L" extrabold", 10, FontWeight800}, {L" ultrabold", 10, FontWeight800}, {L" black", 6, FontWeight900}, {L" heavy", 6, FontWeight900}}; size_t numVariants = WTF_ARRAY_LENGTH(variantForSuffix); for (size_t i = 0; i < numVariants; i++) { const FamilyWeightSuffix& entry = variantForSuffix[i]; if (family.endsWith(entry.suffix, TextCaseUnicodeInsensitive)) { String familyName = family.getString(); familyName.truncate(family.length() - entry.length); adjustedName = AtomicString(familyName); variantWeight = entry.weight; return true; } } return false; }
static void truncateForScriptLikeAttribute(String& decodedSnippet) { // Beware of trailing characters which came from the page itself, not the // injected vector. Excluding the terminating character covers common cases // where the page immediately ends the attribute, but doesn't cover more // complex cases where there is other page data following the injection. // Generally, these won't parse as javascript, so the injected vector // typically excludes them from consideration via a single-line comment or // by enclosing them in a string literal terminated later by the page's own // closing punctuation. Since the snippet has not been parsed, the vector // may also try to introduce these via entities. As a result, we'd like to // stop before the first "//", the first <!--, the first entity, or the first // quote not immediately following the first equals sign (taking whitespace // into consideration). To keep things simpler, we don't try to distinguish // between entity-introducing amperands vs. other uses, nor do we bother to // check for a second slash for a comment, nor do we bother to check for // !-- following a less-than sign. We stop instead on any ampersand // slash, or less-than sign. size_t position = 0; if ((position = decodedSnippet.find("=")) != kNotFound && (position = decodedSnippet.find(isNotHTMLSpace<UChar>, position + 1)) != kNotFound && (position = decodedSnippet.find(isTerminatingCharacter, isHTMLQuote(decodedSnippet[position]) ? position + 1 : position)) != kNotFound) { decodedSnippet.truncate(position); } }
static void RemoveLastId() { int index = fieldId.size(); while (index != 0 && fieldId[index - 1] != '^' && fieldId[index - 1] != ':') { --index; } fieldId.truncate(index); }
void WebInspectorServer::didReceiveUnrecognizedHTTPRequest(WebSocketServerConnection* connection, PassRefPtr<HTTPRequest> request) { // request->url() contains only the path extracted from the HTTP request line // and URL is poor at parsing incomplete URLs, so extract the interesting parts manually. String path = request->url(); size_t pathEnd = path.find('?'); if (pathEnd == notFound) pathEnd = path.find('#'); if (pathEnd != notFound) path.truncate(pathEnd); // Ask for the complete payload in memory for the sake of simplicity. A more efficient way would be // to ask for header data and then let the platform abstraction write the payload straight on the connection. Vector<char> body; String contentType; bool found = platformResourceForPath(path, body, contentType); HTTPHeaderMap headerFields; headerFields.set("Connection", "close"); headerFields.set("Content-Length", String::number(body.size())); if (found) headerFields.set("Content-Type", contentType); // Send when ready and close immediately afterwards. connection->sendHTTPResponseHeader(found ? 200 : 404, found ? "OK" : "Not Found", headerFields); connection->sendRawData(body.data(), body.size()); connection->shutdownAfterSendOrNow(); }
void TextFieldInputType::handleBeforeTextInsertedEvent(BeforeTextInsertedEvent* event) { // Make sure that the text to be inserted will not violate the maxLength. // We use HTMLInputElement::innerEditorValue() instead of // HTMLInputElement::value() because they can be mismatched by // sanitizeValue() in HTMLInputElement::subtreeHasChanged() in some cases. unsigned oldLength = element().innerEditorValue().length(); // selectionLength represents the selection length of this text field to be // removed by this insertion. // If the text field has no focus, we don't need to take account of the // selection length. The selection is the source of text drag-and-drop in // that case, and nothing in the text field will be removed. unsigned selectionLength = element().focused() ? plainText(element().document().frame()->selection().selection().toNormalizedRange().get()).length() : 0; ASSERT(oldLength >= selectionLength); // Selected characters will be removed by the next text event. unsigned baseLength = oldLength - selectionLength; unsigned maxLength = static_cast<unsigned>(this->maxLength()); // maxLength can never be negative. unsigned appendableLength = maxLength > baseLength ? maxLength - baseLength : 0; // Truncate the inserted text to avoid violating the maxLength and other constraints. String eventText = event->text(); unsigned textLength = eventText.length(); while (textLength > 0 && isASCIILineBreak(eventText[textLength - 1])) textLength--; eventText.truncate(textLength); eventText.replace("\r\n", " "); eventText.replace('\r', ' '); eventText.replace('\n', ' '); event->setText(limitLength(eventText, appendableLength)); }
static void truncateForSrcLikeAttribute(String& decodedSnippet) { // In HTTP URLs, characters following the first ?, #, or third slash may come from // the page itself and can be merely ignored by an attacker's server when a remote // script or script-like resource is requested. In data URLs, the payload starts at // the first comma, and the first /*, //, or <!-- may introduce a comment. Also // data URLs may use the same string literal tricks as with script content itself. // In either case, content following this may come from the page and may be ignored // when the script is executed. Also, any of these characters may now be represented // by the (enlarged) set of HTML5 entities. // For simplicity, we don't differentiate based on URL scheme, and stop at the first // & (since it might be part of an entity for any of the subsequent punctuation) // the first # or ?, the third slash, or the first slash, <, ', or " once a comma // is seen. int slashCount = 0; bool commaSeen = false; for (size_t currentLength = 0; currentLength < decodedSnippet.length(); ++currentLength) { UChar currentChar = decodedSnippet[currentLength]; if (currentChar == '&' || currentChar == '?' || currentChar == '#' || ((currentChar == '/' || currentChar == '\\') && (commaSeen || ++slashCount > 2)) || (currentChar == '<' && commaSeen) || (currentChar == '\'' && commaSeen) || (currentChar == '"' && commaSeen)) { decodedSnippet.truncate(currentLength); return; } if (currentChar == ',') commaSeen = true; } }
String Value_datetime_imp::get_String( tslen inLimit ) const { String str; if( inLimit != 0 ) { UChar* p = str.getBuffer(kDateTimeStrMaxLength + 1); const DTFormat* pDTFormat = get_DTFormat(); Convert_datetime_str_fast( (DateTimeEncoded&)mValue, pDTFormat->mDateFormat, pDTFormat->mDateSep, pDTFormat->mTimeSep, p ); if( ((DateTimeEncoded&)mValue).encoded < 0 ) str.releaseBuffer(kDateTimeStrMaxLength); // 24 symbols for negative dates else str.releaseBuffer(kDateTimeStrMaxLength - 1); // 23 symbols for positive dates // not -1 and less than maxLen if( inLimit > 0 && vuint32(inLimit) < kDateTimeStrMaxLength ) { str.truncate( inLimit ); } } return str; }
void Resource::onMemoryDump(WebMemoryDumpLevelOfDetail levelOfDetail, WebProcessMemoryDump* memoryDump) const { static const size_t kMaxURLReportLength = 128; static const int kMaxResourceClientToShowInMemoryInfra = 10; const String dumpName = getMemoryDumpName(); WebMemoryAllocatorDump* dump = memoryDump->createMemoryAllocatorDump(dumpName); dump->addScalar("encoded_size", "bytes", m_encodedSize); if (canDelete()) { dump->addScalar("dead_size", "bytes", m_encodedSize); } else { dump->addScalar("live_size", "bytes", m_encodedSize); } if (m_data) { dump->addScalar("purgeable_size", "bytes", isPurgeable() && !wasPurged() ? encodedSize() + overheadSize() : 0); m_data->onMemoryDump(dumpName, memoryDump); } if (levelOfDetail == WebMemoryDumpLevelOfDetail::Detailed) { String urlToReport = url().string(); if (urlToReport.length() > kMaxURLReportLength) { urlToReport.truncate(kMaxURLReportLength); urlToReport = urlToReport + "..."; } dump->addString("url", "", urlToReport); dump->addString("reason_not_deletable", "", reasonNotDeletable()); Vector<String> clientNames; ResourceClientWalker<ResourceClient> walker(m_clients); while (ResourceClient* client = walker.next()) clientNames.append(client->debugName()); ResourceClientWalker<ResourceClient> walker2(m_clientsAwaitingCallback); while (ResourceClient* client = walker2.next()) clientNames.append("(awaiting) " + client->debugName()); ResourceClientWalker<ResourceClient> walker3(m_finishedClients); while (ResourceClient* client = walker3.next()) clientNames.append("(finished) " + client->debugName()); std::sort(clientNames.begin(), clientNames.end(), codePointCompareLessThan); StringBuilder builder; for (size_t i = 0; i < clientNames.size() && i < kMaxResourceClientToShowInMemoryInfra; ++i) { if (i > 0) builder.append(" / "); builder.append(clientNames[i]); } if (clientNames.size() > kMaxResourceClientToShowInMemoryInfra) { builder.append(" / and "); builder.appendNumber(clientNames.size() - kMaxResourceClientToShowInMemoryInfra); builder.append(" more"); } dump->addString("ResourceClient", "", builder.toString()); } const String overheadName = dumpName + "/metadata"; WebMemoryAllocatorDump* overheadDump = memoryDump->createMemoryAllocatorDump(overheadName); overheadDump->addScalar("size", "bytes", overheadSize()); memoryDump->addSuballocation(overheadDump->guid(), String(WTF::Partitions::kAllocatedObjectPoolName)); }
String directoryName(const String& path) { String fileName = pathGetFileName(path); String dirName = String(path); dirName.truncate(dirName.length() - pathGetFileName(path).length()); return dirName; }
String directoryName(const String& path) { String name = path.left(path.length() - pathGetFileName(path).length()); if (name.characterStartingAt(name.length() - 1) == '\\') { // Remove any trailing "\". name.truncate(name.length() - 1); } return name; }
static String extractURL(const String &inURL, String* title) { String url = inURL; int splitLoc = url.find('\n'); if (splitLoc > 0) { if (title) *title = url.substring(splitLoc+1); url.truncate(splitLoc); } else if (title) *title = url; return url; }
String StyledMarkupAccumulator::stringValueForRange(const Node& node, const Range* range) { if (!range) return node.nodeValue(); String nodeValue = node.nodeValue(); if (&node == range->endContainer()) nodeValue.truncate(range->endOffset()); if (&node == range->startContainer()) nodeValue.remove(0, range->startOffset()); return nodeValue; }
String StyledMarkupAccumulator::stringValueForRange(const Text& node) { if (m_start.isNull()) return node.data(); String str = node.data(); if (m_start.text() == node) str.truncate(m_end.offset()); if (m_end.text() == node) str.remove(0, m_start.offset()); return str; }
void validateFilename(String& name, String& extension) { // Remove any invalid file system characters. name = name.removeCharacters(&isInvalidFileCharacter); extension = extension.removeCharacters(&isInvalidFileCharacter); if (extension.length() >= maxFilenameLength) extension = String(); // Truncate overly-long filenames, reserving one character for a dot. name.truncate(maxFilenameLength - extension.length() - 1); }
String XSSAuditor::canonicalize(const String& snippet, TruncationStyle truncationStyle) { String decodedSnippet = fullyDecodeString(snippet, m_encoding); if (truncationStyle != TruncationStyle::None) { decodedSnippet.truncate(kMaximumFragmentLengthTarget); if (truncationStyle == TruncationStyle::SrcLikeAttribute) truncateForSrcLikeAttribute(decodedSnippet); else if (truncationStyle == TruncationStyle::ScriptLikeAttribute) truncateForScriptLikeAttribute(decodedSnippet); } return decodedSnippet.removeCharacters(&isNonCanonicalCharacter); }
String StyledMarkupAccumulator::stringValueForRange(const Node* node, const Range* range) { if (!range) return node->nodeValue(); String str = node->nodeValue(); if (node == range->endContainer()) str.truncate(range->endOffset()); if (node == range->startContainer()) str.remove(0, range->startOffset()); return str; }
static String stringValueForRange(const Node* node, const Range* range) { if (!range) return node->nodeValue(); String str = node->nodeValue(); ExceptionCode ec; if (node == range->endContainer(ec)) str.truncate(range->endOffset(ec)); if (node == range->startContainer(ec)) str.remove(0, range->startOffset(ec)); return str; }
String getCurrentDir(void) { String path; size_t size = PATH_MAX; char *buf = path.buf(size); getcwd(buf, size); buf[size - 1] = 0; path.truncate(); return path; }
String StyledMarkupAccumulator::stringValueForRange(const Node& node, const Range* range) { if (!node.isTextNode()) return emptyString(); String text = toText(node).data(); if (!range) return text; if (node == range->endContainer()) text.truncate(range->endOffset()); if (node == range->startContainer()) text.remove(0, range->startOffset()); return text; }
String getProcessName(void) { String path; size_t size = MAX_PATH; char *buf = path.buf(size); DWORD nWritten = GetModuleFileNameA(NULL, buf, size); (void)nWritten; path.truncate(); return path; }
String TextCodecUTF16::decode(const char* bytes, size_t length, bool) { if (!length) return String(); const unsigned char* p = reinterpret_cast<const unsigned char*>(bytes); size_t numBytes = length + m_haveBufferedByte; size_t numChars = numBytes / 2; UChar* buffer; String result = String::newUninitialized(numChars, buffer); UChar* q = buffer; if (m_haveBufferedByte) { UChar c; if (m_littleEndian) c = m_bufferedByte | (p[0] << 8); else c = (m_bufferedByte << 8) | p[0]; if (c != BOM) *q++ = c; m_haveBufferedByte = false; p += 1; numChars -= 1; } if (m_littleEndian) for (size_t i = 0; i < numChars; ++i) { UChar c = p[0] | (p[1] << 8); p += 2; if (c != BOM) *q++ = c; } else for (size_t i = 0; i < numChars; ++i) { UChar c = (p[0] << 8) | p[1]; p += 2; if (c != BOM) *q++ = c; } if (numBytes & 1) { ASSERT(!m_haveBufferedByte); m_haveBufferedByte = true; m_bufferedByte = p[0]; } result.truncate(q - buffer); return result; }
static void writeImageToDataObject(DataObject* dataObject, Element* element, const KURL& url) { // Shove image data into a DataObject for use as a file ImageResourceContent* cachedImage = getImageResourceContent(element); if (!cachedImage || !cachedImage->getImage() || !cachedImage->isLoaded()) return; RefPtr<SharedBuffer> imageBuffer = cachedImage->getImage()->data(); if (!imageBuffer || !imageBuffer->size()) return; String imageExtension = cachedImage->getImage()->filenameExtension(); ASSERT(!imageExtension.isEmpty()); // Determine the filename for the file contents of the image. String filename = cachedImage->response().suggestedFilename(); if (filename.isEmpty()) filename = url.lastPathComponent(); String fileExtension; if (filename.isEmpty()) { filename = element->getAttribute(HTMLNames::altAttr); } else { // Strip any existing extension. Assume that alt text is usually not a // filename. int extensionIndex = filename.reverseFind('.'); if (extensionIndex != -1) { fileExtension = filename.substring(extensionIndex + 1); filename.truncate(extensionIndex); } } if (!fileExtension.isEmpty() && fileExtension != imageExtension) { String imageMimeType = MIMETypeRegistry::getMIMETypeForExtension(imageExtension); ASSERT(imageMimeType.startsWith("image/")); // Use the file extension only if it has imageMimeType: it's untrustworthy // otherwise. if (imageMimeType == MIMETypeRegistry::getMIMETypeForExtension(fileExtension)) imageExtension = fileExtension; } imageExtension = "." + imageExtension; validateFilename(filename, imageExtension); dataObject->addSharedBuffer(filename + imageExtension, imageBuffer); }
String getCurrentDir(void) { String path; DWORD size = MAX_PATH; char *buf = path.buf(size); DWORD ret = GetCurrentDirectoryA(size, buf); (void)ret; buf[size - 1] = 0; path.truncate(); return path; }
void TextFieldInputType::handleBeforeTextInsertedEvent( BeforeTextInsertedEvent* event) { // Make sure that the text to be inserted will not violate the maxLength. // We use HTMLInputElement::innerEditorValue() instead of // HTMLInputElement::value() because they can be mismatched by // sanitizeValue() in HTMLInputElement::subtreeHasChanged() in some cases. unsigned oldLength = element().innerEditorValue().length(); // selectionLength represents the selection length of this text field to be // removed by this insertion. // If the text field has no focus, we don't need to take account of the // selection length. The selection is the source of text drag-and-drop in // that case, and nothing in the text field will be removed. unsigned selectionLength = 0; if (element().isFocused()) { // TODO(xiaochengh): The use of updateStyleAndLayoutIgnorePendingStylesheets // needs to be audited. See http://crbug.com/590369 for more details. element().document().updateStyleAndLayoutIgnorePendingStylesheets(); selectionLength = element().document().frame()->selection().selectedText().length(); } DCHECK_GE(oldLength, selectionLength); // Selected characters will be removed by the next text event. unsigned baseLength = oldLength - selectionLength; unsigned maxLength; if (this->maxLength() < 0) maxLength = std::numeric_limits<int>::max(); else maxLength = static_cast<unsigned>(this->maxLength()); unsigned appendableLength = maxLength > baseLength ? maxLength - baseLength : 0; // Truncate the inserted text to avoid violating the maxLength and other // constraints. String eventText = event->text(); unsigned textLength = eventText.length(); while (textLength > 0 && isASCIILineBreak(eventText[textLength - 1])) textLength--; eventText.truncate(textLength); eventText.replace("\r\n", " "); eventText.replace('\r', ' '); eventText.replace('\n', ' '); event->setText(limitLength(eventText, appendableLength)); }