Changeset 220315 in webkit
- Timestamp:
- Aug 5, 2017 2:27:15 AM (7 years ago)
- Location:
- trunk/Source/WebDriver
- Files:
-
- 7 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/Source/WebDriver/Capabilities.h
r219605 r220315 27 27 28 28 #include <wtf/Forward.h> 29 #include <wtf/Seconds.h> 29 30 #include <wtf/Vector.h> 30 31 #include <wtf/text/WTFString.h> … … 32 33 namespace WebDriver { 33 34 35 struct Timeouts { 36 std::optional<Seconds> script; 37 std::optional<Seconds> pageLoad; 38 std::optional<Seconds> implicit; 39 }; 40 34 41 struct Capabilities { 35 String browserName; 36 String browserVersion; 37 String platform; 42 std::optional<String> browserName; 43 std::optional<String> browserVersion; 44 std::optional<String> platformName; 45 std::optional<bool> acceptInsecureCerts; 46 std::optional<Timeouts> timeouts; 38 47 #if PLATFORM(GTK) 39 StringbrowserBinary;40 Vector<String> browserArguments;41 bool useOverlayScrollbars { true };48 std::optional<String> browserBinary; 49 std::optional<Vector<String>> browserArguments; 50 std::optional<bool> useOverlayScrollbars; 42 51 #endif 43 52 }; -
trunk/Source/WebDriver/ChangeLog
r220314 r220315 1 2017-08-05 Carlos Garcia Campos <cgarcia@igalia.com> 2 3 WebDriver: properly handle capabilities and process firstMatch too 4 https://bugs.webkit.org/show_bug.cgi?id=174618 5 6 Reviewed by Brian Burg. 7 8 Implement processing of capabilities following the spec. This patch adds validation, merging and matching of 9 capabilities. 10 11 7.2 Processing Capabilities. 12 https://w3c.github.io/webdriver/webdriver-spec.html#processing-capabilities 13 14 * Capabilities.h: Make all capabilities optional and move Timeouts struct here. 15 * Session.h: 16 * WebDriverService.cpp: 17 (WebDriver::deserializeTimeouts): Helper to extract timeouts from JSON object. 18 (WebDriver::WebDriverService::parseCapabilities const): At this point capabilities have already been validated, 19 so we just need to get them without checking the value type. 20 (WebDriver::WebDriverService::validatedCapabilities const): Validate the given capabilities, ensuring types of 21 values are the expected one. 22 (WebDriver::WebDriverService::mergeCapabilities const): Merge the alwaysMatch and firstMatch capabilities into a 23 single object ensuring that the same capability is not in both. 24 (WebDriver::WebDriverService::matchCapabilities const): Try to match the merged capabilities againt the platform 25 expected capabilities. 26 (WebDriver::WebDriverService::processCapabilities const): Validate, merge and match the capabilities. 27 (WebDriver::WebDriverService::newSession): Use processCapabilities(). Also initialize the timeouts from 28 capabilities and add all capabilities to the command result. 29 (WebDriver::WebDriverService::setTimeouts): Use deserializeTimeouts(). 30 * WebDriverService.h: 31 * glib/SessionHostGlib.cpp: 32 (WebDriver::SessionHost::launchBrowser): Updated to properly access the capabilities that are now optional. 33 (WebDriver::SessionHost::startAutomationSession): Add FIXME. 34 * gtk/WebDriverServiceGtk.cpp: 35 (WebDriver::WebDriverService::platformCapabilities): Return the Capabilities with the known required ones filled. 36 (WebDriver::WebDriverService::platformValidateCapability const): Validate webkitgtk:browserOptions. 37 (WebDriver::WebDriverService::platformMatchCapability const): This does nothing for now. 38 (WebDriver::WebDriverService::platformCompareBrowserVersions): Compare the given browser versions. 39 (WebDriver::WebDriverService::platformParseCapabilities const): Updated now that capabilites have already been 40 validated before. 41 1 42 2017-08-05 Carlos Garcia Campos <cgarcia@igalia.com> 2 43 -
trunk/Source/WebDriver/Session.h
r220314 r220315 26 26 #pragma once 27 27 28 #include "Capabilities.h" 28 29 #include <wtf/Forward.h> 29 30 #include <wtf/Function.h> 30 31 #include <wtf/OptionSet.h> 31 32 #include <wtf/RefCounted.h> 32 #include <wtf/Seconds.h>33 33 #include <wtf/Vector.h> 34 34 #include <wtf/text/WTFString.h> … … 42 42 namespace WebDriver { 43 43 44 class Capabilities;45 44 class CommandResult; 46 45 class SessionHost; … … 60 59 enum class ExecuteScriptMode { Sync, Async }; 61 60 enum class Timeout { Script, PageLoad, Implicit }; 62 63 struct Timeouts {64 std::optional<Seconds> script;65 std::optional<Seconds> pageLoad;66 std::optional<Seconds> implicit;67 };68 61 69 62 void waitForNavigationToComplete(Function<void (CommandResult&&)>&&); -
trunk/Source/WebDriver/WebDriverService.cpp
r219794 r220315 252 252 } 253 253 254 bool WebDriverService::parseCapabilities(InspectorObject& desiredCapabilities, Capabilities& capabilities, Function<void (CommandResult&&)>& completionHandler) 255 { 256 RefPtr<InspectorValue> value; 257 if (desiredCapabilities.getValue(ASCIILiteral("browserName"), value) && !value->asString(capabilities.browserName)) { 258 completionHandler(CommandResult::fail(CommandResult::ErrorCode::SessionNotCreated, String("browserName parameter is invalid in capabilities"))); 259 return false; 260 } 261 if (desiredCapabilities.getValue(ASCIILiteral("version"), value) && !value->asString(capabilities.browserVersion)) { 262 completionHandler(CommandResult::fail(CommandResult::ErrorCode::SessionNotCreated, String("version parameter is invalid in capabilities"))); 263 return false; 264 } 265 if (desiredCapabilities.getValue(ASCIILiteral("platform"), value) && !value->asString(capabilities.platform)) { 266 completionHandler(CommandResult::fail(CommandResult::ErrorCode::SessionNotCreated, String("platform parameter is invalid in capabilities"))); 267 return false; 268 } 269 // FIXME: parse all other well-known capabilities: acceptInsecureCerts, pageLoadStrategy, proxy, setWindowRect, timeouts, unhandledPromptBehavior. 270 return platformParseCapabilities(desiredCapabilities, capabilities, completionHandler); 271 } 272 273 RefPtr<Session> WebDriverService::findSessionOrCompleteWithError(InspectorObject& parameters, Function<void (CommandResult&&)>& completionHandler) 274 { 275 String sessionID; 276 if (!parameters.getString(ASCIILiteral("sessionId"), sessionID)) { 277 completionHandler(CommandResult::fail(CommandResult::ErrorCode::InvalidArgument)); 278 return nullptr; 279 } 280 281 auto session = m_sessions.get(sessionID); 282 if (!session) { 283 completionHandler(CommandResult::fail(CommandResult::ErrorCode::InvalidSessionID)); 284 return nullptr; 285 } 286 287 return session; 288 } 289 290 void WebDriverService::newSession(RefPtr<InspectorObject>&& parameters, Function<void (CommandResult&&)>&& completionHandler) 291 { 292 // §8.1 New Session. 293 // https://www.w3.org/TR/webdriver/#new-session 294 RefPtr<InspectorObject> capabilitiesObject; 295 if (!parameters->getObject(ASCIILiteral("capabilities"), capabilitiesObject)) { 296 completionHandler(CommandResult::fail(CommandResult::ErrorCode::SessionNotCreated)); 297 return; 298 } 299 RefPtr<InspectorValue> requiredCapabilitiesValue; 300 RefPtr<InspectorObject> requiredCapabilities; 301 if (!capabilitiesObject->getValue(ASCIILiteral("alwaysMatch"), requiredCapabilitiesValue)) 302 requiredCapabilities = InspectorObject::create(); 303 else if (!requiredCapabilitiesValue->asObject(requiredCapabilities)) { 304 completionHandler(CommandResult::fail(CommandResult::ErrorCode::SessionNotCreated, String("alwaysMatch is invalid in capabilities"))); 305 return; 306 } 307 // FIXME: process firstMatch capabilities. 308 309 Capabilities capabilities; 310 if (!parseCapabilities(*requiredCapabilities, capabilities, completionHandler)) 311 return; 312 313 auto sessionHost = std::make_unique<SessionHost>(WTFMove(capabilities)); 314 auto* sessionHostPtr = sessionHost.get(); 315 sessionHostPtr->connectToBrowser([this, sessionHost = WTFMove(sessionHost), completionHandler = WTFMove(completionHandler)](SessionHost::Succeeded succeeded) mutable { 316 if (succeeded == SessionHost::Succeeded::No) { 317 completionHandler(CommandResult::fail(CommandResult::ErrorCode::SessionNotCreated, String("Failed to connect to browser"))); 318 return; 319 } 320 321 RefPtr<Session> session = Session::create(WTFMove(sessionHost)); 322 session->createTopLevelBrowsingContext([this, session, completionHandler = WTFMove(completionHandler)](CommandResult&& result) mutable { 323 if (result.isError()) { 324 completionHandler(CommandResult::fail(CommandResult::ErrorCode::SessionNotCreated, result.errorString())); 325 return; 326 } 327 328 m_activeSession = session.get(); 329 m_sessions.add(session->id(), session); 330 RefPtr<InspectorObject> resultObject = InspectorObject::create(); 331 resultObject->setString(ASCIILiteral("sessionId"), session->id()); 332 RefPtr<InspectorObject> capabilities = InspectorObject::create(); 333 capabilities->setString(ASCIILiteral("browserName"), session->capabilities().browserName); 334 capabilities->setString(ASCIILiteral("version"), session->capabilities().browserVersion); 335 capabilities->setString(ASCIILiteral("platform"), session->capabilities().platform); 336 resultObject->setObject(ASCIILiteral("value"), WTFMove(capabilities)); 337 completionHandler(CommandResult::success(WTFMove(resultObject))); 338 }); 339 }); 340 } 341 342 void WebDriverService::deleteSession(RefPtr<InspectorObject>&& parameters, Function<void (CommandResult&&)>&& completionHandler) 343 { 344 // §8.2 Delete Session. 345 // https://www.w3.org/TR/webdriver/#delete-session 346 String sessionID; 347 if (!parameters->getString(ASCIILiteral("sessionId"), sessionID)) { 348 completionHandler(CommandResult::fail(CommandResult::ErrorCode::InvalidArgument)); 349 return; 350 } 351 352 auto session = m_sessions.take(sessionID); 353 if (!session) { 354 completionHandler(CommandResult::fail(CommandResult::ErrorCode::InvalidSessionID)); 355 return; 356 } 357 358 if (m_activeSession == session.get()) 359 m_activeSession = nullptr; 360 361 session->close(WTFMove(completionHandler)); 362 } 363 364 void WebDriverService::setTimeouts(RefPtr<InspectorObject>&& parameters, Function<void (CommandResult&&)>&& completionHandler) 254 static std::optional<Timeouts> deserializeTimeouts(InspectorObject& timeoutsObject) 365 255 { 366 256 // §8.5 Set Timeouts. 367 // https://www.w3.org/TR/webdriver/#set-timeouts 368 auto session = findSessionOrCompleteWithError(*parameters, completionHandler); 369 if (!session) 370 return; 371 372 Session::Timeouts timeouts; 373 auto end = parameters->end(); 374 for (auto it = parameters->begin(); it != end; ++it) { 257 // https://w3c.github.io/webdriver/webdriver-spec.html#dfn-deserialize-as-a-timeout 258 Timeouts timeouts; 259 auto end = timeoutsObject.end(); 260 for (auto it = timeoutsObject.begin(); it != end; ++it) { 375 261 if (it->key == "sessionId") 376 262 continue; 377 263 378 264 int timeoutMS; 379 if (!it->value->asInteger(timeoutMS) || timeoutMS < 0 || timeoutMS > INT_MAX) { 380 completionHandler(CommandResult::fail(CommandResult::ErrorCode::InvalidArgument)); 381 return; 382 } 265 if (!it->value->asInteger(timeoutMS) || timeoutMS < 0 || timeoutMS > INT_MAX) 266 return std::nullopt; 383 267 384 268 if (it->key == "script") … … 388 272 else if (it->key == "implicit") 389 273 timeouts.implicit = Seconds::fromMilliseconds(timeoutMS); 390 else { 391 completionHandler(CommandResult::fail(CommandResult::ErrorCode::InvalidArgument)); 392 return; 393 } 394 } 395 396 session->setTimeouts(timeouts, WTFMove(completionHandler)); 274 else 275 return std::nullopt; 276 } 277 return timeouts; 278 } 279 280 void WebDriverService::parseCapabilities(const InspectorObject& matchedCapabilities, Capabilities& capabilities) const 281 { 282 // Matched capabilities have already been validated. 283 bool acceptInsecureCerts; 284 if (matchedCapabilities.getBoolean(ASCIILiteral("acceptInsecureCerts"), acceptInsecureCerts)) 285 capabilities.acceptInsecureCerts = acceptInsecureCerts; 286 String browserName; 287 if (matchedCapabilities.getString(ASCIILiteral("browserName"), browserName)) 288 capabilities.browserName = browserName; 289 String browserVersion; 290 if (matchedCapabilities.getString(ASCIILiteral("browserVersion"), browserVersion)) 291 capabilities.browserVersion = browserVersion; 292 String platformName; 293 if (matchedCapabilities.getString(ASCIILiteral("platformName"), platformName)) 294 capabilities.platformName = platformName; 295 RefPtr<InspectorObject> timeouts; 296 if (matchedCapabilities.getObject(ASCIILiteral("timeouts"), timeouts)) 297 capabilities.timeouts = deserializeTimeouts(*timeouts); 298 platformParseCapabilities(matchedCapabilities, capabilities); 299 } 300 301 RefPtr<Session> WebDriverService::findSessionOrCompleteWithError(InspectorObject& parameters, Function<void (CommandResult&&)>& completionHandler) 302 { 303 String sessionID; 304 if (!parameters.getString(ASCIILiteral("sessionId"), sessionID)) { 305 completionHandler(CommandResult::fail(CommandResult::ErrorCode::InvalidArgument)); 306 return nullptr; 307 } 308 309 auto session = m_sessions.get(sessionID); 310 if (!session) { 311 completionHandler(CommandResult::fail(CommandResult::ErrorCode::InvalidSessionID)); 312 return nullptr; 313 } 314 315 return session; 316 } 317 318 RefPtr<InspectorObject> WebDriverService::validatedCapabilities(const InspectorObject& capabilities) const 319 { 320 // §7.2 Processing Capabilities. 321 // https://w3c.github.io/webdriver/webdriver-spec.html#dfn-validate-capabilities 322 auto result = InspectorObject::create(); 323 auto end = capabilities.end(); 324 for (auto it = capabilities.begin(); it != end; ++it) { 325 if (it->value->isNull()) 326 result->setValue(it->key, RefPtr<InspectorValue>(it->value)); 327 else if (it->key == "acceptInsecureCerts") { 328 bool acceptInsecureCerts; 329 if (!it->value->asBoolean(acceptInsecureCerts)) 330 return nullptr; 331 result->setBoolean(it->key, acceptInsecureCerts); 332 } else if (it->key == "browserName" || it->key == "browserVersion" || it->key == "platformName") { 333 String stringValue; 334 if (!it->value->asString(stringValue)) 335 return nullptr; 336 result->setString(it->key, stringValue); 337 } else if (it->key == "pageLoadStrategy") { 338 String pageLoadStrategy; 339 if (!it->value->asString(pageLoadStrategy)) 340 return nullptr; 341 // FIXME: implement pageLoadStrategy. 342 result->setString(it->key, pageLoadStrategy); 343 } else if (it->key == "proxy") { 344 // FIXME: implement proxy support. 345 } else if (it->key == "timeouts") { 346 RefPtr<InspectorObject> timeouts; 347 if (!it->value->asObject(timeouts) || !deserializeTimeouts(*timeouts)) 348 return nullptr; 349 result->setValue(it->key, RefPtr<InspectorValue>(it->value)); 350 } else if (it->key == "unhandledPromptBehavior") { 351 String unhandledPromptBehavior; 352 if (!it->value->asString(unhandledPromptBehavior)) 353 return nullptr; 354 // FIXME: implement prompts support. 355 result->setString(it->key, unhandledPromptBehavior); 356 } else if (it->key.find(":") != notFound) { 357 if (!platformValidateCapability(it->key, it->value)) 358 return nullptr; 359 result->setValue(it->key, RefPtr<InspectorValue>(it->value)); 360 } 361 } 362 return result; 363 } 364 365 RefPtr<InspectorObject> WebDriverService::mergeCapabilities(const InspectorObject& requiredCapabilities, const InspectorObject& firstMatchCapabilities) const 366 { 367 // §7.2 Processing Capabilities. 368 // https://w3c.github.io/webdriver/webdriver-spec.html#dfn-merging-capabilities 369 auto result = InspectorObject::create(); 370 auto requiredEnd = requiredCapabilities.end(); 371 for (auto it = requiredCapabilities.begin(); it != requiredEnd; ++it) 372 result->setValue(it->key, RefPtr<InspectorValue>(it->value)); 373 374 auto firstMatchEnd = firstMatchCapabilities.end(); 375 for (auto it = firstMatchCapabilities.begin(); it != firstMatchEnd; ++it) { 376 if (requiredCapabilities.find(it->key) != requiredEnd) 377 return nullptr; 378 379 result->setValue(it->key, RefPtr<InspectorValue>(it->value)); 380 } 381 382 return result; 383 } 384 385 std::optional<String> WebDriverService::matchCapabilities(const InspectorObject& mergedCapabilities) const 386 { 387 // §7.2 Processing Capabilities. 388 // https://w3c.github.io/webdriver/webdriver-spec.html#dfn-matching-capabilities 389 Capabilities matchedCapabilities = platformCapabilities(); 390 391 // Some capabilities like browser name and version might need to launch the browser, 392 // so we only reject the known capabilities that don't match. 393 auto end = mergedCapabilities.end(); 394 for (auto it = mergedCapabilities.begin(); it != end; ++it) { 395 if (it->key == "browserName" && matchedCapabilities.browserName) { 396 String browserName; 397 it->value->asString(browserName); 398 if (!equalIgnoringASCIICase(matchedCapabilities.browserName.value(), browserName)) 399 return makeString("expected browserName ", matchedCapabilities.browserName.value(), " but got ", browserName); 400 } else if (it->key == "browserVersion" && matchedCapabilities.browserVersion) { 401 String browserVersion; 402 it->value->asString(browserVersion); 403 if (!platformCompareBrowserVersions(browserVersion, matchedCapabilities.browserVersion.value())) 404 return makeString("requested browserVersion is ", browserVersion, " but actual version is ", matchedCapabilities.browserVersion.value()); 405 } else if (it->key == "platformName" && matchedCapabilities.platformName) { 406 String platformName; 407 it->value->asString(platformName); 408 if (!equalLettersIgnoringASCIICase(platformName, "any") && !equalIgnoringASCIICase(matchedCapabilities.platformName.value(), platformName)) 409 return makeString("expected platformName ", matchedCapabilities.platformName.value(), " but got ", platformName); 410 } else if (it->key == "acceptInsecureCerts" && matchedCapabilities.acceptInsecureCerts) { 411 bool acceptInsecureCerts; 412 it->value->asBoolean(acceptInsecureCerts); 413 if (acceptInsecureCerts && !matchedCapabilities.acceptInsecureCerts.value()) 414 return String("browser doesn't accept insecure TLS certificates"); 415 } else if (it->key == "proxy") { 416 // FIXME: implement proxy support. 417 } else if (auto errorString = platformMatchCapability(it->key, it->value)) 418 return errorString; 419 } 420 421 return std::nullopt; 422 } 423 424 RefPtr<InspectorObject> WebDriverService::processCapabilities(const InspectorObject& parameters, Function<void (CommandResult&&)>& completionHandler) const 425 { 426 // §7.2 Processing Capabilities. 427 // https://w3c.github.io/webdriver/webdriver-spec.html#processing-capabilities 428 429 // 1. Let capabilities request be the result of getting the property "capabilities" from parameters. 430 RefPtr<InspectorObject> capabilitiesObject; 431 if (!parameters.getObject(ASCIILiteral("capabilities"), capabilitiesObject)) { 432 completionHandler(CommandResult::fail(CommandResult::ErrorCode::SessionNotCreated)); 433 return nullptr; 434 } 435 436 // 2. Let required capabilities be the result of getting the property "alwaysMatch" from capabilities request. 437 RefPtr<InspectorValue> requiredCapabilitiesValue; 438 RefPtr<InspectorObject> requiredCapabilities; 439 if (!capabilitiesObject->getValue(ASCIILiteral("alwaysMatch"), requiredCapabilitiesValue)) 440 // 2.1. If required capabilities is undefined, set the value to an empty JSON Object. 441 requiredCapabilities = InspectorObject::create(); 442 else if (!requiredCapabilitiesValue->asObject(requiredCapabilities)) { 443 completionHandler(CommandResult::fail(CommandResult::ErrorCode::SessionNotCreated, String("alwaysMatch is invalid in capabilities"))); 444 return nullptr; 445 } 446 447 // 2.2. Let required capabilities be the result of trying to validate capabilities with argument required capabilities. 448 requiredCapabilities = validatedCapabilities(*requiredCapabilities); 449 if (!requiredCapabilities) { 450 completionHandler(CommandResult::fail(CommandResult::ErrorCode::SessionNotCreated, String("Invalid alwaysMatch capabilities"))); 451 return nullptr; 452 } 453 454 // 3. Let all first match capabilities be the result of getting the property "firstMatch" from capabilities request. 455 RefPtr<InspectorValue> firstMatchCapabilitiesValue; 456 RefPtr<InspectorArray> firstMatchCapabilitiesList; 457 if (!capabilitiesObject->getValue(ASCIILiteral("firstMatch"), firstMatchCapabilitiesValue)) { 458 // 3.1. If all first match capabilities is undefined, set the value to a JSON List with a single entry of an empty JSON Object. 459 firstMatchCapabilitiesList = InspectorArray::create(); 460 firstMatchCapabilitiesList->pushObject(InspectorObject::create()); 461 } else if (!firstMatchCapabilitiesValue->asArray(firstMatchCapabilitiesList)) { 462 // 3.2. If all first match capabilities is not a JSON List, return error with error code invalid argument. 463 completionHandler(CommandResult::fail(CommandResult::ErrorCode::SessionNotCreated, String("firstMatch is invalid in capabilities"))); 464 return nullptr; 465 } 466 467 // 4. Let validated first match capabilities be an empty JSON List. 468 Vector<RefPtr<InspectorObject>> validatedFirstMatchCapabilitiesList; 469 auto firstMatchCapabilitiesListLength = firstMatchCapabilitiesList->length(); 470 validatedFirstMatchCapabilitiesList.reserveInitialCapacity(firstMatchCapabilitiesListLength); 471 // 5. For each first match capabilities corresponding to an indexed property in all first match capabilities. 472 for (unsigned i = 0; i < firstMatchCapabilitiesListLength; ++i) { 473 RefPtr<InspectorValue> firstMatchCapabilitiesValue = firstMatchCapabilitiesList->get(i); 474 RefPtr<InspectorObject> firstMatchCapabilities; 475 if (!firstMatchCapabilitiesValue->asObject(firstMatchCapabilities)) { 476 completionHandler(CommandResult::fail(CommandResult::ErrorCode::SessionNotCreated, String("Invalid capabilities found in firstMatch"))); 477 return nullptr; 478 } 479 // 5.1. Let validated capabilities be the result of trying to validate capabilities with argument first match capabilities. 480 firstMatchCapabilities = validatedCapabilities(*firstMatchCapabilities); 481 if (!firstMatchCapabilities) { 482 completionHandler(CommandResult::fail(CommandResult::ErrorCode::SessionNotCreated, String("Invalid firstMatch capabilities"))); 483 return nullptr; 484 } 485 // 5.2. Append validated capabilities to validated first match capabilities. 486 validatedFirstMatchCapabilitiesList.uncheckedAppend(WTFMove(firstMatchCapabilities)); 487 } 488 489 // 6. For each first match capabilities corresponding to an indexed property in validated first match capabilities. 490 std::optional<String> errorString; 491 for (auto& validatedFirstMatchCapabilies : validatedFirstMatchCapabilitiesList) { 492 // 6.1. Let merged capabilities be the result of trying to merge capabilities with required capabilities and first match capabilities as arguments. 493 auto mergedCapabilities = mergeCapabilities(*requiredCapabilities, *validatedFirstMatchCapabilies); 494 if (!mergedCapabilities) { 495 completionHandler(CommandResult::fail(CommandResult::ErrorCode::SessionNotCreated, String("Same capability found in firstMatch and alwaysMatch"))); 496 return nullptr; 497 } 498 // 6.2. Let matched capabilities be the result of trying to match capabilities with merged capabilities as an argument. 499 errorString = matchCapabilities(*mergedCapabilities); 500 if (!errorString) { 501 // 6.3. If matched capabilities is not null return matched capabilities. 502 return mergedCapabilities; 503 } 504 } 505 506 completionHandler(CommandResult::fail(CommandResult::ErrorCode::SessionNotCreated, errorString ? errorString.value() : String("Invalid capabilities"))); 507 return nullptr; 508 } 509 510 void WebDriverService::newSession(RefPtr<InspectorObject>&& parameters, Function<void (CommandResult&&)>&& completionHandler) 511 { 512 // §8.1 New Session. 513 // https://www.w3.org/TR/webdriver/#new-session 514 auto matchedCapabilities = processCapabilities(*parameters, completionHandler); 515 if (!matchedCapabilities) 516 return; 517 518 Capabilities capabilities; 519 parseCapabilities(*matchedCapabilities, capabilities); 520 auto sessionHost = std::make_unique<SessionHost>(WTFMove(capabilities)); 521 auto* sessionHostPtr = sessionHost.get(); 522 sessionHostPtr->connectToBrowser([this, sessionHost = WTFMove(sessionHost), completionHandler = WTFMove(completionHandler)](SessionHost::Succeeded succeeded) mutable { 523 if (succeeded == SessionHost::Succeeded::No) { 524 completionHandler(CommandResult::fail(CommandResult::ErrorCode::SessionNotCreated, String("Failed to connect to browser"))); 525 return; 526 } 527 528 RefPtr<Session> session = Session::create(WTFMove(sessionHost)); 529 session->createTopLevelBrowsingContext([this, session, completionHandler = WTFMove(completionHandler)](CommandResult&& result) mutable { 530 if (result.isError()) { 531 completionHandler(CommandResult::fail(CommandResult::ErrorCode::SessionNotCreated, result.errorMessage())); 532 return; 533 } 534 535 m_activeSession = session.get(); 536 m_sessions.add(session->id(), session); 537 538 const auto& capabilities = session->capabilities(); 539 if (capabilities.timeouts) 540 session->setTimeouts(capabilities.timeouts.value(), [](CommandResult&&) { }); 541 542 RefPtr<InspectorObject> resultObject = InspectorObject::create(); 543 resultObject->setString(ASCIILiteral("sessionId"), session->id()); 544 RefPtr<InspectorObject> capabilitiesObject = InspectorObject::create(); 545 if (capabilities.browserName) 546 capabilitiesObject->setString(ASCIILiteral("browserName"), capabilities.browserName.value()); 547 if (capabilities.browserVersion) 548 capabilitiesObject->setString(ASCIILiteral("browserVersion"), capabilities.browserVersion.value()); 549 if (capabilities.platformName) 550 capabilitiesObject->setString(ASCIILiteral("platformName"), capabilities.platformName.value()); 551 if (capabilities.acceptInsecureCerts) 552 capabilitiesObject->setBoolean(ASCIILiteral("acceptInsecureCerts"), capabilities.acceptInsecureCerts.value()); 553 if (capabilities.timeouts) { 554 RefPtr<InspectorObject> timeoutsObject = InspectorObject::create(); 555 if (capabilities.timeouts.value().script) 556 timeoutsObject->setInteger(ASCIILiteral("script"), capabilities.timeouts.value().script.value().millisecondsAs<int>()); 557 if (capabilities.timeouts.value().pageLoad) 558 timeoutsObject->setInteger(ASCIILiteral("pageLoad"), capabilities.timeouts.value().pageLoad.value().millisecondsAs<int>()); 559 if (capabilities.timeouts.value().implicit) 560 timeoutsObject->setInteger(ASCIILiteral("implicit"), capabilities.timeouts.value().implicit.value().millisecondsAs<int>()); 561 capabilitiesObject->setObject(ASCIILiteral("timeouts"), WTFMove(timeoutsObject)); 562 } 563 resultObject->setObject(ASCIILiteral("value"), WTFMove(capabilitiesObject)); 564 completionHandler(CommandResult::success(WTFMove(resultObject))); 565 }); 566 }); 567 } 568 569 void WebDriverService::deleteSession(RefPtr<InspectorObject>&& parameters, Function<void (CommandResult&&)>&& completionHandler) 570 { 571 // §8.2 Delete Session. 572 // https://www.w3.org/TR/webdriver/#delete-session 573 String sessionID; 574 if (!parameters->getString(ASCIILiteral("sessionId"), sessionID)) { 575 completionHandler(CommandResult::fail(CommandResult::ErrorCode::InvalidArgument)); 576 return; 577 } 578 579 auto session = m_sessions.take(sessionID); 580 if (!session) { 581 completionHandler(CommandResult::fail(CommandResult::ErrorCode::InvalidSessionID)); 582 return; 583 } 584 585 if (m_activeSession == session.get()) 586 m_activeSession = nullptr; 587 588 session->close(WTFMove(completionHandler)); 589 } 590 591 void WebDriverService::setTimeouts(RefPtr<InspectorObject>&& parameters, Function<void (CommandResult&&)>&& completionHandler) 592 { 593 // §8.5 Set Timeouts. 594 // https://www.w3.org/TR/webdriver/#set-timeouts 595 auto session = findSessionOrCompleteWithError(*parameters, completionHandler); 596 if (!session) 597 return; 598 599 auto timeouts = deserializeTimeouts(*parameters); 600 if (!timeouts) { 601 completionHandler(CommandResult::fail(CommandResult::ErrorCode::InvalidArgument)); 602 return; 603 } 604 605 session->setTimeouts(timeouts.value(), WTFMove(completionHandler)); 397 606 } 398 607 -
trunk/Source/WebDriver/WebDriverService.h
r219605 r220315 51 51 void quit(); 52 52 53 static bool platformCompareBrowserVersions(const String&, const String&); 54 53 55 private: 54 56 enum class HTTPMethod { Get, Post, Delete }; … … 101 103 void executeAsyncScript(RefPtr<Inspector::InspectorObject>&&, Function<void (CommandResult&&)>&&); 102 104 103 bool parseCapabilities(Inspector::InspectorObject& desiredCapabilities, Capabilities&, Function<void (CommandResult&&)>&); 104 bool platformParseCapabilities(Inspector::InspectorObject& desiredCapabilities, Capabilities&, Function<void (CommandResult&&)>&); 105 static Capabilities platformCapabilities(); 106 RefPtr<Inspector::InspectorObject> processCapabilities(const Inspector::InspectorObject&, Function<void (CommandResult&&)>&) const; 107 RefPtr<Inspector::InspectorObject> validatedCapabilities(const Inspector::InspectorObject&) const; 108 RefPtr<Inspector::InspectorObject> mergeCapabilities(const Inspector::InspectorObject&, const Inspector::InspectorObject&) const; 109 std::optional<String> matchCapabilities(const Inspector::InspectorObject&) const; 110 bool platformValidateCapability(const String&, const RefPtr<Inspector::InspectorValue>&) const; 111 std::optional<String> platformMatchCapability(const String&, const RefPtr<Inspector::InspectorValue>&) const; 112 void parseCapabilities(const Inspector::InspectorObject& desiredCapabilities, Capabilities&) const; 113 void platformParseCapabilities(const Inspector::InspectorObject& desiredCapabilities, Capabilities&) const; 105 114 RefPtr<Session> findSessionOrCompleteWithError(Inspector::InspectorObject&, Function<void (CommandResult&&)>&); 106 115 -
trunk/Source/WebDriver/glib/SessionHostGlib.cpp
r219608 r220315 136 136 g_subprocess_launcher_setenv(launcher.get(), "WEBKIT_INSPECTOR_SERVER", inspectorAddress.get(), TRUE); 137 137 #if PLATFORM(GTK) 138 g_subprocess_launcher_setenv(launcher.get(), "GTK_OVERLAY_SCROLLING", m_capabilities.useOverlayScrollbars ? "1" : "0", TRUE);138 g_subprocess_launcher_setenv(launcher.get(), "GTK_OVERLAY_SCROLLING", m_capabilities.useOverlayScrollbars.value() ? "1" : "0", TRUE); 139 139 #endif 140 140 141 GUniquePtr<char*> args(g_new0(char*, m_capabilities.browserArguments.size() + 2)); 142 args.get()[0] = g_strdup(m_capabilities.browserBinary.utf8().data()); 143 for (unsigned i = 0; i < m_capabilities.browserArguments.size(); ++i) 144 args.get()[i + 1] = g_strdup(m_capabilities.browserArguments[i].utf8().data()); 141 const auto& browserArguments = m_capabilities.browserArguments.value(); 142 GUniquePtr<char*> args(g_new0(char*, browserArguments.size() + 2)); 143 args.get()[0] = g_strdup(m_capabilities.browserBinary.value().utf8().data()); 144 for (unsigned i = 0; i < browserArguments.size(); ++i) 145 args.get()[i + 1] = g_strdup(browserArguments[i].utf8().data()); 145 146 146 147 m_browser = adoptGRef(g_subprocess_launcher_spawnv(launcher.get(), args.get(), nullptr)); … … 224 225 ASSERT(m_dbusConnection); 225 226 ASSERT(!m_startSessionCompletionHandler); 227 // FIXME: Make StartAutomationSession return browser information and we use it to match capabilities. 226 228 m_startSessionCompletionHandler = WTFMove(completionHandler); 227 229 g_dbus_connection_call(m_dbusConnection.get(), nullptr, -
trunk/Source/WebDriver/gtk/WebDriverServiceGtk.cpp
r219605 r220315 35 35 namespace WebDriver { 36 36 37 bool WebDriverService::platformParseCapabilities(InspectorObject& desiredCapabilities, Capabilities& capabilities, Function<void (CommandResult&&)>& completionHandler)37 Capabilities WebDriverService::platformCapabilities() 38 38 { 39 RefPtr<InspectorValue> value; 39 Capabilities capabilities; 40 capabilities.platformName = String("linux"); 41 capabilities.acceptInsecureCerts = false; 42 return capabilities; 43 } 44 45 bool WebDriverService::platformValidateCapability(const String& name, const RefPtr<InspectorValue>& value) const 46 { 47 if (name != "webkitgtk:browserOptions") 48 return true; 49 40 50 RefPtr<InspectorObject> browserOptions; 41 if (desiredCapabilities.getValue(ASCIILiteral("webkitgtk:browserOptions"), value) && !value->asObject(browserOptions)) { 42 completionHandler(CommandResult::fail(CommandResult::ErrorCode::SessionNotCreated, String("webkitgtk:browserOptions is invalid in capabilities"))); 51 if (!value->asObject(browserOptions)) 43 52 return false; 44 } 45 if (browserOptions->isNull()) { 46 capabilities.browserBinary = LIBEXECDIR "/webkit2gtk-" WEBKITGTK_API_VERSION_STRING "/MiniBrowser"; 47 capabilities.browserArguments = { ASCIILiteral("--automation") }; 53 54 if (browserOptions->isNull()) 48 55 return true; 49 }50 56 51 if (!browserOptions->getString(ASCIILiteral("binary"), capabilities.browserBinary)) { 52 completionHandler(CommandResult::fail(CommandResult::ErrorCode::SessionNotCreated, String("binary parameter is invalid or missing in webkitgtk:browserOptions"))); 57 // If browser options are provided, binary is required. 58 String binary; 59 if (!browserOptions->getString(ASCIILiteral("binary"), binary)) 53 60 return false; 54 }55 61 62 RefPtr<InspectorValue> useOverlayScrollbarsValue; 63 bool useOverlayScrollbars; 64 if (browserOptions->getValue(ASCIILiteral("useOverlayScrollbars"), useOverlayScrollbarsValue) && !useOverlayScrollbarsValue->asBoolean(useOverlayScrollbars)) 65 return false; 66 67 RefPtr<InspectorValue> browserArgumentsValue; 56 68 RefPtr<InspectorArray> browserArguments; 57 if (browserOptions->getValue(ASCIILiteral("args"), value) && !value->asArray(browserArguments)) { 58 completionHandler(CommandResult::fail(CommandResult::ErrorCode::SessionNotCreated, String("args parameter is invalid in webkitgtk:browserOptions"))); 69 if (browserOptions->getValue(ASCIILiteral("args"), browserArgumentsValue) && !browserArgumentsValue->asArray(browserArguments)) 59 70 return false; 60 } 71 61 72 unsigned browserArgumentsLength = browserArguments->length(); 62 if (!browserArgumentsLength)63 return true;64 capabilities.browserArguments.reserveInitialCapacity(browserArgumentsLength);65 73 for (unsigned i = 0; i < browserArgumentsLength; ++i) { 66 74 RefPtr<InspectorValue> value = browserArguments->get(i); 67 75 String argument; 68 if (!value->asString(argument)) { 69 capabilities.browserArguments.clear(); 70 completionHandler(CommandResult::fail(CommandResult::ErrorCode::SessionNotCreated, String("Failed to extract arguments from webkitgtk:browserOptions::args"))); 76 if (!value->asString(argument)) 71 77 return false; 72 }73 capabilities.browserArguments.uncheckedAppend(WTFMove(argument));74 78 } 75 79 76 if (browserOptions->getValue(ASCIILiteral("useOverlayScrollbars"), value) && !value->asBoolean(capabilities.useOverlayScrollbars)) { 77 completionHandler(CommandResult::fail(CommandResult::ErrorCode::SessionNotCreated, String("useOverlayScrollbars parameter is invalid in webkitgtk:browserOptions"))); 80 return true; 81 } 82 83 std::optional<String> WebDriverService::platformMatchCapability(const String&, const RefPtr<InspectorValue>&) const 84 { 85 return std::nullopt; 86 } 87 88 static bool parseVersion(const String& version, uint64_t& major, uint64_t& minor, uint64_t& micro) 89 { 90 major = minor = micro = 0; 91 92 Vector<String> tokens; 93 version.split(".", false, tokens); 94 bool ok; 95 switch (tokens.size()) { 96 case 3: 97 micro = tokens[2].toInt64(&ok); 98 if (!ok) 99 return false; 100 FALLTHROUGH; 101 case 2: 102 minor = tokens[1].toInt64(&ok); 103 if (!ok) 104 return false; 105 FALLTHROUGH; 106 case 1: 107 major = tokens[0].toInt64(&ok); 108 if (!ok) 109 return false; 110 break; 111 default: 78 112 return false; 79 113 } … … 82 116 } 83 117 118 bool WebDriverService::platformCompareBrowserVersions(const String& requiredVersion, const String& proposedVersion) 119 { 120 // We require clients to use format major.micro.minor as version string. 121 uint64_t requiredMajor, requiredMinor, requiredMicro; 122 if (!parseVersion(requiredVersion, requiredMajor, requiredMinor, requiredMicro)) 123 return false; 124 125 uint64_t proposedMajor, proposedMinor, proposedMicro; 126 if (!parseVersion(proposedVersion, proposedMajor, proposedMinor, proposedMicro)) 127 return false; 128 129 return proposedMajor > requiredMajor 130 || (proposedMajor == requiredMajor && proposedMinor > requiredMinor) 131 || (proposedMajor == requiredMajor && proposedMinor == requiredMinor && proposedMicro >= requiredMicro); 132 } 133 134 void WebDriverService::platformParseCapabilities(const InspectorObject& matchedCapabilities, Capabilities& capabilities) const 135 { 136 RefPtr<InspectorObject> browserOptions; 137 if (!matchedCapabilities.getObject(ASCIILiteral("webkitgtk:browserOptions"), browserOptions)) { 138 capabilities.browserBinary = String(LIBEXECDIR "/webkit2gtk-" WEBKITGTK_API_VERSION_STRING "/MiniBrowser"); 139 capabilities.browserArguments = Vector<String> { ASCIILiteral("--automation") }; 140 capabilities.useOverlayScrollbars = true; 141 return; 142 } 143 144 String browserBinary; 145 browserOptions->getString(ASCIILiteral("binary"), browserBinary); 146 ASSERT(!browserBinary.isNull()); 147 capabilities.browserBinary = browserBinary; 148 149 capabilities.browserArguments = Vector<String>(); 150 RefPtr<InspectorArray> browserArguments; 151 if (browserOptions->getArray(ASCIILiteral("args"), browserArguments)) { 152 unsigned browserArgumentsLength = browserArguments->length(); 153 capabilities.browserArguments->reserveInitialCapacity(browserArgumentsLength); 154 for (unsigned i = 0; i < browserArgumentsLength; ++i) { 155 RefPtr<InspectorValue> value = browserArguments->get(i); 156 String argument; 157 value->asString(argument); 158 ASSERT(!argument.isNull()); 159 capabilities.browserArguments->uncheckedAppend(WTFMove(argument)); 160 } 161 } 162 163 bool useOverlayScrollbars; 164 if (browserOptions->getBoolean(ASCIILiteral("useOverlayScrollbars"), useOverlayScrollbars)) 165 capabilities.useOverlayScrollbars = useOverlayScrollbars; 166 else 167 capabilities.useOverlayScrollbars = true; 168 } 169 84 170 } // namespace WebDriver
Note: See TracChangeset
for help on using the changeset viewer.