1
0
mirror of https://github.com/MontFerret/ferret.git synced 2024-12-14 11:23:02 +02:00
ferret/pkg/drivers/cdp/driver.go
Tim Voronov 71c246dd17
Feature/#236 cookies (#242)
* Added KeepCookies option to CDP driver

* Added LoadDocumentParams

* Added COOKIE_GET and COOKIE_SET methods
2019-03-15 19:59:05 -04:00

224 lines
4.1 KiB
Go

package cdp
import (
"context"
"sync"
"github.com/MontFerret/ferret/pkg/drivers"
"github.com/MontFerret/ferret/pkg/drivers/common"
"github.com/MontFerret/ferret/pkg/runtime/logging"
"github.com/mafredri/cdp"
"github.com/mafredri/cdp/devtool"
"github.com/mafredri/cdp/protocol/emulation"
"github.com/mafredri/cdp/protocol/network"
"github.com/mafredri/cdp/protocol/page"
"github.com/mafredri/cdp/protocol/target"
"github.com/mafredri/cdp/rpcc"
"github.com/mafredri/cdp/session"
"github.com/pkg/errors"
)
const DriverName = "cdp"
type Driver struct {
sync.Mutex
dev *devtool.DevTools
conn *rpcc.Conn
client *cdp.Client
session *session.Manager
contextID target.BrowserContextID
options *Options
}
func NewDriver(opts ...Option) *Driver {
drv := new(Driver)
drv.options = newOptions(opts)
drv.dev = devtool.New(drv.options.Address)
return drv
}
func (drv *Driver) Name() string {
return drv.options.Name
}
func (drv *Driver) LoadDocument(ctx context.Context, params drivers.LoadDocumentParams) (drivers.HTMLDocument, error) {
logger := logging.FromContext(ctx)
err := drv.init(ctx)
if err != nil {
logger.
Error().
Timestamp().
Err(err).
Str("driver", drv.options.Name).
Msg("failed to initialize the driver")
return nil, err
}
url := params.URL
if url == "" {
url = BlankPageURL
}
// Create a new target belonging to the browser context
createTargetArgs := target.NewCreateTargetArgs(url)
if drv.options.KeepCookies == false && params.KeepCookies == false {
// Set it to an incognito mode
createTargetArgs.SetBrowserContextID(drv.contextID)
}
createTarget, err := drv.client.Target.CreateTarget(ctx, createTargetArgs)
if err != nil {
logger.
Error().
Timestamp().
Err(err).
Str("driver", drv.options.Name).
Msg("failed to create a browser target")
return nil, err
}
// Connect to target using the existing websocket connection.
conn, err := drv.session.Dial(ctx, createTarget.TargetID)
if err != nil {
logger.
Error().
Timestamp().
Err(err).
Str("driver", drv.options.Name).
Msg("failed to establish a connection")
return nil, err
}
client := cdp.NewClient(conn)
err = runBatch(
func() error {
return client.Page.Enable(ctx)
},
func() error {
return client.Page.SetLifecycleEventsEnabled(
ctx,
page.NewSetLifecycleEventsEnabledArgs(true),
)
},
func() error {
return client.DOM.Enable(ctx)
},
func() error {
return client.Runtime.Enable(ctx)
},
func() error {
var ua string
if params.UserAgent != "" {
ua = common.GetUserAgent(params.UserAgent)
} else {
ua = common.GetUserAgent(drv.options.UserAgent)
}
logger.
Debug().
Timestamp().
Str("user-agent", ua).
Msg("using User-Agent")
// do not use custom user agent
if ua == "" {
return nil
}
return client.Emulation.SetUserAgentOverride(
ctx,
emulation.NewSetUserAgentOverrideArgs(ua),
)
},
func() error {
return client.Network.Enable(ctx, network.NewEnableArgs())
},
)
if err != nil {
return nil, err
}
return LoadHTMLDocument(ctx, conn, client, params)
}
func (drv *Driver) Close() error {
drv.Lock()
defer drv.Unlock()
if drv.session != nil {
drv.session.Close()
return drv.conn.Close()
}
return nil
}
func (drv *Driver) init(ctx context.Context) error {
drv.Lock()
defer drv.Unlock()
if drv.session == nil {
ver, err := drv.dev.Version(ctx)
if err != nil {
return errors.Wrap(err, "failed to initialize driver")
}
bconn, err := rpcc.DialContext(ctx, ver.WebSocketDebuggerURL)
if err != nil {
return errors.Wrap(err, "failed to initialize driver")
}
bc := cdp.NewClient(bconn)
sess, err := session.NewManager(bc)
if err != nil {
bconn.Close()
return errors.Wrap(err, "failed to initialize driver")
}
drv.conn = bconn
drv.client = bc
drv.session = sess
if drv.options.KeepCookies {
return nil
}
createCtx, err := bc.Target.CreateBrowserContext(ctx)
if err != nil {
bconn.Close()
sess.Close()
return err
}
drv.contextID = createCtx.BrowserContextID
}
return nil
}