1
0
mirror of https://github.com/aclindsa/ofxgo.git synced 2024-11-22 03:30:04 -05:00
ofxgo/vanguard_client.go
Aaron Lindsay d8491bed1d Make Client an interface instead of a struct
This makes it easier to maintain per-institution hacks that start
interacting with each other if you try to do them all in the same client
code. This commit also breaks out the existing Vanguard hack into its
own Client implementation.
2018-10-03 10:18:54 -04:00

80 lines
2.1 KiB
Go

package ofxgo
import (
"errors"
"io"
"net/http"
"strings"
)
// VanguardClient provides a Client implementation which handles Vanguard's
// cookie-passing requirements. VanguardClient uses default, non-zero settings,
// if its fields are not initialized.
type VanguardClient struct {
*BasicClient
}
// NewVanguardClient returns a Client interface configured to handle Vanguard's
// brand of idiosyncracy
func NewVanguardClient(bc *BasicClient) Client {
return &VanguardClient{bc}
}
// rawRequestCookies is RawRequest with the added feature of sending cookies
func rawRequestCookies(URL string, r io.Reader, cookies []*http.Cookie) (*http.Response, error) {
if !strings.HasPrefix(URL, "https://") {
return nil, errors.New("Refusing to send OFX request with possible plain-text password over non-https protocol")
}
request, err := http.NewRequest("POST", URL, r)
if err != nil {
return nil, err
}
request.Header.Set("Content-Type", "application/x-ofx")
for _, cookie := range cookies {
request.AddCookie(cookie)
}
response, err := http.DefaultClient.Do(request)
if err != nil {
return nil, err
}
if response.StatusCode != 200 {
return nil, errors.New("OFXQuery request status: " + response.Status)
}
return response, nil
}
func (c *VanguardClient) RequestNoParse(r *Request) (*http.Response, error) {
r.SetClientFields(c)
b, err := r.Marshal()
if err != nil {
return nil, err
}
response, err := c.RawRequest(r.URL, b)
// Some financial institutions (cough, Vanguard, cough), require a cookie
// to be set on the http request, or they return empty responses.
// Fortunately, the initial response contains the cookie we need, so if we
// detect an empty response with cookies set that didn't have any errors,
// re-try the request while sending their cookies back to them.
if err == nil && response.ContentLength <= 0 && len(response.Cookies()) > 0 {
b, err = r.Marshal()
if err != nil {
return nil, err
}
return rawRequestCookies(r.URL, b, response.Cookies())
}
return response, err
}
func (c *VanguardClient) Request(r *Request) (*Response, error) {
return clientRequest(c, r)
}