summaryrefslogtreecommitdiff
path: root/vendor/github.com/playwright-community/playwright-go/fetch.go
diff options
context:
space:
mode:
authormo khan <mo@mokhan.ca>2025-05-14 13:18:54 -0600
committermo khan <mo@mokhan.ca>2025-05-14 13:18:54 -0600
commit4b2d609a0efcc1d9b2f1a08f954d067ad1d9cd1e (patch)
tree0afacf9217b0569130da6b97d4197331681bf119 /vendor/github.com/playwright-community/playwright-go/fetch.go
parentab373d1fe698cd3f53258c09bc8515d88a6d0b9e (diff)
test: use playwright to test out an OIDC login
Diffstat (limited to 'vendor/github.com/playwright-community/playwright-go/fetch.go')
-rw-r--r--vendor/github.com/playwright-community/playwright-go/fetch.go451
1 files changed, 451 insertions, 0 deletions
diff --git a/vendor/github.com/playwright-community/playwright-go/fetch.go b/vendor/github.com/playwright-community/playwright-go/fetch.go
new file mode 100644
index 0000000..fc7f79f
--- /dev/null
+++ b/vendor/github.com/playwright-community/playwright-go/fetch.go
@@ -0,0 +1,451 @@
+package playwright
+
+import (
+ "encoding/base64"
+ "encoding/json"
+ "errors"
+ "fmt"
+ "os"
+ "strings"
+)
+
+type apiRequestImpl struct {
+ *Playwright
+}
+
+func (r *apiRequestImpl) NewContext(options ...APIRequestNewContextOptions) (APIRequestContext, error) {
+ overrides := map[string]interface{}{}
+ if len(options) == 1 {
+ if options[0].ClientCertificates != nil {
+ certs, err := transformClientCertificate(options[0].ClientCertificates)
+ if err != nil {
+ return nil, err
+ }
+ overrides["clientCertificates"] = certs
+ options[0].ClientCertificates = nil
+ }
+ if options[0].ExtraHttpHeaders != nil {
+ overrides["extraHTTPHeaders"] = serializeMapToNameAndValue(options[0].ExtraHttpHeaders)
+ options[0].ExtraHttpHeaders = nil
+ }
+ if options[0].StorageStatePath != nil {
+ var storageState *StorageState
+ storageString, err := os.ReadFile(*options[0].StorageStatePath)
+ if err != nil {
+ return nil, fmt.Errorf("could not read storage state file: %w", err)
+ }
+ err = json.Unmarshal(storageString, &storageState)
+ if err != nil {
+ return nil, fmt.Errorf("could not parse storage state file: %w", err)
+ }
+ options[0].StorageState = storageState
+ options[0].StorageStatePath = nil
+ }
+ }
+
+ channel, err := r.channel.Send("newRequest", options, overrides)
+ if err != nil {
+ return nil, err
+ }
+ return fromChannel(channel).(*apiRequestContextImpl), nil
+}
+
+func newApiRequestImpl(pw *Playwright) *apiRequestImpl {
+ return &apiRequestImpl{pw}
+}
+
+type apiRequestContextImpl struct {
+ channelOwner
+ tracing *tracingImpl
+ closeReason *string
+}
+
+func (r *apiRequestContextImpl) Dispose(options ...APIRequestContextDisposeOptions) error {
+ if len(options) == 1 {
+ r.closeReason = options[0].Reason
+ }
+ _, err := r.channel.Send("dispose", map[string]interface{}{
+ "reason": r.closeReason,
+ })
+ if errors.Is(err, ErrTargetClosed) {
+ return nil
+ }
+ return err
+}
+
+func (r *apiRequestContextImpl) Delete(url string, options ...APIRequestContextDeleteOptions) (APIResponse, error) {
+ opts := APIRequestContextFetchOptions{
+ Method: String("DELETE"),
+ }
+ if len(options) == 1 {
+ err := assignStructFields(&opts, options[0], false)
+ if err != nil {
+ return nil, err
+ }
+ }
+
+ return r.Fetch(url, opts)
+}
+
+func (r *apiRequestContextImpl) Fetch(urlOrRequest interface{}, options ...APIRequestContextFetchOptions) (APIResponse, error) {
+ switch v := urlOrRequest.(type) {
+ case string:
+ return r.innerFetch(v, nil, options...)
+ case Request:
+ return r.innerFetch("", v, options...)
+ default:
+ return nil, fmt.Errorf("urlOrRequest has unsupported type: %T", urlOrRequest)
+ }
+}
+
+func (r *apiRequestContextImpl) innerFetch(url string, request Request, options ...APIRequestContextFetchOptions) (APIResponse, error) {
+ if r.closeReason != nil {
+ return nil, fmt.Errorf("%w: %s", ErrTargetClosed, *r.closeReason)
+ }
+ overrides := map[string]interface{}{}
+ if url != "" {
+ overrides["url"] = url
+ } else if request != nil {
+ overrides["url"] = request.URL()
+ }
+
+ if len(options) == 1 {
+ if options[0].MaxRedirects != nil && *options[0].MaxRedirects < 0 {
+ return nil, errors.New("maxRedirects must be non-negative")
+ }
+ if options[0].MaxRetries != nil && *options[0].MaxRetries < 0 {
+ return nil, errors.New("maxRetries must be non-negative")
+ }
+ // only one of them can be specified
+ if countNonNil(options[0].Data, options[0].Form, options[0].Multipart) > 1 {
+ return nil, errors.New("only one of 'data', 'form' or 'multipart' can be specified")
+ }
+ if options[0].Method == nil {
+ if request != nil {
+ options[0].Method = String(request.Method())
+ } else {
+ options[0].Method = String("GET")
+ }
+ }
+ if options[0].Headers == nil {
+ if request != nil {
+ overrides["headers"] = serializeMapToNameAndValue(request.Headers())
+ }
+ } else {
+ overrides["headers"] = serializeMapToNameAndValue(options[0].Headers)
+ options[0].Headers = nil
+ }
+ if options[0].Data != nil {
+ switch v := options[0].Data.(type) {
+ case string:
+ headersArray, ok := overrides["headers"].([]map[string]string)
+ if ok && isJsonContentType(headersArray) {
+ if json.Valid([]byte(v)) {
+ overrides["jsonData"] = v
+ } else {
+ data, err := json.Marshal(v)
+ if err != nil {
+ return nil, fmt.Errorf("could not marshal data: %w", err)
+ }
+ overrides["jsonData"] = string(data)
+ }
+ } else {
+ overrides["postData"] = base64.StdEncoding.EncodeToString([]byte(v))
+ }
+ case []byte:
+ overrides["postData"] = base64.StdEncoding.EncodeToString(v)
+ case interface{}:
+ data, err := json.Marshal(v)
+ if err != nil {
+ return nil, fmt.Errorf("could not marshal data: %w", err)
+ }
+ overrides["jsonData"] = string(data)
+ default:
+ return nil, errors.New("data must be a string, []byte, or interface{} that can marshal to json")
+ }
+ options[0].Data = nil
+ } else if options[0].Form != nil {
+ form, ok := options[0].Form.(map[string]interface{})
+ if !ok {
+ return nil, errors.New("form must be a map")
+ }
+ overrides["formData"] = serializeMapToNameValue(form)
+ options[0].Form = nil
+ } else if options[0].Multipart != nil {
+ _, ok := options[0].Multipart.(map[string]interface{})
+ if !ok {
+ return nil, errors.New("multipart must be a map")
+ }
+ multipartData := []map[string]interface{}{}
+ for name, value := range options[0].Multipart.(map[string]interface{}) {
+ switch v := value.(type) {
+ case InputFile:
+ multipartData = append(multipartData, map[string]interface{}{
+ "name": name,
+ "file": map[string]string{
+ "name": v.Name,
+ "mimeType": v.MimeType,
+ "buffer": base64.StdEncoding.EncodeToString(v.Buffer),
+ },
+ })
+ default:
+ multipartData = append(multipartData, map[string]interface{}{
+ "name": name,
+ "value": String(fmt.Sprintf("%v", v)),
+ })
+ }
+ }
+ overrides["multipartData"] = multipartData
+ options[0].Multipart = nil
+ } else if request != nil {
+ postDataBuf, err := request.PostDataBuffer()
+ if err == nil {
+ overrides["postData"] = base64.StdEncoding.EncodeToString(postDataBuf)
+ }
+ }
+ if options[0].Params != nil {
+ overrides["params"] = serializeMapToNameValue(options[0].Params)
+ options[0].Params = nil
+ }
+ }
+
+ response, err := r.channel.Send("fetch", options, overrides)
+ if err != nil {
+ return nil, err
+ }
+
+ return newAPIResponse(r, response.(map[string]interface{})), nil
+}
+
+func (r *apiRequestContextImpl) Get(url string, options ...APIRequestContextGetOptions) (APIResponse, error) {
+ opts := APIRequestContextFetchOptions{
+ Method: String("GET"),
+ }
+ if len(options) == 1 {
+ err := assignStructFields(&opts, options[0], false)
+ if err != nil {
+ return nil, err
+ }
+ }
+
+ return r.Fetch(url, opts)
+}
+
+func (r *apiRequestContextImpl) Head(url string, options ...APIRequestContextHeadOptions) (APIResponse, error) {
+ opts := APIRequestContextFetchOptions{
+ Method: String("HEAD"),
+ }
+ if len(options) == 1 {
+ err := assignStructFields(&opts, options[0], false)
+ if err != nil {
+ return nil, err
+ }
+ }
+
+ return r.Fetch(url, opts)
+}
+
+func (r *apiRequestContextImpl) Patch(url string, options ...APIRequestContextPatchOptions) (APIResponse, error) {
+ opts := APIRequestContextFetchOptions{
+ Method: String("PATCH"),
+ }
+ if len(options) == 1 {
+ err := assignStructFields(&opts, options[0], false)
+ if err != nil {
+ return nil, err
+ }
+ }
+
+ return r.Fetch(url, opts)
+}
+
+func (r *apiRequestContextImpl) Put(url string, options ...APIRequestContextPutOptions) (APIResponse, error) {
+ opts := APIRequestContextFetchOptions{
+ Method: String("PUT"),
+ }
+ if len(options) == 1 {
+ err := assignStructFields(&opts, options[0], false)
+ if err != nil {
+ return nil, err
+ }
+ }
+
+ return r.Fetch(url, opts)
+}
+
+func (r *apiRequestContextImpl) Post(url string, options ...APIRequestContextPostOptions) (APIResponse, error) {
+ opts := APIRequestContextFetchOptions{
+ Method: String("POST"),
+ }
+ if len(options) == 1 {
+ err := assignStructFields(&opts, options[0], false)
+ if err != nil {
+ return nil, err
+ }
+ }
+
+ return r.Fetch(url, opts)
+}
+
+func (r *apiRequestContextImpl) StorageState(path ...string) (*StorageState, error) {
+ result, err := r.channel.SendReturnAsDict("storageState")
+ if err != nil {
+ return nil, err
+ }
+ if len(path) == 1 {
+ file, err := os.Create(path[0])
+ if err != nil {
+ return nil, err
+ }
+ if err := json.NewEncoder(file).Encode(result); err != nil {
+ return nil, err
+ }
+ if err := file.Close(); err != nil {
+ return nil, err
+ }
+ }
+ var storageState StorageState
+ remapMapToStruct(result, &storageState)
+ return &storageState, nil
+}
+
+func newAPIRequestContext(parent *channelOwner, objectType string, guid string, initializer map[string]interface{}) *apiRequestContextImpl {
+ rc := &apiRequestContextImpl{}
+ rc.createChannelOwner(rc, parent, objectType, guid, initializer)
+ rc.tracing = fromChannel(initializer["tracing"]).(*tracingImpl)
+ return rc
+}
+
+type apiResponseImpl struct {
+ request *apiRequestContextImpl
+ initializer map[string]interface{}
+ headers *rawHeaders
+}
+
+func (r *apiResponseImpl) Body() ([]byte, error) {
+ result, err := r.request.channel.SendReturnAsDict("fetchResponseBody", []map[string]interface{}{
+ {
+ "fetchUid": r.fetchUid(),
+ },
+ })
+ if err != nil {
+ if errors.Is(err, ErrTargetClosed) {
+ return nil, errors.New("response has been disposed")
+ }
+ return nil, err
+ }
+ body := result["binary"]
+ if body == nil {
+ return nil, errors.New("response has been disposed")
+ }
+ return base64.StdEncoding.DecodeString(body.(string))
+}
+
+func (r *apiResponseImpl) Dispose() error {
+ _, err := r.request.channel.Send("disposeAPIResponse", []map[string]interface{}{
+ {
+ "fetchUid": r.fetchUid(),
+ },
+ })
+ return err
+}
+
+func (r *apiResponseImpl) Headers() map[string]string {
+ return r.headers.Headers()
+}
+
+func (r *apiResponseImpl) HeadersArray() []NameValue {
+ return r.headers.HeadersArray()
+}
+
+func (r *apiResponseImpl) JSON(v interface{}) error {
+ body, err := r.Body()
+ if err != nil {
+ return err
+ }
+ return json.Unmarshal(body, &v)
+}
+
+func (r *apiResponseImpl) Ok() bool {
+ return r.Status() == 0 || (r.Status() >= 200 && r.Status() <= 299)
+}
+
+func (r *apiResponseImpl) Status() int {
+ return int(r.initializer["status"].(float64))
+}
+
+func (r *apiResponseImpl) StatusText() string {
+ return r.initializer["statusText"].(string)
+}
+
+func (r *apiResponseImpl) Text() (string, error) {
+ body, err := r.Body()
+ if err != nil {
+ return "", err
+ }
+ return string(body), nil
+}
+
+func (r *apiResponseImpl) URL() string {
+ return r.initializer["url"].(string)
+}
+
+func (r *apiResponseImpl) fetchUid() string {
+ return r.initializer["fetchUid"].(string)
+}
+
+func (r *apiResponseImpl) fetchLog() ([]string, error) {
+ ret, err := r.request.channel.Send("fetchLog", map[string]interface{}{
+ "fetchUid": r.fetchUid(),
+ })
+ if err != nil {
+ return nil, err
+ }
+ result := make([]string, len(ret.([]interface{})))
+ for i, v := range ret.([]interface{}) {
+ result[i] = v.(string)
+ }
+ return result, nil
+}
+
+func newAPIResponse(context *apiRequestContextImpl, initializer map[string]interface{}) *apiResponseImpl {
+ return &apiResponseImpl{
+ request: context,
+ initializer: initializer,
+ headers: newRawHeaders(initializer["headers"]),
+ }
+}
+
+func countNonNil(args ...interface{}) int {
+ count := 0
+ for _, v := range args {
+ if v != nil {
+ count++
+ }
+ }
+ return count
+}
+
+func isJsonContentType(headers []map[string]string) bool {
+ if len(headers) > 0 {
+ for _, v := range headers {
+ if strings.ToLower(v["name"]) == "content-type" {
+ if v["value"] == "application/json" {
+ return true
+ }
+ }
+ }
+ }
+ return false
+}
+
+func serializeMapToNameValue(data map[string]interface{}) []map[string]string {
+ serialized := make([]map[string]string, 0, len(data))
+ for k, v := range data {
+ serialized = append(serialized, map[string]string{
+ "name": k,
+ "value": fmt.Sprintf("%v", v),
+ })
+ }
+ return serialized
+}