Skip to content

Commit 4380c1b

Browse files
committed
v2.4.8
1 parent 1908e71 commit 4380c1b

14 files changed

+4611
-2181
lines changed

source/Backup/wd_capabilities.au3

Lines changed: 387 additions & 0 deletions
Large diffs are not rendered by default.

source/Backup/wd_cdp.au3

Lines changed: 343 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,343 @@
1+
#include-once
2+
#include "wd_core.au3"
3+
#include "WinHttp_WebSocket.au3" ; https://github.com/Danp2/autoit-websocket
4+
#include <APIErrorsConstants.au3>
5+
6+
#Region Copyright
7+
#cs
8+
* WD_CDP.au3
9+
*
10+
* MIT License
11+
*
12+
* Copyright (c) 2022 Dan Pollak
13+
*
14+
* Permission is hereby granted, free of charge, to any person obtaining a copy
15+
* of this software and associated documentation files (the "Software"), to deal
16+
* in the Software without restriction, including without limitation the rights
17+
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
18+
* copies of the Software, and to permit persons to whom the Software is
19+
* furnished to do so, subject to the following conditions:
20+
*
21+
* The above copyright notice and this permission notice shall be included in all
22+
* copies or substantial portions of the Software.
23+
*
24+
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
25+
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
26+
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
27+
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
28+
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
29+
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
30+
* SOFTWARE.
31+
#ce
32+
#EndRegion Copyright
33+
34+
; #FUNCTION# ====================================================================================================================
35+
; Name ..........: _WD_CDPExecuteCommand
36+
; Description ...: Execute CDP command.
37+
; Syntax ........: _WD_CDPExecuteCommand($sSession, $sCommand, $oParams[, $sWebSocketURL = Default])
38+
; Parameters ....: $sSession - Session ID from _WD_CreateSession
39+
; $sCommand - Name of the command
40+
; $oParams - Parameters of the command as an object
41+
; $sWebSocketURL - [optional] Websocket URL
42+
; Return values .: Success - Raw return value from web driver in JSON format.
43+
; Failure - "" (empty string) and sets @error to $_WD_ERROR_Exception
44+
; Author ........: Damon Harris (TheDcoder)
45+
; Modified ......: Danp2
46+
; Remarks .......: The original version of this function is specific to ChromeDriver, you can execute "Chrome DevTools Protocol"
47+
; commands by using this function, for all available commands see: https://chromedevtools.github.io/devtools-protocol/tot/
48+
;+
49+
; The revised version uses websockets to provide CDP access for all compatible browsers. However, it
50+
; will only with an OS that natively supports WebSockets (Windows 8, Windows Server 2012, or newer)
51+
; Related .......: _WD_LastHTTPResult
52+
; Link ..........:
53+
; Example .......: No
54+
; ===============================================================================================================================
55+
Func _WD_CDPExecuteCommand($sSession, $sCommand, $oParams, $sWebSocketURL = Default)
56+
Local Const $sFuncName = "_WD_ExecuteCDPCommand"
57+
Local $iErr = 0, $vData = Json_ObjCreate()
58+
$_WD_HTTPRESULT = 0
59+
60+
If $sWebSocketURL = Default Then $sWebSocketURL = ''
61+
62+
; Original version (Chrome only)
63+
If Not $sWebSocketURL Then
64+
Json_ObjPut($vData, 'cmd', $sCommand)
65+
Json_ObjPut($vData, 'params', $oParams)
66+
$vData = Json_Encode($vData)
67+
68+
Local $sResponse = __WD_Post($_WD_BASE_URL & ":" & $_WD_PORT & "/session/" & $sSession & '/goog/cdp/execute', $vData)
69+
$iErr = @error
70+
71+
__WD_ConsoleWrite($sFuncName & ': ' & $sResponse, $_WD_DEBUG_Info)
72+
73+
Return SetError(__WD_Error($sFuncName, $iErr), 0, $sResponse)
74+
EndIf
75+
76+
; Websocket version
77+
Local $hOpen = 0, $hConnect = 0, $hRequest = 0, $hWebSocket = 0
78+
Local $aURL, $fStatus, $sErrText, $sMessage = ""
79+
Local $iBufferLen = 1024, $tBuffer = 0, $bRecv = Binary(""), $sRecv
80+
Local $iBytesRead = 0, $iBufferType = 0
81+
Local $iStatus = 0, $iReasonLengthConsumed = 0
82+
Local $tCloseReasonBuffer = DllStructCreate("byte[123]")
83+
Local $sWSSRegex = '^((ws[s]?):\/\/)([^:\/\s]+)(?::([0-9]+))?(.*)$'
84+
Local Static $iID = 0
85+
86+
$aURL = StringRegExp($sWebSocketURL, $sWSSRegex, 3)
87+
88+
If Not IsArray($aURL) Or UBound($aURL) < 5 Then
89+
$iErr = $_WD_ERROR_InvalidValue
90+
$sErrText = "URL invalid"
91+
Else
92+
; Initialize and get session handle
93+
$hOpen = _WinHttpOpen()
94+
95+
If $_WD_WINHTTP_TIMEOUTS Then
96+
_WinHttpSetTimeouts($hOpen, $_WD_HTTPTimeOuts[0], $_WD_HTTPTimeOuts[1], $_WD_HTTPTimeOuts[2], $_WD_HTTPTimeOuts[3])
97+
EndIf
98+
99+
; Get connection handle
100+
$hConnect = _WinHttpConnect($hOpen, $aURL[2], $aURL[3])
101+
102+
$hRequest = _WinHttpOpenRequest($hConnect, "GET", $aURL[4], "")
103+
104+
; Request protocol upgrade from http to websocket.
105+
$fStatus = _WinHttpSetOptionNoParams($hRequest, $WINHTTP_OPTION_UPGRADE_TO_WEB_SOCKET)
106+
107+
If Not $fStatus Then
108+
$iErr = $_WD_ERROR_SocketError
109+
$sErrText = "SetOption error"
110+
Else
111+
; Perform websocket handshake by sending a request and receiving server's response.
112+
; Application may specify additional headers if needed.
113+
$fStatus = _WinHttpSendRequest($hRequest)
114+
115+
If Not $fStatus Then
116+
$iErr = $_WD_ERROR_SocketError
117+
$sErrText = "SendRequest error"
118+
Else
119+
$fStatus = _WinHttpReceiveResponse($hRequest)
120+
121+
If Not $fStatus Then
122+
$iErr = $_WD_ERROR_SocketError
123+
$sErrText = "ReceiveResponse error"
124+
Else
125+
; Application should check what is the HTTP status code returned by the server and behave accordingly.
126+
; WinHttpWebSocketCompleteUpgrade will fail if the HTTP status code is different than 101.
127+
$iStatus = _WinHttpQueryHeaders($hRequest, $WINHTTP_QUERY_STATUS_CODE)
128+
129+
If $iStatus = $HTTP_STATUS_SWITCH_PROTOCOLS Then
130+
$hWebSocket = _WinHttpWebSocketCompleteUpgrade($hRequest, 0)
131+
132+
If $hWebSocket = 0 Then
133+
$iErr = $_WD_ERROR_SocketError
134+
$sErrText = "WebSocketCompleteUpgrade error"
135+
EndIf
136+
Else
137+
$iErr = $_WD_ERROR_SocketError
138+
$sErrText = "ReceiveResponse Status <> $HTTP_STATUS_SWITCH_PROTOCOLS"
139+
EndIf
140+
EndIf
141+
EndIf
142+
EndIf
143+
144+
If Not $iErr Then
145+
_WinHttpCloseHandle($hRequest)
146+
147+
$iID += 1
148+
Json_ObjPut($vData, 'id', $iID)
149+
Json_ObjPut($vData, 'method', $sCommand)
150+
Json_ObjPut($vData, 'params', $oParams)
151+
$vData = Json_Encode($vData)
152+
153+
; Send and receive data on the websocket protocol.
154+
155+
$fStatus = _WinHttpWebSocketSend($hWebSocket, _
156+
$WINHTTP_WEB_SOCKET_UTF8_MESSAGE_BUFFER_TYPE, _
157+
$vData)
158+
159+
If @error Or $fStatus <> 0 Then
160+
$iErr = $_WD_ERROR_SocketError
161+
$sErrText = "WebSocketSend error"
162+
Else
163+
Do
164+
If $iBufferLen = 0 Then
165+
$iErr = $_WD_ERROR_GeneralError
166+
$sErrText = "Not enough memory"
167+
ExitLoop
168+
EndIf
169+
170+
$tBuffer = DllStructCreate("byte[" & $iBufferLen & "]")
171+
172+
$fStatus = _WinHttpWebSocketReceive($hWebSocket, _
173+
$tBuffer, _
174+
$iBytesRead, _
175+
$iBufferType)
176+
177+
If @error Or $fStatus <> 0 Then
178+
$iErr = $_WD_ERROR_SocketError
179+
$sErrText = "WebSocketReceive error"
180+
ExitLoop
181+
EndIf
182+
183+
; If we receive just part of the message restart the receive operation.
184+
$bRecv &= BinaryMid(DllStructGetData($tBuffer, 1), 1, $iBytesRead)
185+
$tBuffer = 0
186+
187+
$iBufferLen -= $iBytesRead
188+
Until $iBufferType <> $WINHTTP_WEB_SOCKET_UTF8_FRAGMENT_BUFFER_TYPE
189+
190+
If Not $iErr Then
191+
; We expected server just to echo single UTF8 message.
192+
If $iBufferType <> $WINHTTP_WEB_SOCKET_UTF8_MESSAGE_BUFFER_TYPE Then
193+
$iErr = $_WD_ERROR_SocketError
194+
$sErrText = "Unexpected buffer type"
195+
EndIf
196+
197+
$sRecv = BinaryToString($bRecv)
198+
EndIf
199+
200+
; Gracefully close the connection.
201+
;~ $fStatus = _WinHttpWebSocketShutdown($hWebSocket, _
202+
;~ $WINHTTP_WEB_SOCKET_SUCCESS_CLOSE_STATUS)
203+
204+
$fStatus = _WinHttpWebSocketClose($hWebSocket, _
205+
$WINHTTP_WEB_SOCKET_SUCCESS_CLOSE_STATUS)
206+
207+
If @error Or ($fStatus And $fStatus <> $ERROR_WINHTTP_CONNECTION_ERROR) Then
208+
$iErr = $_WD_ERROR_SocketError
209+
$sErrText = "WebSocketClose error (" & $fStatus & ")"
210+
Else
211+
; Check close status returned by the server.
212+
$fStatus = _WinHttpWebSocketQueryCloseStatus($hWebSocket, _
213+
$iStatus, _
214+
$iReasonLengthConsumed, _
215+
$tCloseReasonBuffer)
216+
217+
If @error Or ($fStatus And $fStatus <> $ERROR_INVALID_OPERATION) Then
218+
$iErr = $_WD_ERROR_SocketError
219+
$sErrText = "QueryCloseStatus error (" & $fStatus & ")"
220+
EndIf
221+
EndIf
222+
EndIf
223+
EndIf
224+
EndIf
225+
226+
If $iErr Then
227+
Return SetError(__WD_Error($sFuncName, $iErr, $sErrText), 0, "")
228+
EndIf
229+
230+
If ($sRecv) Then
231+
If $_WD_RESPONSE_TRIM <> -1 And StringLen($sRecv) > $_WD_RESPONSE_TRIM Then
232+
$sMessage &= " ResponseText=" & StringLeft($sRecv, $_WD_RESPONSE_TRIM) & "..."
233+
Else
234+
$sMessage &= " ResponseText=" & $sRecv
235+
EndIf
236+
EndIf
237+
Return SetError(__WD_Error($sFuncName, $_WD_ERROR_Success, $sMessage), 0, $sRecv)
238+
EndFunc ;==>_WD_CDPExecuteCommand
239+
240+
; #FUNCTION# ====================================================================================================================
241+
; Name ..........: _WD_CDPGetSettings
242+
; Description ...: Retrieve CDP related settings from the browser.
243+
; Syntax ........: _WD_CDPGetSettings($sSession, $sOption)
244+
; Parameters ....: $sSession - Session ID from _WD_CreateSession
245+
; $sOption - one of the following:
246+
; |DEBUGGER - Returns the Websocket target originally returned by _WD_CreateSession
247+
; |LIST - Lists websocket targets
248+
; |VERSION - Reurns an array containing version metadata
249+
; Return values .: Success - The returned value depends on the selected $sOption.
250+
; |DEBUGGER: Websocket target originally returned by _WD_CreateSession
251+
; |LIST: Array containing websocket targets
252+
; |VERSION: Array containing version metadata
253+
; Failure - "" (empty string) and sets @error to one of the following values:
254+
; - $_WD_ERROR_Exception
255+
; - $_WD_ERROR_GeneralError
256+
; Author ........: Dan Pollak
257+
; Modified ......:
258+
; Remarks .......:
259+
; Related .......: _WD_LastHTTPResult
260+
; Link ..........:
261+
; Example .......: No
262+
; ===============================================================================================================================
263+
Func _WD_CDPGetSettings($sSession, $sOption)
264+
Local Const $sFuncName = "_WD_GetCDPSettings"
265+
Local $sJSON, $oJSON, $sDebuggerAddress, $iEntries, $aKeys, $iKeys, $aResults, $iErr
266+
Local $sKey, $vResult, $sBrowser
267+
$_WD_HTTPRESULT = 0
268+
269+
$sJSON = _WD_GetSession($sSession)
270+
$oJSON = Json_Decode($sJSON)
271+
$sBrowser = Json_Get($oJSON, '[value][capabilities][browserName]')
272+
273+
Switch $sBrowser
274+
Case 'firefox'
275+
$sKey = '[value][capabilities]["moz:debuggerAddress"]'
276+
277+
Case 'chrome'
278+
$sKey = '[value][capabilities]["goog:chromeOptions"][debuggerAddress]'
279+
280+
Case 'msedge'
281+
$sKey = '[value][capabilities]["ms:edgeOptions"][debuggerAddress]'
282+
283+
EndSwitch
284+
285+
$sDebuggerAddress = Json_Get($oJSON, $sKey)
286+
287+
If @error Then
288+
$iErr = $_WD_ERROR_GeneralError
289+
Else
290+
$sOption = StringLower($sOption)
291+
292+
Switch $sOption
293+
Case 'debugger'
294+
$vResult = $sDebuggerAddress
295+
296+
Case 'list', 'version'
297+
$sJSON = __WD_Get("http://" & $sDebuggerAddress & "/json/" & $sOption)
298+
$iErr = @error
299+
300+
If $iErr = $_WD_ERROR_Success Then
301+
$oJSON = Json_Decode($sJSON)
302+
$iEntries = UBound($oJSON)
303+
304+
If $iEntries Then
305+
$aKeys = Json_ObjGetKeys($oJSON[0])
306+
$iKeys = UBound($aKeys)
307+
308+
Dim $aResults[$iKeys][$iEntries + 1]
309+
310+
For $i = 0 To $iKeys - 1
311+
$aResults[$i][0] = $aKeys[$i]
312+
313+
For $j = 0 To $iEntries - 1
314+
$sKey = "[" & $j & "]." & $aKeys[$i]
315+
$aResults[$i][$j + 1] = Json_Get($oJSON, "[" & $j & "]." & $aKeys[$i])
316+
Next
317+
Next
318+
Else
319+
$aKeys = Json_ObjGetKeys($oJSON)
320+
$iKeys = UBound($aKeys)
321+
322+
Dim $aResults[$iKeys][2]
323+
For $i = 0 To $iKeys - 1
324+
$aResults[$i][0] = $aKeys[$i]
325+
326+
$aResults[$i][1] = Json_Get($oJSON, "." & $aKeys[$i])
327+
Next
328+
EndIf
329+
330+
$vResult = $aResults
331+
EndIf
332+
333+
Case Else
334+
Return SetError(__WD_Error($sFuncName, $_WD_ERROR_InvalidDataType, "(Debugger|List|Version) $sCommand=>" & $sOption), 0, "")
335+
EndSwitch
336+
337+
EndIf
338+
339+
If $iErr Then
340+
Return SetError(__WD_Error($sFuncName, $iErr), 0, "")
341+
EndIf
342+
Return SetError(__WD_Error($sFuncName, $_WD_ERROR_Success), 0, $vResult)
343+
EndFunc ;==>_WD_CDPGetSettings

0 commit comments

Comments
 (0)