github.com/versent/saml2aws@v2.17.0+incompatible/pkg/page/form.go (about)

     1  package page
     2  
     3  import (
     4  	"fmt"
     5  	"net/http"
     6  	"net/url"
     7  	"strings"
     8  
     9  	"github.com/pkg/errors"
    10  	"github.com/PuerkitoBio/goquery"
    11  	"github.com/versent/saml2aws/pkg/provider"
    12  )
    13  
    14  
    15  type Form struct {
    16  	URL    string
    17  	Method string
    18  	Values *url.Values
    19  }
    20  
    21  func (form *Form) BuildRequest() (*http.Request, error) {
    22  	values := strings.NewReader(form.Values.Encode())
    23  	req, err := http.NewRequest(form.Method, form.URL, values)
    24  	if err != nil {
    25  		return nil, errors.Wrap(err, "error building request")
    26  	}
    27  	req.Header.Add("Content-Type", "application/x-www-form-urlencoded")
    28  
    29  	return req, nil
    30  }
    31  
    32  func (form *Form) Submit(client *provider.HTTPClient) (*http.Response, error) {
    33  	if req, err := form.BuildRequest(); err != nil {
    34  		return nil, errors.Wrap(err, "error building request")
    35  	} else if res, err := client.Do(req); err != nil {
    36  		return nil, errors.Wrap(err, "error submitting form")
    37  	} else {
    38  		return res, nil
    39  	}
    40  }
    41  
    42  // If the document has multiple forms, the first form with an `action` attribute will be parsed.
    43  // You can specify the exact form using a CSS filter.
    44  func NewFormFromDocument(doc *goquery.Document, formFilter string) (*Form, error) {
    45  	form := Form{Method: "POST"}
    46  
    47  	if formFilter == "" {
    48  		formFilter = "form[action]"
    49  	}
    50  	formSelection := doc.Find(formFilter).First()
    51  	if formSelection.Size() != 1 {
    52  		return nil, fmt.Errorf("could not find form")
    53  	}
    54  
    55  	attrValue, ok := formSelection.Attr("action");
    56  	if !ok {
    57  		return nil, fmt.Errorf("could not extract form action")
    58  	}
    59  	form.URL = attrValue
    60  
    61  	attrValue, ok = formSelection.Attr("method")
    62  	if ok {
    63  		form.Method = strings.ToUpper(attrValue)
    64  	}
    65  
    66  	form.Values = &url.Values{}
    67  	formSelection.Find("input").Each(func(_ int, s *goquery.Selection) {
    68  		name, ok := s.Attr("name")
    69  		if !ok {
    70  			return
    71  		}
    72  
    73  		val, ok := s.Attr("value")
    74  		if !ok {
    75  			return
    76  		}
    77  
    78  		form.Values.Add(name, val)
    79  	})
    80  
    81  	return &form, nil
    82  }
    83  
    84  func NewFormFromResponse(res *http.Response, formFilter string) (*Form, error) {
    85  	doc, err := goquery.NewDocumentFromResponse(res)
    86  	if err != nil {
    87  		return nil, errors.Wrap(err, "failed to build document from response")
    88  	}
    89  	return NewFormFromDocument(doc, formFilter)
    90  }