Chromium Code Reviews| OLD | NEW |
|---|---|
| 1 /* | 1 /* |
| 2 * Copyright (C) 2007 Apple Inc. All rights reserved. | 2 * Copyright (C) 2007 Apple 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 | 5 * modification, are permitted provided that the following conditions |
| 6 * are met: | 6 * are met: |
| 7 * | 7 * |
| 8 * 1. Redistributions of source code must retain the above copyright | 8 * 1. 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 * 2. Redistributions in binary form must reproduce the above copyright | 10 * 2. Redistributions in binary form must reproduce the above copyright |
| (...skipping 19 matching lines...) Expand all Loading... | |
| 30 #include "platform/weborigin/SecurityOrigin.h" | 30 #include "platform/weborigin/SecurityOrigin.h" |
| 31 | 31 |
| 32 #include "platform/weborigin/KURL.h" | 32 #include "platform/weborigin/KURL.h" |
| 33 #include "platform/weborigin/KnownPorts.h" | 33 #include "platform/weborigin/KnownPorts.h" |
| 34 #include "platform/weborigin/SchemeRegistry.h" | 34 #include "platform/weborigin/SchemeRegistry.h" |
| 35 #include "platform/weborigin/SecurityOriginCache.h" | 35 #include "platform/weborigin/SecurityOriginCache.h" |
| 36 #include "platform/weborigin/SecurityPolicy.h" | 36 #include "platform/weborigin/SecurityPolicy.h" |
| 37 #include "url/url_canon_ip.h" | 37 #include "url/url_canon_ip.h" |
| 38 #include "wtf/HexNumber.h" | 38 #include "wtf/HexNumber.h" |
| 39 #include "wtf/MainThread.h" | 39 #include "wtf/MainThread.h" |
| 40 #include "wtf/NotFound.h" | |
| 40 #include "wtf/StdLibExtras.h" | 41 #include "wtf/StdLibExtras.h" |
| 41 #include "wtf/text/StringBuilder.h" | 42 #include "wtf/text/StringBuilder.h" |
| 42 | 43 |
| 43 namespace blink { | 44 namespace blink { |
| 44 | 45 |
| 45 const int InvalidPort = 0; | 46 const int InvalidPort = 0; |
| 46 const int MaxAllowedPort = 65535; | 47 const int MaxAllowedPort = 65535; |
| 47 | 48 |
| 48 static SecurityOriginCache* s_originCache = 0; | 49 static SecurityOriginCache* s_originCache = 0; |
| 49 | 50 |
| 50 static bool schemeRequiresAuthority(const KURL& url) | 51 static bool schemeRequiresAuthority(const KURL& url) |
| 51 { | 52 { |
| 52 // We expect URLs with these schemes to have authority components. If the | 53 // We expect URLs with these schemes to have authority components. If the |
| 53 // URL lacks an authority component, we get concerned and mark the origin | 54 // URL lacks an authority component, we get concerned and mark the origin |
| 54 // as unique. | 55 // as unique. |
| 55 return url.protocolIsInHTTPFamily() || url.protocolIs("ftp"); | 56 return url.protocolIsInHTTPFamily() || url.protocolIs("ftp"); |
| 56 } | 57 } |
| 57 | 58 |
| 58 static SecurityOrigin* cachedOrigin(const KURL& url) | 59 static SecurityOrigin* cachedOrigin(const KURL& url) |
| 59 { | 60 { |
| 60 if (s_originCache) | 61 if (s_originCache) |
| 61 return s_originCache->cachedOrigin(url); | 62 return s_originCache->cachedOrigin(url); |
| 62 return 0; | 63 return 0; |
| 63 } | 64 } |
| 64 | 65 |
| 66 static bool sameSuborigin(const SecurityOrigin* origin1, const SecurityOrigin* o rigin2) | |
| 67 { | |
| 68 // If either origin has a suborigin set, both must have the same suborigin. | |
| 69 return origin1->suboriginName() == origin2->suboriginName(); | |
| 70 } | |
| 71 | |
| 65 bool SecurityOrigin::shouldUseInnerURL(const KURL& url) | 72 bool SecurityOrigin::shouldUseInnerURL(const KURL& url) |
| 66 { | 73 { |
| 67 // FIXME: Blob URLs don't have inner URLs. Their form is "blob:<inner-origin >/<UUID>", so treating the part after "blob:" as a URL is incorrect. | 74 // FIXME: Blob URLs don't have inner URLs. Their form is "blob:<inner-origin >/<UUID>", so treating the part after "blob:" as a URL is incorrect. |
| 68 if (url.protocolIs("blob")) | 75 if (url.protocolIs("blob")) |
| 69 return true; | 76 return true; |
| 70 if (url.protocolIs("filesystem")) | 77 if (url.protocolIs("filesystem")) |
| 71 return true; | 78 return true; |
| 72 return false; | 79 return false; |
| 73 } | 80 } |
| 74 | 81 |
| (...skipping 34 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 109 // that assume the scheme has already been canonicalized. | 116 // that assume the scheme has already been canonicalized. |
| 110 String protocol = innerURL.protocol().lower(); | 117 String protocol = innerURL.protocol().lower(); |
| 111 | 118 |
| 112 if (SchemeRegistry::shouldTreatURLSchemeAsNoAccess(protocol)) | 119 if (SchemeRegistry::shouldTreatURLSchemeAsNoAccess(protocol)) |
| 113 return true; | 120 return true; |
| 114 | 121 |
| 115 // This is the common case. | 122 // This is the common case. |
| 116 return false; | 123 return false; |
| 117 } | 124 } |
| 118 | 125 |
| 126 bool deserializeSuboriginAndProtocol(const String& oldProtocol, String& suborigi nName, String& newProtocol) | |
| 127 { | |
| 128 const char suboriginPrefix[] = "suborigin+"; | |
| 129 if (!oldProtocol.startsWith(suboriginPrefix)) | |
| 130 return false; | |
| 131 | |
| 132 size_t suboriginStart = strlen(suboriginPrefix); | |
| 133 size_t protocolStart = oldProtocol.find('+', suboriginStart + 1); | |
| 134 | |
| 135 if (protocolStart == kNotFound) | |
| 136 return false; | |
| 137 | |
| 138 suboriginName = oldProtocol.substring(suboriginStart, protocolStart - subori ginStart); | |
| 139 newProtocol = oldProtocol.substring(protocolStart + 1); | |
| 140 | |
|
Mike West
2015/03/23 07:32:56
ASSERT that the runtime-enabled feature is enabled
jww
2015/04/11 02:52:36
I instead put a check at the top to make sure we o
| |
| 141 return true; | |
| 142 } | |
| 143 | |
| 119 SecurityOrigin::SecurityOrigin(const KURL& url) | 144 SecurityOrigin::SecurityOrigin(const KURL& url) |
| 120 : m_protocol(url.protocol().isNull() ? "" : url.protocol().lower()) | 145 : m_protocol(url.protocol().isNull() ? "" : url.protocol().lower()) |
| 121 , m_host(url.host().isNull() ? "" : url.host().lower()) | 146 , m_host(url.host().isNull() ? "" : url.host().lower()) |
| 122 , m_port(url.port()) | 147 , m_port(url.port()) |
| 123 , m_isUnique(false) | 148 , m_isUnique(false) |
| 124 , m_universalAccess(false) | 149 , m_universalAccess(false) |
| 125 , m_domainWasSetInDOM(false) | 150 , m_domainWasSetInDOM(false) |
| 126 , m_enforceFilePathSeparation(false) | 151 , m_enforceFilePathSeparation(false) |
| 127 , m_needsDatabaseIdentifierQuirkForFiles(false) | 152 , m_needsDatabaseIdentifierQuirkForFiles(false) |
| 128 { | 153 { |
| 154 // Suborigins are serialized into the protocol, so extract it if necessary. | |
| 155 String suboriginName; | |
| 156 if (deserializeSuboriginAndProtocol(m_protocol, suboriginName, m_protocol)) | |
|
Mike West
2015/03/23 07:32:55
A side-effect of lumping the suborigin into the pr
jww
2015/04/25 00:41:22
Agreed. For this original implementation, my idea
| |
| 157 addSuborigin(suboriginName); | |
| 158 | |
| 129 // document.domain starts as m_host, but can be set by the DOM. | 159 // document.domain starts as m_host, but can be set by the DOM. |
| 130 m_domain = m_host; | 160 m_domain = m_host; |
| 131 | 161 |
| 132 if (isDefaultPortForProtocol(m_port, m_protocol)) | 162 if (isDefaultPortForProtocol(m_port, m_protocol)) |
| 133 m_port = InvalidPort; | 163 m_port = InvalidPort; |
| 134 | 164 |
| 135 // By default, only local SecurityOrigins can load local resources. | 165 // By default, only local SecurityOrigins can load local resources. |
| 136 m_canLoadLocalResources = isLocal(); | 166 m_canLoadLocalResources = isLocal(); |
| 137 | 167 |
| 138 if (m_canLoadLocalResources) | 168 if (m_canLoadLocalResources) |
| (...skipping 12 matching lines...) Expand all Loading... | |
| 151 , m_enforceFilePathSeparation(false) | 181 , m_enforceFilePathSeparation(false) |
| 152 , m_needsDatabaseIdentifierQuirkForFiles(false) | 182 , m_needsDatabaseIdentifierQuirkForFiles(false) |
| 153 { | 183 { |
| 154 } | 184 } |
| 155 | 185 |
| 156 SecurityOrigin::SecurityOrigin(const SecurityOrigin* other) | 186 SecurityOrigin::SecurityOrigin(const SecurityOrigin* other) |
| 157 : m_protocol(other->m_protocol.isolatedCopy()) | 187 : m_protocol(other->m_protocol.isolatedCopy()) |
| 158 , m_host(other->m_host.isolatedCopy()) | 188 , m_host(other->m_host.isolatedCopy()) |
| 159 , m_domain(other->m_domain.isolatedCopy()) | 189 , m_domain(other->m_domain.isolatedCopy()) |
| 160 , m_filePath(other->m_filePath.isolatedCopy()) | 190 , m_filePath(other->m_filePath.isolatedCopy()) |
| 191 , m_suboriginName(other->m_suboriginName) | |
| 161 , m_port(other->m_port) | 192 , m_port(other->m_port) |
| 162 , m_isUnique(other->m_isUnique) | 193 , m_isUnique(other->m_isUnique) |
| 163 , m_universalAccess(other->m_universalAccess) | 194 , m_universalAccess(other->m_universalAccess) |
| 164 , m_domainWasSetInDOM(other->m_domainWasSetInDOM) | 195 , m_domainWasSetInDOM(other->m_domainWasSetInDOM) |
| 165 , m_canLoadLocalResources(other->m_canLoadLocalResources) | 196 , m_canLoadLocalResources(other->m_canLoadLocalResources) |
| 166 , m_enforceFilePathSeparation(other->m_enforceFilePathSeparation) | 197 , m_enforceFilePathSeparation(other->m_enforceFilePathSeparation) |
| 167 , m_needsDatabaseIdentifierQuirkForFiles(other->m_needsDatabaseIdentifierQui rkForFiles) | 198 , m_needsDatabaseIdentifierQuirkForFiles(other->m_needsDatabaseIdentifierQui rkForFiles) |
| 168 { | 199 { |
| 169 } | 200 } |
| 170 | 201 |
| (...skipping 22 matching lines...) Expand all Loading... | |
| 193 return adoptRef(new SecurityOrigin(url)); | 224 return adoptRef(new SecurityOrigin(url)); |
| 194 } | 225 } |
| 195 | 226 |
| 196 PassRefPtr<SecurityOrigin> SecurityOrigin::createUnique() | 227 PassRefPtr<SecurityOrigin> SecurityOrigin::createUnique() |
| 197 { | 228 { |
| 198 RefPtr<SecurityOrigin> origin = adoptRef(new SecurityOrigin()); | 229 RefPtr<SecurityOrigin> origin = adoptRef(new SecurityOrigin()); |
| 199 ASSERT(origin->isUnique()); | 230 ASSERT(origin->isUnique()); |
| 200 return origin.release(); | 231 return origin.release(); |
| 201 } | 232 } |
| 202 | 233 |
| 234 void SecurityOrigin::addSuborigin(const String& suborigin) | |
| 235 { | |
| 236 // Changing suborigins midstream is bad. Very bad. It should not happen. | |
| 237 // This is, in fact, one of the very basic invariants that makes suborigins | |
| 238 // an effective security tool. | |
|
Mike West
2015/03/23 07:32:56
ASSERT that the runtime-enabled feature is enabled
jww
2015/04/11 02:52:36
Done.
| |
| 239 RELEASE_ASSERT(m_suboriginName.isNull() || m_suboriginName == suborigin); | |
|
Mike West
2015/03/23 07:32:55
When would the suborigin be set to itself? Could w
jww
2015/04/11 02:52:36
There are some cases, I believe during script exec
| |
| 240 m_suboriginName = suborigin; | |
|
Mike West
2015/03/23 07:32:55
Please add unit tests for this change. You can ver
jww
2015/04/11 02:52:36
Done.
| |
| 241 } | |
| 242 | |
| 203 PassRefPtr<SecurityOrigin> SecurityOrigin::isolatedCopy() const | 243 PassRefPtr<SecurityOrigin> SecurityOrigin::isolatedCopy() const |
| 204 { | 244 { |
| 205 return adoptRef(new SecurityOrigin(this)); | 245 return adoptRef(new SecurityOrigin(this)); |
| 206 } | 246 } |
| 207 | 247 |
| 208 void SecurityOrigin::setDomainFromDOM(const String& newDomain) | 248 void SecurityOrigin::setDomainFromDOM(const String& newDomain) |
| 209 { | 249 { |
| 210 m_domainWasSetInDOM = true; | 250 m_domainWasSetInDOM = true; |
| 211 m_domain = newDomain.lower(); | 251 m_domain = newDomain.lower(); |
| 212 } | 252 } |
| (...skipping 15 matching lines...) Expand all Loading... | |
| 228 { | 268 { |
| 229 if (m_universalAccess) | 269 if (m_universalAccess) |
| 230 return true; | 270 return true; |
| 231 | 271 |
| 232 if (this == other) | 272 if (this == other) |
| 233 return true; | 273 return true; |
| 234 | 274 |
| 235 if (isUnique() || other->isUnique()) | 275 if (isUnique() || other->isUnique()) |
| 236 return false; | 276 return false; |
| 237 | 277 |
| 278 if (!sameSuborigin(this, other)) | |
| 279 return false; | |
|
Mike West
2015/03/23 07:32:56
Please add unit tests for this change.
jww
2015/04/11 02:52:36
Done.
| |
| 280 | |
| 238 // Here are two cases where we should permit access: | 281 // Here are two cases where we should permit access: |
| 239 // | 282 // |
| 240 // 1) Neither document has set document.domain. In this case, we insist | 283 // 1) Neither document has set document.domain. In this case, we insist |
| 241 // that the scheme, host, and port of the URLs match. | 284 // that the scheme, host, and port of the URLs match. |
| 242 // | 285 // |
| 243 // 2) Both documents have set document.domain. In this case, we insist | 286 // 2) Both documents have set document.domain. In this case, we insist |
| 244 // that the documents have set document.domain to the same value and | 287 // that the documents have set document.domain to the same value and |
| 245 // that the scheme of the URLs match. | 288 // that the scheme of the URLs match. |
| 246 // | 289 // |
| 247 // This matches the behavior of Firefox 2 and Internet Explorer 6. | 290 // This matches the behavior of Firefox 2 and Internet Explorer 6. |
| (...skipping 43 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 291 return true; | 334 return true; |
| 292 | 335 |
| 293 if (isUnique()) | 336 if (isUnique()) |
| 294 return false; | 337 return false; |
| 295 | 338 |
| 296 RefPtr<SecurityOrigin> targetOrigin = SecurityOrigin::create(url); | 339 RefPtr<SecurityOrigin> targetOrigin = SecurityOrigin::create(url); |
| 297 | 340 |
| 298 if (targetOrigin->isUnique()) | 341 if (targetOrigin->isUnique()) |
| 299 return false; | 342 return false; |
| 300 | 343 |
| 344 if (!sameSuborigin(this, targetOrigin.get())) | |
|
Mike West
2015/03/23 07:32:55
Please add unit tests for this change.
It seems l
jww
2015/04/11 02:52:36
Added.
| |
| 345 return false; | |
| 346 | |
| 301 // We call isSameSchemeHostPort here instead of canAccess because we want | 347 // We call isSameSchemeHostPort here instead of canAccess because we want |
| 302 // to ignore document.domain effects. | 348 // to ignore document.domain effects. |
| 303 if (isSameSchemeHostPort(targetOrigin.get())) | 349 if (isSameSchemeHostPort(targetOrigin.get())) |
| 304 return true; | 350 return true; |
| 305 | 351 |
| 306 if (SecurityPolicy::isAccessWhiteListed(this, targetOrigin.get())) | 352 if (SecurityPolicy::isAccessWhiteListed(this, targetOrigin.get())) |
| 307 return true; | 353 return true; |
| 308 | 354 |
| 309 return false; | 355 return false; |
| 310 } | 356 } |
| (...skipping 74 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 385 errorMessage = "Only secure origins are allowed. http://goo.gl/lq4gCo"; | 431 errorMessage = "Only secure origins are allowed. http://goo.gl/lq4gCo"; |
| 386 return false; | 432 return false; |
| 387 } | 433 } |
| 388 | 434 |
| 389 SecurityOrigin::Policy SecurityOrigin::canShowNotifications() const | 435 SecurityOrigin::Policy SecurityOrigin::canShowNotifications() const |
| 390 { | 436 { |
| 391 if (m_universalAccess) | 437 if (m_universalAccess) |
| 392 return AlwaysAllow; | 438 return AlwaysAllow; |
| 393 if (isUnique()) | 439 if (isUnique()) |
| 394 return AlwaysDeny; | 440 return AlwaysDeny; |
| 441 if (hasSuborigin()) | |
| 442 return AlwaysDeny; | |
|
Mike West
2015/03/23 07:32:55
There's no test for this behavioral change. Please
jww
2015/04/11 02:52:36
Done.
| |
| 395 return Ask; | 443 return Ask; |
| 396 } | 444 } |
| 397 | 445 |
| 398 void SecurityOrigin::grantLoadLocalResources() | 446 void SecurityOrigin::grantLoadLocalResources() |
| 399 { | 447 { |
| 400 // Granting privileges to some, but not all, documents in a SecurityOrigin | 448 // Granting privileges to some, but not all, documents in a SecurityOrigin |
| 401 // is a security hazard because the documents without the privilege can | 449 // is a security hazard because the documents without the privilege can |
| 402 // obtain the privilege by injecting script into the documents that have | 450 // obtain the privilege by injecting script into the documents that have |
| 403 // been granted the privilege. | 451 // been granted the privilege. |
| 404 m_canLoadLocalResources = true; | 452 m_canLoadLocalResources = true; |
| (...skipping 69 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 474 AtomicString SecurityOrigin::toRawAtomicString() const | 522 AtomicString SecurityOrigin::toRawAtomicString() const |
| 475 { | 523 { |
| 476 if (m_protocol == "file") | 524 if (m_protocol == "file") |
| 477 return AtomicString("file://", AtomicString::ConstructFromLiteral); | 525 return AtomicString("file://", AtomicString::ConstructFromLiteral); |
| 478 | 526 |
| 479 StringBuilder result; | 527 StringBuilder result; |
| 480 buildRawString(result); | 528 buildRawString(result); |
| 481 return result.toAtomicString(); | 529 return result.toAtomicString(); |
| 482 } | 530 } |
| 483 | 531 |
| 484 inline void SecurityOrigin::buildRawString(StringBuilder& builder) const | 532 inline void SecurityOrigin::buildRawString(StringBuilder& builder) const |
|
Mike West
2015/03/23 07:32:55
Please add unit tests for the new behavior here.
| |
| 485 { | 533 { |
| 486 builder.reserveCapacity(m_protocol.length() + m_host.length() + 10); | 534 if (hasSuborigin()) { |
| 535 builder.reserveCapacity(11 + m_suboriginName.length() + m_protocol.lengt h() + m_host.length() + 10); | |
| 536 builder.appendLiteral("suborigin+"); | |
| 537 builder.append(m_suboriginName); | |
| 538 builder.append('+'); | |
|
Mike West
2015/03/23 07:32:55
This is very strange syntax.
jww
2015/04/11 02:52:36
Initially I went with ':', but this causes all sor
| |
| 539 } else { | |
| 540 builder.reserveCapacity(m_protocol.length() + m_host.length() + 10); | |
| 541 } | |
| 487 builder.append(m_protocol); | 542 builder.append(m_protocol); |
| 488 builder.appendLiteral("://"); | 543 builder.appendLiteral("://"); |
| 489 builder.append(m_host); | 544 builder.append(m_host); |
| 490 | 545 |
| 491 if (m_port) { | 546 if (m_port) { |
| 492 builder.append(':'); | 547 builder.append(':'); |
| 493 builder.appendNumber(m_port); | 548 builder.appendNumber(m_port); |
| 494 } | 549 } |
| 495 } | 550 } |
| 496 | 551 |
| 497 PassRefPtr<SecurityOrigin> SecurityOrigin::createFromString(const String& origin String) | 552 PassRefPtr<SecurityOrigin> SecurityOrigin::createFromString(const String& origin String) |
| 498 { | 553 { |
| 499 return SecurityOrigin::create(KURL(KURL(), originString)); | 554 return SecurityOrigin::create(KURL(KURL(), originString)); |
| 500 } | 555 } |
| 501 | 556 |
| 502 PassRefPtr<SecurityOrigin> SecurityOrigin::create(const String& protocol, const String& host, int port) | 557 PassRefPtr<SecurityOrigin> SecurityOrigin::create(const String& protocol, const String& host, int port) |
| 503 { | 558 { |
| 504 if (port < 0 || port > MaxAllowedPort) | 559 if (port < 0 || port > MaxAllowedPort) |
| 505 return createUnique(); | 560 return createUnique(); |
| 506 String decodedHost = decodeURLEscapeSequences(host); | 561 String decodedHost = decodeURLEscapeSequences(host); |
| 507 return create(KURL(KURL(), protocol + "://" + host + ":" + String::number(po rt) + "/")); | 562 return create(KURL(KURL(), protocol + "://" + host + ":" + String::number(po rt) + "/")); |
| 508 } | 563 } |
| 509 | 564 |
| 510 bool SecurityOrigin::isSameSchemeHostPort(const SecurityOrigin* other) const | 565 bool SecurityOrigin::isSameSchemeHostPort(const SecurityOrigin* other) const |
| 511 { | 566 { |
| 567 if (!sameSuborigin(this, other)) | |
|
Mike West
2015/03/23 07:32:55
Do we always want the suborigin check when doing a
jww
2015/04/11 02:52:36
Even while it's experimental? It won't be a subori
| |
| 568 return false; | |
| 569 | |
| 512 if (m_host != other->m_host) | 570 if (m_host != other->m_host) |
| 513 return false; | 571 return false; |
| 514 | 572 |
| 515 if (m_protocol != other->m_protocol) | 573 if (m_protocol != other->m_protocol) |
| 516 return false; | 574 return false; |
| 517 | 575 |
| 518 if (m_port != other->m_port) | 576 if (m_port != other->m_port) |
| 519 return false; | 577 return false; |
| 520 | 578 |
| 521 if (isLocal() && !passesFileCheck(other)) | 579 if (isLocal() && !passesFileCheck(other)) |
| (...skipping 10 matching lines...) Expand all Loading... | |
| 532 } | 590 } |
| 533 | 591 |
| 534 void SecurityOrigin::transferPrivilegesFrom(const SecurityOrigin& origin) | 592 void SecurityOrigin::transferPrivilegesFrom(const SecurityOrigin& origin) |
| 535 { | 593 { |
| 536 m_universalAccess = origin.m_universalAccess; | 594 m_universalAccess = origin.m_universalAccess; |
| 537 m_canLoadLocalResources = origin.m_canLoadLocalResources; | 595 m_canLoadLocalResources = origin.m_canLoadLocalResources; |
| 538 m_enforceFilePathSeparation = origin.m_enforceFilePathSeparation; | 596 m_enforceFilePathSeparation = origin.m_enforceFilePathSeparation; |
| 539 } | 597 } |
| 540 | 598 |
| 541 } // namespace blink | 599 } // namespace blink |
| OLD | NEW |