2019-03-05 13:14:50 +00:00
|
|
|
package chromedp
|
2017-01-24 15:09:23 +00:00
|
|
|
|
|
|
|
import (
|
2019-03-15 17:17:57 +00:00
|
|
|
"context"
|
2017-01-24 15:09:23 +00:00
|
|
|
"io"
|
2019-03-05 13:14:50 +00:00
|
|
|
"net"
|
|
|
|
"strings"
|
2017-01-24 15:09:23 +00:00
|
|
|
|
2019-03-15 17:17:57 +00:00
|
|
|
"github.com/chromedp/cdproto"
|
2017-01-24 15:09:23 +00:00
|
|
|
"github.com/gorilla/websocket"
|
|
|
|
)
|
|
|
|
|
2018-07-13 04:24:37 +00:00
|
|
|
var (
|
2017-01-24 15:09:23 +00:00
|
|
|
// DefaultReadBufferSize is the default maximum read buffer size.
|
|
|
|
DefaultReadBufferSize = 25 * 1024 * 1024
|
|
|
|
|
|
|
|
// DefaultWriteBufferSize is the default maximum write buffer size.
|
|
|
|
DefaultWriteBufferSize = 10 * 1024 * 1024
|
|
|
|
)
|
|
|
|
|
2018-07-13 04:24:37 +00:00
|
|
|
// Transport is the common interface to send/receive messages to a target.
|
2017-01-24 15:09:23 +00:00
|
|
|
type Transport interface {
|
2019-03-15 17:17:57 +00:00
|
|
|
Read() (*cdproto.Message, error)
|
|
|
|
Write(*cdproto.Message) error
|
2017-01-24 15:09:23 +00:00
|
|
|
io.Closer
|
|
|
|
}
|
|
|
|
|
|
|
|
// Conn wraps a gorilla/websocket.Conn connection.
|
|
|
|
type Conn struct {
|
|
|
|
*websocket.Conn
|
|
|
|
}
|
|
|
|
|
2019-03-05 13:14:50 +00:00
|
|
|
// Read reads the next message.
|
2019-03-15 17:17:57 +00:00
|
|
|
func (c *Conn) Read() (*cdproto.Message, error) {
|
|
|
|
msg := new(cdproto.Message)
|
|
|
|
if err := c.ReadJSON(msg); err != nil {
|
2017-01-24 15:09:23 +00:00
|
|
|
return nil, err
|
|
|
|
}
|
2019-03-15 17:17:57 +00:00
|
|
|
return msg, nil
|
2017-01-24 15:09:23 +00:00
|
|
|
}
|
|
|
|
|
2019-03-05 13:14:50 +00:00
|
|
|
// Write writes a message.
|
2019-03-15 17:17:57 +00:00
|
|
|
func (c *Conn) Write(msg *cdproto.Message) error {
|
|
|
|
return c.WriteJSON(msg)
|
2017-01-24 15:09:23 +00:00
|
|
|
}
|
|
|
|
|
2019-03-05 13:14:50 +00:00
|
|
|
// Dial dials the specified websocket URL using gorilla/websocket.
|
2019-03-15 17:17:57 +00:00
|
|
|
func DialContext(ctx context.Context, urlstr string) (*Conn, error) {
|
2017-01-24 15:09:23 +00:00
|
|
|
d := &websocket.Dialer{
|
|
|
|
ReadBufferSize: DefaultReadBufferSize,
|
|
|
|
WriteBufferSize: DefaultWriteBufferSize,
|
|
|
|
}
|
|
|
|
|
|
|
|
// connect
|
2019-03-15 17:17:57 +00:00
|
|
|
conn, _, err := d.DialContext(ctx, urlstr, nil)
|
2017-01-24 15:09:23 +00:00
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
|
|
|
|
return &Conn{conn}, nil
|
|
|
|
}
|
|
|
|
|
2019-03-05 13:14:50 +00:00
|
|
|
// ForceIP forces the host component in urlstr to be an IP address.
|
|
|
|
//
|
|
|
|
// Since Chrome 66+, Chrome DevTools Protocol clients connecting to a browser
|
|
|
|
// must send the "Host:" header as either an IP address, or "localhost".
|
|
|
|
func ForceIP(urlstr string) string {
|
|
|
|
if i := strings.Index(urlstr, "://"); i != -1 {
|
|
|
|
scheme := urlstr[:i+3]
|
|
|
|
host, port, path := urlstr[len(scheme)+3:], "", ""
|
|
|
|
if i := strings.Index(host, "/"); i != -1 {
|
|
|
|
host, path = host[:i], host[i:]
|
|
|
|
}
|
|
|
|
if i := strings.Index(host, ":"); i != -1 {
|
|
|
|
host, port = host[:i], host[i:]
|
|
|
|
}
|
|
|
|
if addr, err := net.ResolveIPAddr("ip", host); err == nil {
|
|
|
|
urlstr = scheme + addr.IP.String() + port + path
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return urlstr
|
|
|
|
}
|