Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(204)

Unified Diff: third_party/WebKit/Source/platform/network/ParsedContentType.cpp

Issue 2708523003: Make ParsedContentType more conformant to the spec (Closed)
Patch Set: fix Created 3 years, 10 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
Index: third_party/WebKit/Source/platform/network/ParsedContentType.cpp
diff --git a/third_party/WebKit/Source/platform/network/ParsedContentType.cpp b/third_party/WebKit/Source/platform/network/ParsedContentType.cpp
index b8e7814c017001280345ba7d34ac70f9ee9b863a..e7e6880b9c89d4f80af199899a1511082274730b 100644
--- a/third_party/WebKit/Source/platform/network/ParsedContentType.cpp
+++ b/third_party/WebKit/Source/platform/network/ParsedContentType.cpp
@@ -31,57 +31,132 @@
#include "platform/network/ParsedContentType.h"
-#include "wtf/text/CString.h"
#include "wtf/text/StringBuilder.h"
+#include "wtf/text/StringView.h"
namespace blink {
-using SubstringRange = ParsedContentType::SubstringRange;
+using Mode = ParsedContentType::Mode;
namespace {
-void skipSpaces(const String& input, unsigned& startIndex) {
- while (startIndex < input.length() && input[startIndex] == ' ')
- ++startIndex;
+bool isTokenCharacter(Mode mode, UChar c) {
+ if (c >= 128)
+ return false;
+ if (c < 0x20)
+ return false;
+
+ switch (c) {
+ case ' ':
+ case ';':
+ case '"':
+ return false;
+ case '(':
+ case ')':
+ case '<':
+ case '>':
+ case '@':
+ case ',':
+ case ':':
+ case '\\':
+ case '/':
+ case '[':
+ case ']':
+ case '?':
+ case '=':
+ return mode == Mode::Relaxed;
+ default:
+ return true;
+ }
}
-SubstringRange parseParameterPart(const String& input, unsigned& startIndex) {
- unsigned inputLength = input.length();
- unsigned tokenStart = startIndex;
- unsigned& tokenEnd = startIndex;
-
- if (tokenEnd >= inputLength)
- return SubstringRange();
-
- bool quoted = input[tokenStart] == '\"';
- bool escape = false;
-
- while (tokenEnd < inputLength) {
- UChar c = input[tokenEnd];
- if (quoted && tokenStart != tokenEnd && c == '\"' && !escape)
- return SubstringRange(tokenStart + 1, tokenEnd++ - tokenStart - 1);
- if (!quoted && (c == ';' || c == '='))
- return SubstringRange(tokenStart, tokenEnd - tokenStart);
- escape = !escape && c == '\\';
- ++tokenEnd;
+bool consume(char c, const String& input, unsigned& index) {
+ DCHECK_NE(c, ' ');
+ while (index < input.length() && input[index] == ' ')
+ ++index;
+
+ if (index < input.length() && input[index] == c) {
+ ++index;
+ return true;
}
+ return false;
+}
+
+bool consumeToken(Mode mode,
+ const String& input,
+ unsigned& index,
+ StringView& output) {
+ DCHECK(output.isNull());
+
+ while (index < input.length() && input[index] == ' ')
+ ++index;
+
+ auto start = index;
+ while (index < input.length() && isTokenCharacter(mode, input[index]))
+ ++index;
- if (quoted)
- return SubstringRange();
- return SubstringRange(tokenStart, tokenEnd - tokenStart);
+ if (start == index)
+ return false;
+
+ output = StringView(input, start, index - start);
+ return true;
}
-String substringForRange(const String& string, const SubstringRange& range) {
- return string.substring(range.first, range.second);
+bool consumeQuotedString(const String& input, unsigned& index, String& output) {
+ StringBuilder builder;
+ DCHECK_EQ('"', input[index]);
+ ++index;
+ while (index < input.length()) {
+ if (input[index] == '\\') {
+ ++index;
+ if (index == input.length())
+ return false;
+ builder.append(input[index]);
+ ++index;
+ continue;
+ }
+ if (input[index] == '"') {
+ output = builder.toString();
+ ++index;
+ return true;
+ }
+ builder.append(input[index]);
+ ++index;
+ }
+ return false;
+}
+
+bool consumeTokenOrQuotedString(Mode mode,
+ const String& input,
+ unsigned& index,
+ String& output) {
+ while (index < input.length() && input[index] == ' ')
+ ++index;
+ if (input.length() == index)
+ return false;
+ if (input[index] == '"') {
+ return consumeQuotedString(input, index, output);
+ }
+ StringView view;
+ auto result = consumeToken(mode, input, index, view);
+ output = view.toString();
+ return result;
+}
+
+bool isEnd(const String& input, unsigned index) {
+ while (index < input.length()) {
+ if (input[index] != ' ')
+ return false;
+ ++index;
+ }
+ return true;
}
} // namespace
-ParsedContentType::ParsedContentType(const String& contentType) {
- if (contentType.contains('\r') || contentType.contains('\n'))
- m_isValid = false;
- else
- m_isValid = parse(contentType.stripWhiteSpace());
+ParsedContentType::ParsedContentType(const String& contentType, Mode mode)
+ : m_mode(mode) {
+ m_isValid = parse(contentType);
}
String ParsedContentType::charset() const {
@@ -144,65 +219,52 @@ size_t ParsedContentType::parameterCount() const {
bool ParsedContentType::parse(const String& contentType) {
unsigned index = 0;
- unsigned contentTypeLength = contentType.length();
- skipSpaces(contentType, index);
- if (index >= contentTypeLength) {
- DVLOG(1) << "Invalid Content-Type string '" << contentType << "'";
+
+ StringView type, subtype;
+ if (!consumeToken(Mode::Normal, contentType, index, type)) {
+ DVLOG(1) << "Failed to find `type' in '" << contentType << "'";
return false;
}
-
- // There should not be any quoted strings until we reach the parameters.
- size_t semiColonIndex = contentType.find(';', index);
- if (semiColonIndex == kNotFound) {
- m_mimeType =
- substringForRange(contentType,
- SubstringRange(index, contentTypeLength - index))
- .stripWhiteSpace();
- return true;
+ if (!consume('/', contentType, index)) {
+ DVLOG(1) << "Failed to find '/' in '" << contentType << "'";
+ return false;
+ }
+ if (!consumeToken(Mode::Normal, contentType, index, subtype)) {
+ DVLOG(1) << "Failed to find `type' in '" << contentType << "'";
+ return false;
}
- m_mimeType = substringForRange(contentType,
- SubstringRange(index, semiColonIndex - index))
- .stripWhiteSpace();
- index = semiColonIndex + 1;
- do {
- skipSpaces(contentType, index);
- SubstringRange keyRange = parseParameterPart(contentType, index);
- if (!keyRange.second || index >= contentTypeLength) {
- DVLOG(1) << "Invalid Content-Type parameter name. (at " << index << ")";
+ StringBuilder builder;
+ builder.append(type);
+ builder.append('/');
+ builder.append(subtype);
+ m_mimeType = builder.toString();
+
+ KeyValuePairs map;
+ while (!isEnd(contentType, index)) {
+ if (!consume(';', contentType, index)) {
+ DVLOG(1) << "Failed to find ';'";
return false;
}
- // Should we tolerate spaces here?
- if (contentType[index++] != '=' || index >= contentTypeLength) {
- DVLOG(1) << "Invalid Content-Type malformed parameter (at " << index
- << ").";
+ StringView key;
+ String value;
+ if (!consumeToken(Mode::Normal, contentType, index, key)) {
+ DVLOG(1) << "Invalid Content-Type parameter name. (at " << index << ")";
return false;
}
-
- // Should we tolerate spaces here?
- SubstringRange valueRange = parseParameterPart(contentType, index);
-
- if (!valueRange.second) {
- DVLOG(1) << "Invalid Content-Type, invalid parameter value (at " << index
- << ", for '"
- << substringForRange(contentType, keyRange).stripWhiteSpace()
- << "').";
+ if (!consume('=', contentType, index)) {
+ DVLOG(1) << "Failed to find '='";
return false;
}
-
- // Should we tolerate spaces here?
- if (index < contentTypeLength && contentType[index++] != ';') {
- DVLOG(1) << "Invalid Content-Type, invalid character at the end of "
- "key/value parameter (at "
- << index << ").";
+ if (!consumeTokenOrQuotedString(m_mode, contentType, index, value)) {
+ DVLOG(1) << "Invalid Content-Type, invalid parameter value (at " << index
+ << ", for '" << key.toString() << "').";
return false;
}
-
- m_parameters.set(substringForRange(contentType, keyRange),
- substringForRange(contentType, valueRange));
- } while (index < contentTypeLength);
-
+ map.set(key.toString(), value);
+ }
+ m_parameters = std::move(map);
return true;
}

Powered by Google App Engine
This is Rietveld 408576698