mirror of
https://github.com/MontFerret/ferret.git
synced 2024-12-12 11:15:14 +02:00
Feature/#360 default driver params (#372)
* Added default headers and cookies * wip * Added tests * Added default headers and cookies to HTTP driver * Removed unused struct prop
This commit is contained in:
parent
4b1633269a
commit
9b762d32ee
@ -60,12 +60,108 @@ func (r *Runner) Run(ctx context.Context) error {
|
||||
cdp.NewDriver(cdp.WithAddress(r.settings.CDPAddress)),
|
||||
)
|
||||
|
||||
ctx = drivers.WithContext(
|
||||
ctx,
|
||||
cdp.NewDriver(cdp.WithAddress(r.settings.CDPAddress),
|
||||
cdp.WithCustomName("cdp_headers"),
|
||||
cdp.WithHeader("Single_header", []string{"single_header_value"}),
|
||||
cdp.WithHeaders(drivers.HTTPHeaders{
|
||||
"Multi_set_header": []string{"multi_set_header_value"},
|
||||
"Multi_set_header2": []string{"multi_set_header2_value"},
|
||||
}),
|
||||
),
|
||||
)
|
||||
|
||||
ctx = drivers.WithContext(
|
||||
ctx,
|
||||
cdp.NewDriver(cdp.WithAddress(r.settings.CDPAddress),
|
||||
cdp.WithCustomName("cdp_cookies"),
|
||||
cdp.WithCookie(drivers.HTTPCookie{
|
||||
Name: "single_cookie",
|
||||
Value: "single_cookie_value",
|
||||
Path: "/",
|
||||
MaxAge: 0,
|
||||
Secure: false,
|
||||
HTTPOnly: false,
|
||||
SameSite: 0,
|
||||
}),
|
||||
cdp.WithCookies([]drivers.HTTPCookie{
|
||||
{
|
||||
Name: "multi_set_cookie",
|
||||
Value: "multi_set_cookie_value",
|
||||
Path: "/",
|
||||
MaxAge: 0,
|
||||
Secure: false,
|
||||
HTTPOnly: false,
|
||||
SameSite: 0,
|
||||
},
|
||||
{
|
||||
Name: "multi_set_cookie2",
|
||||
Value: "multi_set_cookie2_value",
|
||||
Path: "/",
|
||||
MaxAge: 0,
|
||||
Secure: false,
|
||||
HTTPOnly: false,
|
||||
SameSite: 0,
|
||||
},
|
||||
}),
|
||||
),
|
||||
)
|
||||
|
||||
ctx = drivers.WithContext(
|
||||
ctx,
|
||||
http.NewDriver(),
|
||||
drivers.AsDefault(),
|
||||
)
|
||||
|
||||
ctx = drivers.WithContext(
|
||||
ctx,
|
||||
http.NewDriver(
|
||||
http.WithCustomName("http_headers"),
|
||||
http.WithHeader("Single_header", []string{"single_header_value"}),
|
||||
http.WithHeaders(drivers.HTTPHeaders{
|
||||
"Multi_set_header": []string{"multi_set_header_value"},
|
||||
"Multi_set_header2": []string{"multi_set_header2_value"},
|
||||
}),
|
||||
),
|
||||
)
|
||||
|
||||
ctx = drivers.WithContext(
|
||||
ctx,
|
||||
http.NewDriver(
|
||||
http.WithCustomName("http_cookies"),
|
||||
http.WithCookie(drivers.HTTPCookie{
|
||||
Name: "single_cookie",
|
||||
Value: "single_cookie_value",
|
||||
Path: "/",
|
||||
MaxAge: 0,
|
||||
Secure: false,
|
||||
HTTPOnly: false,
|
||||
SameSite: 0,
|
||||
}),
|
||||
http.WithCookies([]drivers.HTTPCookie{
|
||||
{
|
||||
Name: "multi_set_cookie",
|
||||
Value: "multi_set_cookie_value",
|
||||
Path: "/",
|
||||
MaxAge: 0,
|
||||
Secure: false,
|
||||
HTTPOnly: false,
|
||||
SameSite: 0,
|
||||
},
|
||||
{
|
||||
Name: "multi_set_cookie2",
|
||||
Value: "multi_set_cookie2_value",
|
||||
Path: "/",
|
||||
MaxAge: 0,
|
||||
Secure: false,
|
||||
HTTPOnly: false,
|
||||
SameSite: 0,
|
||||
},
|
||||
}),
|
||||
),
|
||||
)
|
||||
|
||||
results, err := r.runQueries(ctx, r.settings.Dir)
|
||||
|
||||
if err != nil {
|
||||
|
@ -54,6 +54,18 @@ func New(settings Settings) *Server {
|
||||
headers = string(b)
|
||||
}
|
||||
|
||||
var cookies string
|
||||
|
||||
if len(ctx.Request().Cookies()) > 0 {
|
||||
b, err := json.Marshal(ctx.Request().Cookies())
|
||||
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
cookies = string(b)
|
||||
}
|
||||
|
||||
ts := time.Now().Format("2006-01-02 15:04:05")
|
||||
|
||||
return ctx.HTML(http.StatusOK, fmt.Sprintf(`
|
||||
@ -65,9 +77,10 @@ func New(settings Settings) *Server {
|
||||
<body>
|
||||
<span id="timestamp">%s</span>
|
||||
<span id="headers">%s</span>
|
||||
<span id="cookies">%s</span>
|
||||
</body>
|
||||
</html>
|
||||
`, ts, headers))
|
||||
`, ts, headers, cookies))
|
||||
})
|
||||
api.GET("/ping", func(ctx echo.Context) error {
|
||||
return ctx.JSON(http.StatusOK, echo.Map{
|
||||
|
21
e2e/tests/dynamic/doc/cookies/default.fql
Normal file
21
e2e/tests/dynamic/doc/cookies/default.fql
Normal file
@ -0,0 +1,21 @@
|
||||
LET url = @static + "/api/ts"
|
||||
LET page = DOCUMENT(url, {
|
||||
driver: "cdp_cookies"
|
||||
})
|
||||
|
||||
LET el = ELEMENT(page, "#cookies")
|
||||
LET actual = (
|
||||
FOR c IN JSON_PARSE(el.innerText)
|
||||
SORT c.Name
|
||||
RETURN c
|
||||
)
|
||||
|
||||
LET expected = {
|
||||
"Single_cookie": "single_cookie_value",
|
||||
"Multi_set_cookie": "multi_set_cookie_value",
|
||||
}
|
||||
|
||||
RETURN EXPECT(expected, {
|
||||
"Single_cookie": actual[2].Value,
|
||||
"Multi_set_cookie": actual[0].Value,
|
||||
})
|
31
e2e/tests/dynamic/doc/cookies/override_default.fql
Normal file
31
e2e/tests/dynamic/doc/cookies/override_default.fql
Normal file
@ -0,0 +1,31 @@
|
||||
LET url = @static + "/api/ts"
|
||||
LET page = DOCUMENT(url, {
|
||||
driver: "cdp_cookies",
|
||||
cookies: [
|
||||
{
|
||||
name: "Single_cookie",
|
||||
value: "Foo"
|
||||
},
|
||||
{
|
||||
name: "Multi_set_cookie",
|
||||
value: "Bar"
|
||||
}
|
||||
]
|
||||
})
|
||||
|
||||
LET el = ELEMENT(page, "#cookies")
|
||||
LET actual = (
|
||||
FOR c IN JSON_PARSE(el.innerText)
|
||||
SORT c.Name
|
||||
RETURN c
|
||||
)
|
||||
|
||||
LET expected = {
|
||||
"Single_cookie": "Foo",
|
||||
"Multi_set_cookie": "Bar",
|
||||
}
|
||||
|
||||
RETURN EXPECT(expected, {
|
||||
"Single_cookie": actual[1].Value,
|
||||
"Multi_set_cookie": actual[0].Value,
|
||||
})
|
17
e2e/tests/dynamic/doc/headers/default.fql
Normal file
17
e2e/tests/dynamic/doc/headers/default.fql
Normal file
@ -0,0 +1,17 @@
|
||||
LET url = @static + "/api/ts"
|
||||
LET page = DOCUMENT(url, {
|
||||
driver: "cdp_headers"
|
||||
})
|
||||
|
||||
LET el = ELEMENT(page, "#headers")
|
||||
LET actual = JSON_PARSE(el.innerText)
|
||||
|
||||
LET expected = {
|
||||
"Single_header": ["single_header_value"],
|
||||
"Multi_set_header":["multi_set_header_value"],
|
||||
}
|
||||
|
||||
RETURN EXPECT(expected, {
|
||||
"Single_header": actual["Single_header"],
|
||||
"Multi_set_header": actual["Multi_set_header"],
|
||||
})
|
20
e2e/tests/dynamic/doc/headers/override_default.fql
Normal file
20
e2e/tests/dynamic/doc/headers/override_default.fql
Normal file
@ -0,0 +1,20 @@
|
||||
LET url = @static + "/api/ts"
|
||||
LET page = DOCUMENT(url, {
|
||||
driver: "cdp_headers",
|
||||
headers: {
|
||||
"single_header": "foo"
|
||||
}
|
||||
})
|
||||
|
||||
LET el = ELEMENT(page, "#headers")
|
||||
LET actual = JSON_PARSE(el.innerText)
|
||||
|
||||
LET expected = {
|
||||
"Single_header": ["foo"],
|
||||
"Multi_set_header":["multi_set_header_value"],
|
||||
}
|
||||
|
||||
RETURN EXPECT(expected, {
|
||||
"Single_header": actual["Single_header"],
|
||||
"Multi_set_header": actual["Multi_set_header"],
|
||||
})
|
21
e2e/tests/static/doc/cookies/default.fql
Normal file
21
e2e/tests/static/doc/cookies/default.fql
Normal file
@ -0,0 +1,21 @@
|
||||
LET url = @static + "/api/ts"
|
||||
LET page = DOCUMENT(url, {
|
||||
driver: "http_cookies"
|
||||
})
|
||||
|
||||
LET el = ELEMENT(page, "#cookies")
|
||||
LET actual = (
|
||||
FOR c IN JSON_PARSE(el.innerText)
|
||||
SORT c.Name
|
||||
RETURN c
|
||||
)
|
||||
|
||||
LET expected = {
|
||||
"Single_cookie": "single_cookie_value",
|
||||
"Multi_set_cookie": "multi_set_cookie_value",
|
||||
}
|
||||
|
||||
RETURN EXPECT(expected, {
|
||||
"Single_cookie": actual[2].Value,
|
||||
"Multi_set_cookie": actual[0].Value,
|
||||
})
|
10
e2e/tests/static/doc/cookies/get.fql
Normal file
10
e2e/tests/static/doc/cookies/get.fql
Normal file
@ -0,0 +1,10 @@
|
||||
LET url = @static + "/api/ts"
|
||||
LET doc = DOCUMENT(url, {
|
||||
driver: "http"
|
||||
})
|
||||
|
||||
LET cookiesPath = LENGTH(doc.cookies) > 0 ? "ok" : "false"
|
||||
LET cookie = COOKIE_GET(doc, "x-ferret")
|
||||
LET expected = "ok e2e"
|
||||
|
||||
RETURN EXPECT(expected, cookiesPath + " " + cookie.value)
|
31
e2e/tests/static/doc/cookies/override_default.fql
Normal file
31
e2e/tests/static/doc/cookies/override_default.fql
Normal file
@ -0,0 +1,31 @@
|
||||
LET url = @static + "/api/ts"
|
||||
LET page = DOCUMENT(url, {
|
||||
driver: "http_cookies",
|
||||
cookies: [
|
||||
{
|
||||
name: "Single_cookie",
|
||||
value: "Foo"
|
||||
},
|
||||
{
|
||||
name: "Multi_set_cookie",
|
||||
value: "Bar"
|
||||
}
|
||||
]
|
||||
})
|
||||
|
||||
LET el = ELEMENT(page, "#cookies")
|
||||
LET actual = (
|
||||
FOR c IN JSON_PARSE(el.innerText)
|
||||
SORT c.Name
|
||||
RETURN c
|
||||
)
|
||||
|
||||
LET expected = {
|
||||
"Single_cookie": "Foo",
|
||||
"Multi_set_cookie": "Bar",
|
||||
}
|
||||
|
||||
RETURN EXPECT(expected, {
|
||||
"Single_cookie": actual[1].Value,
|
||||
"Multi_set_cookie": actual[0].Value,
|
||||
})
|
17
e2e/tests/static/doc/headers/default.fql
Normal file
17
e2e/tests/static/doc/headers/default.fql
Normal file
@ -0,0 +1,17 @@
|
||||
LET url = @static + "/api/ts"
|
||||
LET page = DOCUMENT(url, {
|
||||
driver: "http_headers"
|
||||
})
|
||||
|
||||
LET el = ELEMENT(page, "#headers")
|
||||
LET actual = JSON_PARSE(el.innerText)
|
||||
|
||||
LET expected = {
|
||||
"Single_header": ["single_header_value"],
|
||||
"Multi_set_header":["multi_set_header_value"],
|
||||
}
|
||||
|
||||
RETURN EXPECT(expected, {
|
||||
"Single_header": actual["Single_header"],
|
||||
"Multi_set_header": actual["Multi_set_header"],
|
||||
})
|
20
e2e/tests/static/doc/headers/override_default.fql
Normal file
20
e2e/tests/static/doc/headers/override_default.fql
Normal file
@ -0,0 +1,20 @@
|
||||
LET url = @static + "/api/ts"
|
||||
LET page = DOCUMENT(url, {
|
||||
driver: "http_headers",
|
||||
headers: {
|
||||
"single_header": "foo"
|
||||
}
|
||||
})
|
||||
|
||||
LET el = ELEMENT(page, "#headers")
|
||||
LET actual = JSON_PARSE(el.innerText)
|
||||
|
||||
LET expected = {
|
||||
"Single_header": ["foo"],
|
||||
"Multi_set_header":["multi_set_header_value"],
|
||||
}
|
||||
|
||||
RETURN EXPECT(expected, {
|
||||
"Single_header": actual["Single_header"],
|
||||
"Multi_set_header": actual["Multi_set_header"],
|
||||
})
|
@ -107,6 +107,34 @@ func (drv *Driver) Open(ctx context.Context, params drivers.Params) (drivers.HTM
|
||||
params.Viewport = defaultViewport
|
||||
}
|
||||
|
||||
if drv.options.Headers != nil && params.Headers == nil {
|
||||
params.Headers = make(drivers.HTTPHeaders)
|
||||
}
|
||||
|
||||
// set default headers
|
||||
for k, v := range drv.options.Headers {
|
||||
_, exists := params.Headers[k]
|
||||
|
||||
// do not override user's set values
|
||||
if !exists {
|
||||
params.Headers[k] = v
|
||||
}
|
||||
}
|
||||
|
||||
if drv.options.Cookies != nil && params.Cookies == nil {
|
||||
params.Cookies = make(drivers.HTTPCookies)
|
||||
}
|
||||
|
||||
// set default cookies
|
||||
for k, v := range drv.options.Cookies {
|
||||
_, exists := params.Cookies[k]
|
||||
|
||||
// do not override user's set values
|
||||
if !exists {
|
||||
params.Cookies[k] = v
|
||||
}
|
||||
}
|
||||
|
||||
return LoadHTMLPage(ctx, conn, params)
|
||||
}
|
||||
|
||||
|
@ -1,5 +1,7 @@
|
||||
package cdp
|
||||
|
||||
import "github.com/MontFerret/ferret/pkg/drivers"
|
||||
|
||||
type (
|
||||
Options struct {
|
||||
Name string
|
||||
@ -7,6 +9,8 @@ type (
|
||||
UserAgent string
|
||||
Address string
|
||||
KeepCookies bool
|
||||
Headers drivers.HTTPHeaders
|
||||
Cookies drivers.HTTPCookies
|
||||
}
|
||||
|
||||
Option func(opts *Options)
|
||||
@ -57,3 +61,47 @@ func WithCustomName(name string) Option {
|
||||
opts.Name = name
|
||||
}
|
||||
}
|
||||
|
||||
func WithHeader(name string, value []string) Option {
|
||||
return func(opts *Options) {
|
||||
if opts.Headers == nil {
|
||||
opts.Headers = make(drivers.HTTPHeaders)
|
||||
}
|
||||
|
||||
opts.Headers[name] = value
|
||||
}
|
||||
}
|
||||
|
||||
func WithHeaders(headers drivers.HTTPHeaders) Option {
|
||||
return func(opts *Options) {
|
||||
if opts.Headers == nil {
|
||||
opts.Headers = make(drivers.HTTPHeaders)
|
||||
}
|
||||
|
||||
for k, v := range headers {
|
||||
opts.Headers[k] = v
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func WithCookie(cookie drivers.HTTPCookie) Option {
|
||||
return func(opts *Options) {
|
||||
if opts.Cookies == nil {
|
||||
opts.Cookies = make(drivers.HTTPCookies)
|
||||
}
|
||||
|
||||
opts.Cookies[cookie.Name] = cookie
|
||||
}
|
||||
}
|
||||
|
||||
func WithCookies(cookies []drivers.HTTPCookie) Option {
|
||||
return func(opts *Options) {
|
||||
if opts.Cookies == nil {
|
||||
opts.Cookies = make(drivers.HTTPCookies)
|
||||
}
|
||||
|
||||
for _, c := range cookies {
|
||||
opts.Cookies[c.Name] = c
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -143,7 +143,7 @@ func LoadHTMLPage(
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if params.Cookies != nil {
|
||||
if len(params.Cookies) > 0 {
|
||||
cookies := make([]network.CookieParam, 0, len(params.Cookies))
|
||||
|
||||
for _, c := range params.Cookies {
|
||||
@ -166,7 +166,7 @@ func LoadHTMLPage(
|
||||
}
|
||||
}
|
||||
|
||||
if params.Headers != nil {
|
||||
if len(params.Headers) > 0 {
|
||||
j, err := json.Marshal(params.Headers)
|
||||
|
||||
if err != nil {
|
||||
|
@ -30,6 +30,8 @@ type (
|
||||
HTTPOnly bool
|
||||
SameSite SameSite
|
||||
}
|
||||
|
||||
HTTPCookies map[string]HTTPCookie
|
||||
)
|
||||
|
||||
const (
|
||||
|
@ -26,7 +26,7 @@ func NewDriver(opts ...Option) *Driver {
|
||||
drv := new(Driver)
|
||||
drv.options = newOptions(opts)
|
||||
|
||||
if drv.options.proxy == "" {
|
||||
if drv.options.Proxy == "" {
|
||||
drv.client = pester.New()
|
||||
} else {
|
||||
client, err := newClientWithProxy(drv.options)
|
||||
@ -38,15 +38,15 @@ func NewDriver(opts ...Option) *Driver {
|
||||
}
|
||||
}
|
||||
|
||||
drv.client.Concurrency = drv.options.concurrency
|
||||
drv.client.MaxRetries = drv.options.maxRetries
|
||||
drv.client.Backoff = drv.options.backoff
|
||||
drv.client.Concurrency = drv.options.Concurrency
|
||||
drv.client.MaxRetries = drv.options.MaxRetries
|
||||
drv.client.Backoff = drv.options.Backoff
|
||||
|
||||
return drv
|
||||
}
|
||||
|
||||
func newClientWithProxy(options *Options) (*http.Client, error) {
|
||||
proxyURL, err := url.Parse(options.proxy)
|
||||
proxyURL, err := url.Parse(options.Proxy)
|
||||
|
||||
if err != nil {
|
||||
return nil, err
|
||||
@ -59,7 +59,7 @@ func newClientWithProxy(options *Options) (*http.Client, error) {
|
||||
}
|
||||
|
||||
func (drv *Driver) Name() string {
|
||||
return DriverName
|
||||
return drv.options.Name
|
||||
}
|
||||
|
||||
func (drv *Driver) Open(ctx context.Context, params drivers.Params) (drivers.HTMLPage, error) {
|
||||
@ -76,33 +76,54 @@ func (drv *Driver) Open(ctx context.Context, params drivers.Params) (drivers.HTM
|
||||
req.Header.Set("Cache-Control", "no-cache")
|
||||
req.Header.Set("Pragma", "no-cache")
|
||||
|
||||
if params.Headers != nil {
|
||||
for k := range params.Headers {
|
||||
req.Header.Add(k, params.Headers.Get(k))
|
||||
if drv.options.Headers != nil && params.Headers == nil {
|
||||
params.Headers = make(drivers.HTTPHeaders)
|
||||
}
|
||||
|
||||
logger.
|
||||
Debug().
|
||||
Timestamp().
|
||||
Str("header", k).
|
||||
Msg("set header")
|
||||
// Set default headers
|
||||
for k, v := range drv.options.Headers {
|
||||
_, exists := params.Headers[k]
|
||||
|
||||
// do not override user's set values
|
||||
if !exists {
|
||||
params.Headers[k] = v
|
||||
}
|
||||
}
|
||||
|
||||
if params.Cookies != nil {
|
||||
for _, c := range params.Cookies {
|
||||
req.AddCookie(&http.Cookie{
|
||||
Name: c.Name,
|
||||
Value: c.Value,
|
||||
})
|
||||
for k := range params.Headers {
|
||||
req.Header.Add(k, params.Headers.Get(k))
|
||||
|
||||
logger.
|
||||
Debug().
|
||||
Timestamp().
|
||||
Str("cookie", c.Name).
|
||||
Msg("set cookie")
|
||||
logger.
|
||||
Debug().
|
||||
Timestamp().
|
||||
Str("header", k).
|
||||
Msg("set header")
|
||||
}
|
||||
|
||||
if drv.options.Cookies != nil && params.Cookies == nil {
|
||||
params.Cookies = make(drivers.HTTPCookies)
|
||||
}
|
||||
|
||||
// set default cookies
|
||||
for k, v := range drv.options.Cookies {
|
||||
_, exists := params.Cookies[k]
|
||||
|
||||
// do not override user's set values
|
||||
if !exists {
|
||||
params.Cookies[k] = v
|
||||
}
|
||||
}
|
||||
|
||||
for _, c := range params.Cookies {
|
||||
req.AddCookie(fromDriverCookie(c))
|
||||
|
||||
logger.
|
||||
Debug().
|
||||
Timestamp().
|
||||
Str("cookie", c.Name).
|
||||
Msg("set cookie")
|
||||
}
|
||||
|
||||
req = req.WithContext(ctx)
|
||||
|
||||
var ua string
|
||||
@ -110,7 +131,7 @@ func (drv *Driver) Open(ctx context.Context, params drivers.Params) (drivers.HTM
|
||||
if params.UserAgent != "" {
|
||||
ua = common.GetUserAgent(params.UserAgent)
|
||||
} else {
|
||||
ua = common.GetUserAgent(drv.options.userAgent)
|
||||
ua = common.GetUserAgent(drv.options.UserAgent)
|
||||
}
|
||||
|
||||
logger.
|
||||
@ -141,7 +162,13 @@ func (drv *Driver) Open(ctx context.Context, params drivers.Params) (drivers.HTM
|
||||
return nil, errors.Wrapf(err, "failed to parse a document %s", params.URL)
|
||||
}
|
||||
|
||||
return NewHTMLPage(doc, params.URL, params.Cookies)
|
||||
cookies, err := toDriverCookies(resp.Cookies())
|
||||
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return NewHTMLPage(doc, params.URL, cookies)
|
||||
}
|
||||
|
||||
func (drv *Driver) Parse(_ context.Context, str values.String) (drivers.HTMLPage, error) {
|
||||
|
@ -2,14 +2,16 @@ package http
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"golang.org/x/net/html"
|
||||
|
||||
"github.com/MontFerret/ferret/pkg/runtime/core"
|
||||
"github.com/MontFerret/ferret/pkg/runtime/values"
|
||||
HTTP "net/http"
|
||||
|
||||
"github.com/PuerkitoBio/goquery"
|
||||
"github.com/antchfx/htmlquery"
|
||||
"github.com/antchfx/xpath"
|
||||
"golang.org/x/net/html"
|
||||
|
||||
"github.com/MontFerret/ferret/pkg/drivers"
|
||||
"github.com/MontFerret/ferret/pkg/runtime/core"
|
||||
"github.com/MontFerret/ferret/pkg/runtime/values"
|
||||
)
|
||||
|
||||
func parseXPathNode(nav *htmlquery.NodeNavigator) (core.Value, error) {
|
||||
@ -45,3 +47,71 @@ func outerHTML(s *goquery.Selection) (string, error) {
|
||||
|
||||
return buf.String(), nil
|
||||
}
|
||||
|
||||
func toDriverCookies(cookies []*HTTP.Cookie) (drivers.HTTPCookies, error) {
|
||||
res := make(drivers.HTTPCookies)
|
||||
|
||||
for _, c := range cookies {
|
||||
dc, err := toDriverCookie(c)
|
||||
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
res[dc.Name] = dc
|
||||
}
|
||||
|
||||
return res, nil
|
||||
}
|
||||
|
||||
func toDriverCookie(cookie *HTTP.Cookie) (drivers.HTTPCookie, error) {
|
||||
res := drivers.HTTPCookie{}
|
||||
|
||||
if cookie == nil {
|
||||
return res, core.Error(core.ErrMissedArgument, "cookie")
|
||||
}
|
||||
|
||||
res.Name = cookie.Name
|
||||
res.Value = cookie.Value
|
||||
res.Path = cookie.Path
|
||||
res.Domain = cookie.Domain
|
||||
res.Expires = cookie.Expires
|
||||
res.MaxAge = cookie.MaxAge
|
||||
res.Secure = cookie.Secure
|
||||
res.HTTPOnly = cookie.HttpOnly
|
||||
|
||||
switch cookie.SameSite {
|
||||
case HTTP.SameSiteLaxMode:
|
||||
res.SameSite = drivers.SameSiteLaxMode
|
||||
case HTTP.SameSiteStrictMode:
|
||||
res.SameSite = drivers.SameSiteStrictMode
|
||||
default:
|
||||
res.SameSite = drivers.SameSiteDefaultMode
|
||||
}
|
||||
|
||||
return res, nil
|
||||
}
|
||||
|
||||
func fromDriverCookie(cookie drivers.HTTPCookie) *HTTP.Cookie {
|
||||
res := &HTTP.Cookie{}
|
||||
|
||||
res.Name = cookie.Name
|
||||
res.Value = cookie.Value
|
||||
res.Path = cookie.Path
|
||||
res.Domain = cookie.Domain
|
||||
res.Expires = cookie.Expires
|
||||
res.MaxAge = cookie.MaxAge
|
||||
res.Secure = cookie.Secure
|
||||
res.HttpOnly = cookie.HTTPOnly
|
||||
|
||||
switch cookie.SameSite {
|
||||
case drivers.SameSiteLaxMode:
|
||||
res.SameSite = HTTP.SameSiteLaxMode
|
||||
case drivers.SameSiteStrictMode:
|
||||
res.SameSite = HTTP.SameSiteStrictMode
|
||||
default:
|
||||
res.SameSite = HTTP.SameSiteDefaultMode
|
||||
}
|
||||
|
||||
return res
|
||||
}
|
||||
|
@ -1,6 +1,7 @@
|
||||
package http
|
||||
|
||||
import (
|
||||
"github.com/MontFerret/ferret/pkg/drivers"
|
||||
"github.com/sethgrid/pester"
|
||||
)
|
||||
|
||||
@ -8,19 +9,23 @@ type (
|
||||
Option func(opts *Options)
|
||||
|
||||
Options struct {
|
||||
backoff pester.BackoffStrategy
|
||||
maxRetries int
|
||||
concurrency int
|
||||
proxy string
|
||||
userAgent string
|
||||
Name string
|
||||
Backoff pester.BackoffStrategy
|
||||
MaxRetries int
|
||||
Concurrency int
|
||||
Proxy string
|
||||
UserAgent string
|
||||
Headers drivers.HTTPHeaders
|
||||
Cookies drivers.HTTPCookies
|
||||
}
|
||||
)
|
||||
|
||||
func newOptions(setters []Option) *Options {
|
||||
opts := new(Options)
|
||||
opts.backoff = pester.ExponentialBackoff
|
||||
opts.concurrency = 3
|
||||
opts.maxRetries = 5
|
||||
opts.Name = DriverName
|
||||
opts.Backoff = pester.ExponentialBackoff
|
||||
opts.Concurrency = 3
|
||||
opts.MaxRetries = 5
|
||||
|
||||
for _, setter := range setters {
|
||||
setter(opts)
|
||||
@ -31,42 +36,92 @@ func newOptions(setters []Option) *Options {
|
||||
|
||||
func WithDefaultBackoff() Option {
|
||||
return func(opts *Options) {
|
||||
opts.backoff = pester.DefaultBackoff
|
||||
opts.Backoff = pester.DefaultBackoff
|
||||
}
|
||||
}
|
||||
|
||||
func WithLinearBackoff() Option {
|
||||
return func(opts *Options) {
|
||||
opts.backoff = pester.LinearBackoff
|
||||
opts.Backoff = pester.LinearBackoff
|
||||
}
|
||||
}
|
||||
|
||||
func WithExponentialBackoff() Option {
|
||||
return func(opts *Options) {
|
||||
opts.backoff = pester.ExponentialBackoff
|
||||
opts.Backoff = pester.ExponentialBackoff
|
||||
}
|
||||
}
|
||||
|
||||
func WithMaxRetries(value int) Option {
|
||||
return func(opts *Options) {
|
||||
opts.maxRetries = value
|
||||
opts.MaxRetries = value
|
||||
}
|
||||
}
|
||||
|
||||
func WithConcurrency(value int) Option {
|
||||
return func(opts *Options) {
|
||||
opts.concurrency = value
|
||||
opts.Concurrency = value
|
||||
}
|
||||
}
|
||||
|
||||
func WithProxy(address string) Option {
|
||||
return func(opts *Options) {
|
||||
opts.proxy = address
|
||||
opts.Proxy = address
|
||||
}
|
||||
}
|
||||
|
||||
func WithUserAgent(value string) Option {
|
||||
return func(opts *Options) {
|
||||
opts.userAgent = value
|
||||
opts.UserAgent = value
|
||||
}
|
||||
}
|
||||
|
||||
func WithCustomName(name string) Option {
|
||||
return func(opts *Options) {
|
||||
opts.Name = name
|
||||
}
|
||||
}
|
||||
|
||||
func WithHeader(name string, value []string) Option {
|
||||
return func(opts *Options) {
|
||||
if opts.Headers == nil {
|
||||
opts.Headers = make(drivers.HTTPHeaders)
|
||||
}
|
||||
|
||||
opts.Headers[name] = value
|
||||
}
|
||||
}
|
||||
|
||||
func WithHeaders(headers drivers.HTTPHeaders) Option {
|
||||
return func(opts *Options) {
|
||||
if opts.Headers == nil {
|
||||
opts.Headers = make(drivers.HTTPHeaders)
|
||||
}
|
||||
|
||||
for k, v := range headers {
|
||||
opts.Headers[k] = v
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func WithCookie(cookie drivers.HTTPCookie) Option {
|
||||
return func(opts *Options) {
|
||||
if opts.Cookies == nil {
|
||||
opts.Cookies = make(drivers.HTTPCookies)
|
||||
}
|
||||
|
||||
opts.Cookies[cookie.Name] = cookie
|
||||
}
|
||||
}
|
||||
|
||||
func WithCookies(cookies []drivers.HTTPCookie) Option {
|
||||
return func(opts *Options) {
|
||||
if opts.Cookies == nil {
|
||||
opts.Cookies = make(drivers.HTTPCookies)
|
||||
}
|
||||
|
||||
for _, c := range cookies {
|
||||
opts.Cookies[c.Name] = c
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -2,24 +2,26 @@ package http
|
||||
|
||||
import (
|
||||
"context"
|
||||
"hash/fnv"
|
||||
|
||||
"github.com/PuerkitoBio/goquery"
|
||||
|
||||
"github.com/MontFerret/ferret/pkg/drivers"
|
||||
"github.com/MontFerret/ferret/pkg/drivers/common"
|
||||
"github.com/MontFerret/ferret/pkg/runtime/core"
|
||||
"github.com/MontFerret/ferret/pkg/runtime/values"
|
||||
"github.com/PuerkitoBio/goquery"
|
||||
"hash/fnv"
|
||||
)
|
||||
|
||||
type HTMLPage struct {
|
||||
document *HTMLDocument
|
||||
cookies []drivers.HTTPCookie
|
||||
cookies drivers.HTTPCookies
|
||||
frames *values.Array
|
||||
}
|
||||
|
||||
func NewHTMLPage(
|
||||
qdoc *goquery.Document,
|
||||
url string,
|
||||
cookies []drivers.HTTPCookie,
|
||||
cookies drivers.HTTPCookies,
|
||||
) (*HTMLPage, error) {
|
||||
doc, err := NewRootHTMLDocument(qdoc, url)
|
||||
|
||||
@ -79,7 +81,13 @@ func (p *HTMLPage) Hash() uint64 {
|
||||
}
|
||||
|
||||
func (p *HTMLPage) Copy() core.Value {
|
||||
page, err := NewHTMLPage(p.document.doc, p.document.GetURL().String(), p.cookies[:])
|
||||
cookies := make(drivers.HTTPCookies)
|
||||
|
||||
for k, v := range p.cookies {
|
||||
cookies[k] = v
|
||||
}
|
||||
|
||||
page, err := NewHTMLPage(p.document.doc, p.document.GetURL().String(), cookies)
|
||||
|
||||
if err != nil {
|
||||
return values.None
|
||||
|
@ -13,7 +13,7 @@ type (
|
||||
URL string
|
||||
UserAgent string
|
||||
KeepCookies bool
|
||||
Cookies []HTTPCookie
|
||||
Cookies HTTPCookies
|
||||
Headers HTTPHeaders
|
||||
Viewport *Viewport
|
||||
}
|
||||
|
@ -26,7 +26,7 @@ type PageLoadParams struct {
|
||||
// userAgent (String) - Optional, user agent.
|
||||
// keepCookies (Boolean) - Optional, boolean value indicating whether to use cookies from previous sessions.
|
||||
// i.e. not to open a page in the Incognito mode.
|
||||
// cookies (HTTPCookie) - Optional, set of HTTP cookies.
|
||||
// cookies (HTTPCookies) - Optional, set of HTTP cookies.
|
||||
// headers (HTTPHeaders) - Optional, HTTP headers.
|
||||
// viewport (Viewport) - Optional, viewport params.
|
||||
// @returns (HTMLPage) - Returns loaded HTML page.
|
||||
@ -134,17 +134,30 @@ func newPageLoadParams(url values.String, arg core.Value) (PageLoadParams, error
|
||||
cookies, exists := obj.Get(values.NewString("cookies"))
|
||||
|
||||
if exists {
|
||||
if err := core.ValidateType(cookies, types.Array); err != nil {
|
||||
if err := core.ValidateType(cookies, types.Array, types.Object); err != nil {
|
||||
return res, err
|
||||
}
|
||||
|
||||
cookies, err := parseCookies(cookies.(*values.Array))
|
||||
switch c := cookies.(type) {
|
||||
case *values.Array:
|
||||
cookies, err := parseCookieArray(c)
|
||||
|
||||
if err != nil {
|
||||
return res, err
|
||||
if err != nil {
|
||||
return res, err
|
||||
}
|
||||
|
||||
res.Cookies = cookies
|
||||
case *values.Object:
|
||||
cookies, err := parseCookieObject(c)
|
||||
|
||||
if err != nil {
|
||||
return res, err
|
||||
}
|
||||
|
||||
res.Cookies = cookies
|
||||
default:
|
||||
res.Cookies = make(drivers.HTTPCookies)
|
||||
}
|
||||
|
||||
res.Cookies = cookies
|
||||
}
|
||||
|
||||
headers, exists := obj.Get(values.NewString("headers"))
|
||||
@ -183,11 +196,11 @@ func newPageLoadParams(url values.String, arg core.Value) (PageLoadParams, error
|
||||
return res, nil
|
||||
}
|
||||
|
||||
func parseCookies(arr *values.Array) ([]drivers.HTTPCookie, error) {
|
||||
func parseCookieObject(obj *values.Object) (drivers.HTTPCookies, error) {
|
||||
var err error
|
||||
res := make([]drivers.HTTPCookie, 0, arr.Length())
|
||||
res := make(drivers.HTTPCookies)
|
||||
|
||||
arr.ForEach(func(value core.Value, idx int) bool {
|
||||
obj.ForEach(func(value core.Value, _ string) bool {
|
||||
cookie, e := parseCookie(value)
|
||||
|
||||
if e != nil {
|
||||
@ -196,7 +209,28 @@ func parseCookies(arr *values.Array) ([]drivers.HTTPCookie, error) {
|
||||
return false
|
||||
}
|
||||
|
||||
res = append(res, cookie)
|
||||
res[cookie.Name] = cookie
|
||||
|
||||
return true
|
||||
})
|
||||
|
||||
return res, err
|
||||
}
|
||||
|
||||
func parseCookieArray(arr *values.Array) (drivers.HTTPCookies, error) {
|
||||
var err error
|
||||
res := make(drivers.HTTPCookies)
|
||||
|
||||
arr.ForEach(func(value core.Value, _ int) bool {
|
||||
cookie, e := parseCookie(value)
|
||||
|
||||
if e != nil {
|
||||
err = e
|
||||
|
||||
return false
|
||||
}
|
||||
|
||||
res[cookie.Name] = cookie
|
||||
|
||||
return true
|
||||
})
|
||||
|
Loading…
Reference in New Issue
Block a user