Jump to content

Webdriver, Websockets, and Chrome DevTools Protocol ... Oh my! ​😜


Recommended Posts

Hi All,

I have been working on an enhancement to the WebDriver UDF that will make _WD_ExecuteCDPCommand compatible with all major browsers instead of Chrome only. This involves using WebSockets to pass commands back and forth to the browser.

Attached to this post are two files --

  • winhttp_websocket.au3 -- This is a modified version of code originally posted to the forum by @FireFox.
  • genericcdp.au3 -- This contains the enhanced version of _WD_ExecuteCDPCommand (original version by @TheDcoder) and a new function named _WD_GetCDPSettings

You can run genericcdp.au3 for a brief example of how the new functionality works. Comment / uncomment the appropriate lines near the beginning to control while browser gets tested.

Prerequisites

  • You'll obviously need the WebDriver UDF installed and working for this code to have a chance of working correct. 🙄
  • You need to be running an OS that supports WebSockets natively (ie: Windows 8 / Windows Server 2012 or newer)

Caveats
Chromium-based browsers return some unexpected status codes in response to _WinHttpWebSocketClose and _WinHttpWebSocketQueryCloseStatus, so I've included checks to ignore these.

Needs
I would appreciate it if I could get some feedback / suggestions for improvement on these proposed changes.

FWIW, I have only performed these basic CDP commands. Feel free to experiment with other CDP commands and report back on your successes / failures.

Thanks,

Dan

genericcdp.au3 winhttp_websocket.au3

Edited by Danp2
Added OS restrictions
Link to post
Share on other sites

You are using websocket APIs that state that they require a minimum client of Windows 8 or a minimum server of Windows 2012.  Shouldn't that be listed as a prerequisite?  :)

I just ran the genericCDP script using the latest 64-bit Firefox on Windows 7 and I got an @error = 2 from the _WD_ExecuteCDPCommand() function.  I ran the same test on a Windows 10 client and it worked as expected.

The log from Windows 7 PC is below:

