Skip to content

Commit d5f7b2c

Browse files
committed
fix: use page-type target for message routing, not frame targets
iwdp sends Target.targetCreated events for both pages and frames. The client was using the last received targetId, which was often a frame target. Frame targets don't expose Runtime, DOM, and other domains, causing all commands to fail with "domain was not found". Now handleTargetCreated only accepts targets with type "page". Also adds ws-debug diagnostic tool and CI debug step.
1 parent a06196e commit d5f7b2c

3 files changed

Lines changed: 115 additions & 22 deletions

File tree

.github/workflows/test.yml

Lines changed: 2 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -121,27 +121,8 @@ jobs:
121121
echo "=== Pages on port 9222 ==="
122122
curl -sf http://localhost:9222/json | python3 -m json.tool || echo "FAILED"
123123
echo ""
124-
echo "=== Raw WebSocket test (first 5 messages) ==="
125-
python3 -c "
126-
import websocket, json, time
127-
ws = websocket.create_connection('$IWDP_SIM_WS_URL', timeout=5)
128-
for i in range(5):
129-
try:
130-
msg = ws.recv()
131-
print(f'Message {i}: {msg}')
132-
except:
133-
print(f'No more messages after {i}')
134-
break
135-
# Try sending a direct Runtime.evaluate
136-
ws.send(json.dumps({'id': 1, 'method': 'Runtime.evaluate', 'params': {'expression': '1+1'}}))
137-
time.sleep(1)
138-
try:
139-
resp = ws.recv()
140-
print(f'Direct response: {resp}')
141-
except:
142-
print('No response to direct message')
143-
ws.close()
144-
" 2>&1 || echo "Python websocket test failed (may need pip install websocket-client)"
124+
echo "=== Raw WebSocket test ==="
125+
go run ./scripts/ws-debug/main.go "$IWDP_SIM_WS_URL"
145126
146127
- name: Run simulator tests with coverage
147128
run: go test -tags=simulator ./... -v -count=1 -timeout=300s -coverprofile=coverage-simulator.out

internal/webkit/client.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -283,7 +283,7 @@ func (c *Client) handleTargetCreated(params json.RawMessage) {
283283
if err := json.Unmarshal(params, &p); err != nil {
284284
return
285285
}
286-
if p.TargetInfo.TargetID != "" {
286+
if p.TargetInfo.TargetID != "" && p.TargetInfo.Type == "page" {
287287
c.mu.Lock()
288288
c.targetID = p.TargetInfo.TargetID
289289
c.mu.Unlock()

scripts/ws-debug/main.go

Lines changed: 112 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,112 @@
1+
//go:build ignore
2+
3+
// ws-debug connects to an iwdp WebSocket and diagnoses Target routing.
4+
package main
5+
6+
import (
7+
"encoding/json"
8+
"fmt"
9+
"os"
10+
"time"
11+
12+
"github.com/gorilla/websocket"
13+
)
14+
15+
func main() {
16+
if len(os.Args) < 2 {
17+
fmt.Fprintln(os.Stderr, "usage: ws-debug <ws-url>")
18+
os.Exit(1)
19+
}
20+
url := os.Args[1]
21+
fmt.Printf("Connecting to %s\n", url)
22+
23+
conn, _, err := websocket.DefaultDialer.Dial(url, nil)
24+
if err != nil {
25+
fmt.Printf("DIAL ERROR: %v\n", err)
26+
os.Exit(1)
27+
}
28+
defer conn.Close()
29+
fmt.Println("Connected!")
30+
31+
// Read initial messages for 3 seconds (look for Target.targetCreated)
32+
conn.SetReadDeadline(time.Now().Add(3 * time.Second))
33+
fmt.Println("\n=== Reading initial messages (3s) ===")
34+
var targetID string
35+
for i := 0; i < 20; i++ {
36+
_, data, err := conn.ReadMessage()
37+
if err != nil {
38+
fmt.Printf(" Read stopped after %d messages: %v\n", i, err)
39+
break
40+
}
41+
fmt.Printf(" Message %d: %s\n", i, string(data))
42+
var msg struct {
43+
Method string `json:"method"`
44+
Params json.RawMessage `json:"params"`
45+
}
46+
if json.Unmarshal(data, &msg) == nil && msg.Method == "Target.targetCreated" {
47+
var p struct {
48+
TargetInfo struct {
49+
TargetID string `json:"targetId"`
50+
Type string `json:"type"`
51+
} `json:"targetInfo"`
52+
}
53+
json.Unmarshal(msg.Params, &p)
54+
fmt.Printf(" >>> TARGET: id=%s type=%s\n", p.TargetInfo.TargetID, p.TargetInfo.Type)
55+
if p.TargetInfo.Type == "page" {
56+
targetID = p.TargetInfo.TargetID
57+
}
58+
}
59+
}
60+
61+
// Reset deadline
62+
conn.SetReadDeadline(time.Time{})
63+
64+
// Try direct Runtime.evaluate (no Target wrapping)
65+
fmt.Println("\n=== Direct Runtime.evaluate (no Target wrapping) ===")
66+
direct := map[string]interface{}{
67+
"id": 1,
68+
"method": "Runtime.evaluate",
69+
"params": map[string]interface{}{"expression": "1+1", "returnByValue": true},
70+
}
71+
conn.WriteJSON(direct)
72+
conn.SetReadDeadline(time.Now().Add(3 * time.Second))
73+
_, data, err := conn.ReadMessage()
74+
if err != nil {
75+
fmt.Printf(" No response: %v\n", err)
76+
} else {
77+
fmt.Printf(" Response: %s\n", string(data))
78+
}
79+
conn.SetReadDeadline(time.Time{})
80+
81+
// Try with Target wrapping if we have a targetID
82+
if targetID != "" {
83+
fmt.Printf("\n=== Target-wrapped Runtime.evaluate (targetId=%s) ===\n", targetID)
84+
inner, _ := json.Marshal(map[string]interface{}{
85+
"id": 2,
86+
"method": "Runtime.evaluate",
87+
"params": map[string]interface{}{"expression": "1+1", "returnByValue": true},
88+
})
89+
wrapped := map[string]interface{}{
90+
"id": 3,
91+
"method": "Target.sendMessageToTarget",
92+
"params": map[string]string{
93+
"targetId": targetID,
94+
"message": string(inner),
95+
},
96+
}
97+
conn.WriteJSON(wrapped)
98+
conn.SetReadDeadline(time.Now().Add(3 * time.Second))
99+
for i := 0; i < 5; i++ {
100+
_, data, err := conn.ReadMessage()
101+
if err != nil {
102+
fmt.Printf(" Read stopped: %v\n", err)
103+
break
104+
}
105+
fmt.Printf(" Response %d: %s\n", i, string(data))
106+
}
107+
} else {
108+
fmt.Println("\n=== No targetId received — cannot test Target wrapping ===")
109+
}
110+
111+
fmt.Println("\nDone.")
112+
}

0 commit comments

Comments
 (0)