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 }