// https://wicg.github.io/entries-api/#resolve-a-relative-path static String resolveRelativeVirtualPath(StringView baseVirtualPath, StringView relativeVirtualPath) { ASSERT(baseVirtualPath[0] == '/'); if (!relativeVirtualPath.isEmpty() && relativeVirtualPath[0] == '/') return relativeVirtualPath.length() == 1 ? relativeVirtualPath.toString() : resolveRelativeVirtualPath("/", relativeVirtualPath.substring(1)); Vector<StringView> virtualPathSegments; for (auto segment : baseVirtualPath.split('/')) virtualPathSegments.append(segment); for (auto segment : relativeVirtualPath.split('/')) { ASSERT(!segment.isEmpty()); if (segment == ".") continue; if (segment == "..") { if (!virtualPathSegments.isEmpty()) virtualPathSegments.removeLast(); continue; } virtualPathSegments.append(segment); } if (virtualPathSegments.isEmpty()) return "/"_s; StringBuilder builder; for (auto& segment : virtualPathSegments) { builder.append('/'); builder.append(segment); } return builder.toString(); }
size_t lastHyphenLocation(const StringView& text, size_t beforeIndex) const override { CFIndex result = CFStringGetHyphenationLocationBeforeIndex( text.toString().impl()->createCFString().get(), beforeIndex, CFRangeMake(0, text.length()), 0, m_localeCF.get(), 0); return result == kCFNotFound ? 0 : result; }
static void setWindowFeature(WindowFeatures& features, StringView key, StringView value) { // Listing a key with no value is shorthand for key=yes int numericValue; if (value.isEmpty() || equalLettersIgnoringASCIICase(value, "yes")) numericValue = 1; else numericValue = value.toInt(); // We treat key of "resizable" here as an additional feature rather than setting resizeable to true. // This is consistent with Firefox, but could also be handled at another level. if (equalLettersIgnoringASCIICase(key, "left") || equalLettersIgnoringASCIICase(key, "screenx")) features.x = numericValue; else if (equalLettersIgnoringASCIICase(key, "top") || equalLettersIgnoringASCIICase(key, "screeny")) features.y = numericValue; else if (equalLettersIgnoringASCIICase(key, "width") || equalLettersIgnoringASCIICase(key, "innerwidth")) features.width = numericValue; else if (equalLettersIgnoringASCIICase(key, "height") || equalLettersIgnoringASCIICase(key, "innerheight")) features.height = numericValue; else if (equalLettersIgnoringASCIICase(key, "menubar")) features.menuBarVisible = numericValue; else if (equalLettersIgnoringASCIICase(key, "toolbar")) features.toolBarVisible = numericValue; else if (equalLettersIgnoringASCIICase(key, "location")) features.locationBarVisible = numericValue; else if (equalLettersIgnoringASCIICase(key, "status")) features.statusBarVisible = numericValue; else if (equalLettersIgnoringASCIICase(key, "fullscreen")) features.fullscreen = numericValue; else if (equalLettersIgnoringASCIICase(key, "scrollbars")) features.scrollbarsVisible = numericValue; else if (numericValue == 1) features.additionalFeatures.append(key.toString()); }
size_t MockHyphenation::lastHyphenLocation(const StringView& text, size_t beforeIndex) const { String str = text.toString(); if (str.endsWith("phenation", TextCaseASCIIInsensitive)) { if (beforeIndex - (str.length() - 9) > 4) return 4 + (str.length() - 9); if (str.endsWith("hyphenation", TextCaseASCIIInsensitive) && beforeIndex - (str.length() - 11) > 2) { return 2 + (str.length() - 11); } } return 0; }
bool ScriptCustomElementDefinitionBuilder::callableForName( const StringView& name, v8::Local<v8::Function>& callback) const { v8::Local<v8::Value> value; if (!valueForName(m_prototype, name, value)) return false; // "undefined" means "omitted", so return true. if (value->IsUndefined()) return true; if (!value->IsFunction()) { m_exceptionState.throwTypeError(String::format( "\"%s\" is not a callable object", name.toString().ascii().data())); return false; } callback = value.As<v8::Function>(); return true; }
bool MultipartHandle::parseHeadersIfPossible() { size_t contentLength = m_buffer.size(); if (!contentLength) return false; const char* content = m_buffer.data(); // Check if we have the header closing strings. if (!strnstr(content, "\r\n\r\n", contentLength)) { // Some servers closes the headers with only \n-s. if (!strnstr(content, "\n\n", contentLength)) { // Don't have the header closing string. Wait for more data. return false; } } // Parse the HTTP headers. String value; StringView name; char* p = const_cast<char*>(content); const char* end = content + contentLength; size_t totalConsumedLength = 0; for (; p < end; ++p) { String failureReason; size_t consumedLength = parseHTTPHeader(p, end - p, failureReason, name, value, false); if (!consumedLength) break; // No more header to parse. p += consumedLength; totalConsumedLength += consumedLength; // The name should not be empty, but the value could be empty. if (name.isEmpty()) break; m_headers.add(name.toString(), value); } m_buffer.remove(0, totalConsumedLength + 1); return true; }
const char* WebSocketHandshake::readHTTPHeaders(const char* start, const char* end) { StringView name; String value; bool sawSecWebSocketExtensionsHeaderField = false; bool sawSecWebSocketAcceptHeaderField = false; bool sawSecWebSocketProtocolHeaderField = false; const char* p = start; for (; p < end; p++) { size_t consumedLength = parseHTTPHeader(p, end - p, m_failureReason, name, value); if (!consumedLength) return nullptr; p += consumedLength; // Stop once we consumed an empty line. if (name.isEmpty()) break; HTTPHeaderName headerName; if (!findHTTPHeaderName(name, headerName)) { // Evidence in the wild shows that services make use of custom headers in the handshake m_serverHandshakeResponse.addHTTPHeaderField(name.toString(), value); continue; } // https://tools.ietf.org/html/rfc7230#section-3.2.4 // "Newly defined header fields SHOULD limit their field values to US-ASCII octets." if ((headerName == HTTPHeaderName::SecWebSocketExtensions || headerName == HTTPHeaderName::SecWebSocketAccept || headerName == HTTPHeaderName::SecWebSocketProtocol) && !value.containsOnlyASCII()) { m_failureReason = makeString(name, " header value should only contain ASCII characters"); return nullptr; } if (headerName == HTTPHeaderName::SecWebSocketExtensions) { if (sawSecWebSocketExtensionsHeaderField) { m_failureReason = ASCIILiteral("The Sec-WebSocket-Extensions header must not appear more than once in an HTTP response"); return nullptr; } if (!m_extensionDispatcher.processHeaderValue(value)) { m_failureReason = m_extensionDispatcher.failureReason(); return nullptr; } sawSecWebSocketExtensionsHeaderField = true; } else { if (headerName == HTTPHeaderName::SecWebSocketAccept) { if (sawSecWebSocketAcceptHeaderField) { m_failureReason = ASCIILiteral("The Sec-WebSocket-Accept header must not appear more than once in an HTTP response"); return nullptr; } sawSecWebSocketAcceptHeaderField = true; } else if (headerName == HTTPHeaderName::SecWebSocketProtocol) { if (sawSecWebSocketProtocolHeaderField) { m_failureReason = ASCIILiteral("The Sec-WebSocket-Protocol header must not appear more than once in an HTTP response"); return nullptr; } sawSecWebSocketProtocolHeaderField = true; } m_serverHandshakeResponse.addHTTPHeaderField(headerName, value); } } return p; }