_WD_Startup: OS:    WIN_7 WIN32_NT 7601 Service Pack 1
_WD_Startup: AutoIt:    3.3.14.5
_WD_Startup: WD.au3:    0.4.0.5
_WD_Startup: WinHTTP:   1.6.4.2
_WD_Startup: Driver:    C:\Portable Apps\AutoIt3\Include\MyIncludes\WebDriver\Drivers\geckodriver_x64.exe
_WD_Startup: Params:    --log trace
_WD_Startup: Port:  4444
__WD_Post: URL=HTTP://127.0.0.1:4444/session; $sData={"capabilities":{"alwaysMatch": {"moz:debuggerAddress": true, "moz:firefoxOptions": {"log": {"level": "trace"}}}}}
__WD_Post: StatusCode=200; ResponseText={"value":{"sessionId":"38491b67-3b02-4638-a7fd-077cf118e04f","capabilities":{"acceptInsecureCerts":f...
_WD_CreateSession: {"value":{"sessionId":"38491b67-3b02-4638-a7fd-077cf118e04f","capabilities":{"acceptInsecureCerts":false,"browserName":"firefox","browserVersion":"90.0","moz:accessibilityChecks":false,"moz:buildID":"20210705185941","moz:debuggerAddress":"localhost:60972","moz:geckodriverVersion":"0.29.1","moz:headless":false,"moz:processID":6528,"moz:profile":"C:\\Temp\\rust_mozprofile0i0kl3","moz:shutdownTimeout":60000,"moz:useNonSpecCompliantPointerOrigin":false,"moz:webdriverClick":true,"pageLoadStrategy":"normal","platformName":"windows","platformVersion":"6.1","proxy":{},"setWindowRect":true,"strictFileInteractability":false,"timeouts":{"implicit":0,"pageLoad":300000,"script":30000},"unhandledPromptBehavior":"dismiss and notify"}}}
__WD_Post: URL=HTTP://127.0.0.1:4444/session/38491b67-3b02-4638-a7fd-077cf118e04f/url; $sData={"url":"http://google.com"}
__WD_Post: StatusCode=200; ResponseText={"value":null}...
_WD_Navigate: {"value":null}
__WD_Post: URL=HTTP://127.0.0.1:4444/session/38491b67-3b02-4638-a7fd-077cf118e04f/window/new; $sData={"type":"tab"}
__WD_Post: StatusCode=200; ResponseText={"value":{"handle":"64c6d394-1b1b-46d6-bb8f-d1599fbfe0f2","type":"tab"}}...
_WD_Window: {"value":{"handle":"64c6d394-1b1b-46d6-bb8f-d1599fbfe0f2","type":"tab"}}...
__WD_Post: URL=HTTP://127.0.0.1:4444/session/38491b67-3b02-4638-a7fd-077cf118e04f/window; $sData={"handle":"64c6d394-1b1b-46d6-bb8f-d1599fbfe0f2"}
__WD_Post: StatusCode=200; ResponseText={"value":null}...
_WD_Window: {"value":null}...
__WD_Post: URL=HTTP://127.0.0.1:4444/session/38491b67-3b02-4638-a7fd-077cf118e04f/url; $sData={"url":"http://yahoo.com"}
__WD_Post: StatusCode=200; ResponseText={"value":null}...
_WD_Navigate: {"value":null}
__WD_Get: URL=http://localhost:60972/json/list
__WD_Get: StatusCode=200; $iResult = 0; $sResponseText=[
    {
        "description": "",
        "devtoolsFrontendUrl": null,
        "faviconUrl": "",
        "id": "a881de60-63d7-...
_WD_ExecuteCDPCommand: ...
_WD_ExecuteCDPCommand ==> Socket Error: SetOption error

 

Edited by TheXman
Link to post
Share on other sites
Posted (edited)
55 minutes ago, TheXman said:

You are using websocket APIs that state that they require a minimum client of Windows 8 or a minimum server of Windows 2012.  Shouldn't that be listed as a prerequisite? 

Very true. I will update the OP.

55 minutes ago, TheXman said:

I just ran the genericCDP script using the latest 64-bit Firefox on Windows 7 and I got an @error = 2

That makes sense given the above prerequisite.

P.S. Thanks for testing!

Edited by Danp2
Link to post
Share on other sites

I only use Firefox and my primary PCs are Windows 7.  However, I do have a Windows 10 PC with MS Edge that I can run tests on.  I'll take a look at the error when you're closing a websocket, on MS Edge, and see if I can find the root cause.  Can you explain the issue that you are seeing so I know that I'm chasing the right problem? If you have implemented any workarounds that may be masking the issue, can you provide either a script that reproduces the issue or tell me what steps I need to take to reproduce it?

Edited by TheXman
Link to post
Share on other sites

Vacation Mode.

Sorry 

;)

 

Signature beginning:
Please remember: "AutoIt".....  Wondering who uses AutoIt and what it can be used for ?
* GHAPI UDF - modest beginning - communication with GitHub REST API Forum Rules *
Include Dependency Tree (Tool for analyzing script relations)
ADO.au3 UDF     POP3.au3 UDF     XML.au3 UDF    How to use IE.au3  UDF with  AutoIt v3.3.14.x  for other useful stuff click the following button

Spoiler

Any of my own code posted anywhere on the forum is available for use by others without any restriction of any kind. 

My contribution (my own projects): * Debenu Quick PDF Library - UDF * Debenu PDF Viewer SDK - UDF * Acrobat Reader - ActiveX Viewer * UDF for PDFCreator v1.x.x * XZip - UDF * AppCompatFlags UDF * CrowdinAPI UDF * _WinMergeCompare2Files() * _JavaExceptionAdd() * _IsBeta() * Writing DPI Awareness App - workaround * _AutoIt_RequiredVersion() * Chilkatsoft.au3 UDF * TeamViewer.au3 UDF * JavaManagement UDF * VIES over SOAP * WinSCP UDF * GHAPI UDF - modest begining - comunication with GitHub REST APIErrorLog.au3 UDF - A logging Library *

My contribution to others projects or UDF based on  others projects: * _sql.au3 UDF  * POP3.au3 UDF *  RTF Printer - UDF * XML.au3 UDF * ADO.au3 UDF SMTP Mailer UDF * Dual Monitor resolution detection * * 2GUI on Dual Monitor System * _SciLexer.au3 UDF * SciTE - Lexer for console pane

Useful links: * Forum Rules * Forum etiquette *  Forum Information and FAQs * How to post code on the forum * AutoIt Online Documentation * AutoIt Online Beta Documentation * SciTE4AutoIt3 getting started * Convert text blocks to AutoIt code * Games made in Autoit * Programming related sites * Polish AutoIt Tutorial * DllCall Code Generator * 

Wiki: Expand your knowledge - AutoIt Wiki * Collection of User Defined Functions * How to use HelpFile * Good coding practices in AutoIt * 

OpenOffice/LibreOffice/XLS Related: WriterDemo.au3 * XLS/MDB from scratch with ADOX

IE Related:  * How to use IE.au3  UDF with  AutoIt v3.3.14.x * Why isn't Autoit able to click a Javascript Dialog? * Clicking javascript button with no ID * IE document >> save as MHT file * IETab Switcher (by LarsJ ) * HTML Entities * _IEquerySelectorAll() (by uncommon) * IE in TaskSchedulerIE Embedded Control Versioning (use IE9+ and HTML5 in a GUI) *

PDF Related:How to get reference to PDF object embeded in IE *

I encourage you to read: * Global Vars * Best Coding Practices * Please explain code used in Help file for several File functions * OOP-like approach in AutoIt * UDF-Spec Questions *  EXAMPLE: How To Catch ConsoleWrite() output to a file or to CMD *

I also encourage you to check awesome @trancexx code:  * Create COM objects from modules without any demand on user to register anything. * Another COM object registering stuffOnHungApp handlerAvoid "AutoIt Error" message box in unknown errors  * HTML editor

"Homo sum; humani nil a me alienum puto" - Publius Terentius Afer
"Program are meant to be read by humans and only incidentally for computers and execute" - Donald Knuth, "The Art of Computer Programming"
:naughty:  :ranting:, be  :) and       \\//_.

Anticipating Errors :  "Any program that accepts data from a user must include code to validate that data before sending it to the data store. You cannot rely on the data store, ...., or even your programming language to notify you of problems. You must check every byte entered by your users, making sure that data is the correct type for its field and that required fields are not empty."

Signature last update: 2021-03-17

Link to post
Share on other sites

@TheXmanThat's for the offer. Look at the error checking in _WD_ExecuteCDPCommand following the calls to _WinHttpWebSocketClose and _WinHttpWebSocketQueryCloseStatus. I don't encounter these error codes (ERROR_WINHTTP_CONNECTION_ERROR and ERROR_INVALID_OPERATION) with Firefox, but I do consistently with Chrome and Edge.

@mLipokI knew it. Otherwise, you would have already torn it apart and complete rewritten it. 😜

Link to post
Share on other sites

I just starting taking a look.  Before getting too deep, I noticed something that I couldn't figure out.

 

Microsoft defines the _WINHTTP_WEB_SOCKET_CLOSE_STATUS enumerators as: (starting at 0)

typedef enum _WINHTTP_WEB_SOCKET_CLOSE_STATUS {
  WINHTTP_WEB_SOCKET_SUCCESS_CLOSE_STATUS,
  WINHTTP_WEB_SOCKET_ENDPOINT_TERMINATED_CLOSE_STATUS,
  WINHTTP_WEB_SOCKET_PROTOCOL_ERROR_CLOSE_STATUS,
  WINHTTP_WEB_SOCKET_INVALID_DATA_TYPE_CLOSE_STATUS,
  WINHTTP_WEB_SOCKET_EMPTY_CLOSE_STATUS,
  WINHTTP_WEB_SOCKET_ABORTED_CLOSE_STATUS,
  WINHTTP_WEB_SOCKET_INVALID_PAYLOAD_CLOSE_STATUS,
  WINHTTP_WEB_SOCKET_POLICY_VIOLATION_CLOSE_STATUS,
  WINHTTP_WEB_SOCKET_MESSAGE_TOO_BIG_CLOSE_STATUS,
  WINHTTP_WEB_SOCKET_UNSUPPORTED_EXTENSIONS_CLOSE_STATUS,
  WINHTTP_WEB_SOCKET_SERVER_ERROR_CLOSE_STATUS,
  WINHTTP_WEB_SOCKET_SECURE_HANDSHAKE_ERROR_CLOSE_STATUS
} WINHTTP_WEB_SOCKET_CLOSE_STATUS;

However, in the winhttp_websocket.au3 UDF lib, the enum is defined as: (starting at 1000)

Global Enum _
        $WINHTTP_WEB_SOCKET_SUCCESS_CLOSE_STATUS = 1000, _
        $WINHTTP_WEB_SOCKET_ENDPOINT_TERMINATED_CLOSE_STATUS, _
        $WINHTTP_WEB_SOCKET_PROTOCOL_ERROR_CLOSE_STATUS, _
        $WINHTTP_WEB_SOCKET_INVALID_DATA_TYPE_CLOSE_STATUS, _
        $WINHTTP_WEB_SOCKET_EMPTY_CLOSE_STATUS, _
        $WINHTTP_WEB_SOCKET_ABORTED_CLOSE_STATUS, _
        $WINHTTP_WEB_SOCKET_INVALID_PAYLOAD_CLOSE_STATUS, _
        $WINHTTP_WEB_SOCKET_POLICY_VIOLATION_CLOSE_STATUS, _
        $WINHTTP_WEB_SOCKET_MESSAGE_TOO_BIG_CLOSE_STATUS, _
        $WINHTTP_WEB_SOCKET_UNSUPPORTED_EXTENSIONS_CLOSE_STATUS, _
        $WINHTTP_WEB_SOCKET_SERVER_ERROR_CLOSE_STATUS, _
        $WINHTTP_WEB_SOCKET_SECURE_HANDSHAKE_ERROR_CLOSE_STATUS

I haven't been able to figure out why you start your enumerators at 1000?  That would throw off all of the statuses by 1000, including a successful status.  :think:

Edited by TheXman
Added link to MS enum definition
Link to post
Share on other sites

That is very odd.  Looking at sources other than Microsoft, I do see references to the enumerator starting at 1000.

I added a link, in my previous post, to the definition on Microsoft's site.  I'll keep digging to see if I can find more information as to why there's a discrepancy.

Link to post
Share on other sites

After reading thru the WebSocket RFC as it relates to closing a WebSocket connection, in this specific use case where you are just communicating with the browser (CDP), there's really no need for the client to close the WebSocket, it'll be closed when the underlying TCP connection is closed.  I guess if you wanted to do some tidying up, you could close the WebSocket's handle before exiting the script.  ;)  I commented out all of the relevant "close" logic (WebSocketShutdown, WebSocketClose, & WebSocketQueryCloseStatus) and saw no ill effects or remnants left behind.

There's definitely something different between the way Firefox handles the CDP commands and the way MS Edge handles them.  I noticed when running the script in MS Edge, the script switches from the Yahoo page to the Google page and then back to the Yahoo page before exiting.  When running the script against Firefox, it doesn't do the last switch from Google back to Yahoo before exiting, it exits while on the Google page.

Edited by TheXman
Link to post
Share on other sites

Pretty sure what you are encountering is a different in the order that items appear in output from /json/list. You would experience the opposite if you change the line

For $x = UBound($aList, $UBOUND_COLUMNS) - 1 to 1 Step -1

to

For $x = 1 to UBound($aList, $UBOUND_COLUMNS) - 1

It was just a Q&D example, so feel free to suggest improvements. :thumbsup:

Appreciate the feedback on the WebSocket handling. I think that I'll leave the coding as-is for now.

Link to post
Share on other sites
  • Danp2 changed the title to Webdriver, Websockets, and Chrome DevTools Protocol ... Oh my! ​😜

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now
  • Recently Browsing   1 member

×
×
  • Create New...