func (tx *tx) readbody(ctx context.Context) error {
	doc, err := tx.client.DOM.GetDocument(ctx, nil)
	if err != nil {
		return fmt.Errorf("antcdp: get document - %w", err)
	}
	args := dom.GetOuterHTMLArgs{}
	args.NodeID = &doc.Root.NodeID
	reply, err := tx.client.DOM.GetOuterHTML(ctx, &args)
	if err != nil {
		return fmt.Errorf("antcdp: outer html - %w", err)
	}
	if tx.resp.Header == nil {
		tx.resp.Header = make(http.Header)
	}
	var (
		content = reply.OuterHTML
		size    = len(content)
		length  = strconv.Itoa(size)
		body    = ioutil.NopCloser(strings.NewReader(content))
	)
	tx.resp.Body = body
	tx.resp.ContentLength = int64(size)
	tx.resp.Header.Set("Content-Length", length)
	return nil
}
Readbody attempts to read the page's body.
package antcdp
import (
	"context"
	"encoding/json"
	"fmt"
	"io"
	"io/ioutil"
	"net/http"
	"strconv"
	"strings"
	"github.com/hashicorp/go-multierror"
	"github.com/mafredri/cdp"
	"github.com/mafredri/cdp/devtool"
	"github.com/mafredri/cdp/protocol/dom"
	"github.com/mafredri/cdp/protocol/network"
	"github.com/mafredri/cdp/protocol/page"
	"github.com/mafredri/cdp/protocol/storage"
	"github.com/mafredri/cdp/rpcc"
)
type tx struct {
	target  *devtool.Target
	request *http.Request
	resp    *http.Response
	conn    *rpcc.Conn
	client  *cdp.Client
	events  struct {
		req   network.RequestWillBeSentClient
		res   network.ResponseReceivedClient
		ready page.DOMContentEventFiredClient
	}
}
func (tx *tx) init(ctx context.Context) error {
	var url = tx.target.WebSocketDebuggerURL
	conn, err := rpcc.DialContext(ctx, url)
	if err != nil {
		return fmt.Errorf("antcdp: dial %q - %w", url, err)
	}
	tx.conn = conn
	tx.resp = &http.Response{Request: tx.request}
	tx.client = cdp.NewClient(conn)
	if err := tx.client.Page.Enable(ctx); err != nil {
		return err
	}
	if err := tx.client.Network.Enable(ctx, nil); err != nil {
		return err
	}
	if err := tx.setHeaders(ctx); err != nil {
		return err
	}
	if err := tx.setCookies(ctx); err != nil {
		return err
	}
	reqc, err := tx.client.Network.RequestWillBeSent(ctx)
	if err != nil {
		return err
	}
	resc, err := tx.client.Network.ResponseReceived(ctx)
	if err != nil {
		return err
	}
	ready, err := tx.client.Page.DOMContentEventFired(ctx)
	if err != nil {
		return err
	}
	tx.events.req = reqc
	tx.events.res = resc
	tx.events.ready = ready
	return nil
}
func (tx *tx) do(ctx context.Context) (*http.Response, error) {
	var args = page.NewNavigateArgs(tx.request.URL.String())
	reply, err := tx.client.Page.Navigate(ctx, args)
	if err != nil {
		return nil, fmt.Errorf("antcdp: navigate - %w", err)
	}
	if errmsg := reply.ErrorText; errmsg != nil {
		return nil, fmt.Errorf("antcdp: navigate - %s", *errmsg)
	}
	if err := tx.wait(ctx, *reply); err != nil {
		return nil, err
	}
	if _, err := tx.events.ready.Recv(); err != nil {
		return nil, fmt.Errorf("antcdp: dom ready - %w", err)
	}
	if err := tx.readbody(ctx); err != nil {
		return nil, err
	}
	if err := tx.readcookies(ctx); err != nil {
		return nil, err
	}
	return tx.resp, nil
}
func (tx *tx) wait(ctx context.Context, args page.NavigateReply) error {
	var ids = make(map[network.RequestID]struct{})
	var reqc = tx.events.req
	var resc = tx.events.res
	for {
		select {
		case <-reqc.Ready():
			event, err := reqc.Recv()
			if err != nil {
				return fmt.Errorf("antcdp: request recv - %w", err)
			}
			ids[event.RequestID] = struct{}{}
		case <-resc.Ready():
			event, err := resc.Recv()
			if err != nil {
				return fmt.Errorf("antcdp: response recv - %w", err)
			}
			if event.Type != network.ResourceTypeDocument {
				continue
			}
			if id := event.FrameID; id != nil && *id != args.FrameID {
				continue
			}
			if err := tx.merge(event.Response); err != nil {
				return fmt.Errorf("antcdp: merge response - %w", err)
			}
			delete(ids, event.RequestID)
			if len(ids) == 0 {
				return nil
			}
		case <-ctx.Done():
			return ctx.Err()
		}
	}
}