Skip to content

Commit 8412bd5

Browse files
committed
Better cookie handling
1 parent 8b6dc3e commit 8412bd5

File tree

3 files changed

+108
-23
lines changed

3 files changed

+108
-23
lines changed

client/client.go

Lines changed: 63 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,9 @@ import (
1414
"golang.org/x/net/publicsuffix"
1515
)
1616

17+
// ListenerID is used to track event listeners
18+
type ListenerID string
19+
1720
// checkStatusOk performs simple tests to ensure the request was successful
1821
// if an error occured, try to qualify it then return it. In this case the Body of the
1922
// response will not be usable later on.
@@ -42,58 +45,62 @@ func checkStatusOk(resp *http.Response) error {
4245
// Client provides methods to make http requests to the api server while making the
4346
// authentification and session ID renewal transparent.
4447
type Client struct {
45-
username string
46-
password string
47-
baseURL string
48-
sessionID string
49-
hc *http.Client
48+
username string
49+
password string
50+
baseURL string
51+
hc *http.Client
5052
}
5153

5254
// New returns a new Client
5355
// sessionID is optional and used when caching sessions externally
5456
func New(username, password, baseURL, sessionID string) (APIClient, error) {
5557
hc := http.Client{}
56-
return NewWithHC(username, password, baseURL, sessionID, &hc)
58+
return NewWithHTTPClient(username, password, baseURL, sessionID, &hc)
5759
}
5860

59-
// NewWithHC returns a new Client, injecting the HTTP client to use. See New.
60-
func NewWithHC(username, password, baseURL, sessionID string, hc *http.Client) (APIClient, error) {
61+
// NewWithHTTPClient returns a new Client, injecting the HTTP client to use. See New.
62+
func NewWithHTTPClient(username, password, baseURL, sessionID string, hc *http.Client) (APIClient, error) {
6163
jar, err := cookiejar.New(&cookiejar.Options{PublicSuffixList: publicsuffix.List})
6264
if err != nil {
6365
return nil, err
6466
}
67+
url, err := url.Parse(baseURL)
6568
if sessionID != "" {
66-
c := http.Cookie{
69+
cookie := http.Cookie{
6770
Name: "JSESSIONID",
6871
Value: sessionID,
6972
}
70-
url, err := url.Parse(baseURL)
7173
if err != nil {
7274
return nil, err
7375
}
74-
jar.SetCookies(url, []*http.Cookie{&c})
76+
jar.SetCookies(url, []*http.Cookie{&cookie})
7577
}
7678
hc.Jar = jar
7779
client := Client{
78-
username: username,
79-
password: password,
80-
baseURL: baseURL,
81-
sessionID: sessionID,
82-
hc: hc,
80+
username: username,
81+
password: password,
82+
baseURL: baseURL,
83+
hc: hc,
8384
}
8485
return &client, nil
8586
}
8687

8788
// SessionID is the latest known sessionID value
8889
// It can be used for caching sessions externally.
90+
// Returns an empty string if the session cookie is not set
8991
func (c *Client) SessionID() string {
90-
return c.sessionID
92+
u, _ := url.Parse(c.baseURL + "/enduserAPI")
93+
for _, cookie := range c.hc.Jar.Cookies(u) {
94+
if (cookie.Name == "JSESSIONID") && (cookie.Value != "") {
95+
return cookie.Value
96+
}
97+
}
98+
return ""
9199
}
92100

93-
// Login to the api server
101+
// Login to the api server to obtain a session ID cookie
94102
func (c *Client) Login() error {
95103
formData := url.Values{"userId": {c.username}, "userPassword": {c.password}}
96-
97104
resp, err := c.hc.PostForm(c.baseURL+"/enduserAPI/login", formData)
98105
if err != nil {
99106
return err
@@ -102,9 +109,9 @@ func (c *Client) Login() error {
102109
if err := checkStatusOk(resp); err != nil {
103110
return err
104111
}
112+
u, _ := url.Parse(c.baseURL)
105113
for _, cookie := range resp.Cookies() {
106114
if (cookie.Name == "JSESSIONID") && (cookie.Value != "") {
107-
c.sessionID = cookie.Value
108115
return nil
109116
}
110117
}
@@ -131,7 +138,6 @@ func (c *Client) DoWithAuth(req *http.Request) (*http.Response, error) {
131138
if err := checkStatusOk(resp); err != nil {
132139
switch err.(type) {
133140
case *AuthenticationError:
134-
fmt.Println("Need to re-authenticate")
135141
if err := c.Login(); err != nil {
136142
return nil, err
137143
}
@@ -144,7 +150,6 @@ func (c *Client) DoWithAuth(req *http.Request) (*http.Response, error) {
144150
return nil, err
145151
}
146152
}
147-
fmt.Println("Using cached sessionID")
148153
return resp, nil
149154
}
150155

@@ -176,3 +181,39 @@ func (c *Client) Execute(json []byte) (*http.Response, error) {
176181
}
177182
return resp, nil
178183
}
184+
185+
// RegisterListener registers for events and returns a listener id
186+
func (c *Client) RegisterListener() (ListenerID, error) {
187+
req, err := http.NewRequest(http.MethodPost, c.baseURL+"/events/register", nil)
188+
if err != nil {
189+
return "", err
190+
}
191+
resp, err := c.DoWithAuth(req)
192+
if err != nil {
193+
return "", err
194+
}
195+
defer resp.Body.Close()
196+
type Result struct {
197+
lid ListenerID
198+
}
199+
var result Result
200+
if err := json.NewDecoder(resp.Body).Decode(&result); err != nil {
201+
return "", err
202+
}
203+
return result.lid, nil
204+
}
205+
206+
// UnregisterListener unregisters the listener
207+
func (c *Client) UnregisterListener(l ListenerID) error {
208+
query := fmt.Sprintf("%s/events/%s/unregister", c.baseURL, l)
209+
req, err := http.NewRequest(http.MethodPost, query, nil)
210+
if err != nil {
211+
return err
212+
}
213+
resp, err := c.DoWithAuth(req)
214+
if err != nil {
215+
return err
216+
}
217+
resp.Body.Close()
218+
return nil
219+
}

client/client_test.go

Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,8 +2,10 @@ package client
22

33
import (
44
"errors"
5+
"net/http"
56
"net/http/httptest"
67
"testing"
8+
"time"
79

810
"github.com/stretchr/testify/assert"
911
)
@@ -33,3 +35,45 @@ func TestCheckStatusOk(t *testing.T) {
3335
})
3436
}
3537
}
38+
39+
func TestNew(t *testing.T) {
40+
const sID = "myTestSessionID"
41+
c, err := New("user", "pass", "http://dummy.org", sID)
42+
assert.NoError(t, err)
43+
assert.Equal(t, sID, c.SessionID())
44+
}
45+
46+
func TestNewWithHTTPClientGetsSessionCookie(t *testing.T) {
47+
const sID = "myTestSessionID"
48+
server := httptest.NewServer(http.HandlerFunc(func(rw http.ResponseWriter, req *http.Request) {
49+
assert.Equal(t, "/enduserAPI/login", req.URL.String())
50+
cookie := http.Cookie{
51+
Name: "JSESSIONID",
52+
Value: sID,
53+
Expires: time.Now().AddDate(0, 0, 1),
54+
HttpOnly: true,
55+
Secure: false,
56+
}
57+
http.SetCookie(rw, &cookie)
58+
rw.Write([]byte(`{"success":true,"roles":[{"name":"ENDUSER"}]}`))
59+
}))
60+
defer server.Close()
61+
c, err := NewWithHTTPClient("user", "pass", server.URL, "", server.Client())
62+
assert.NoError(t, err)
63+
assert.Equal(t, "", c.SessionID())
64+
err = c.Login()
65+
assert.NoError(t, err)
66+
assert.Equal(t, sID, c.SessionID())
67+
}
68+
69+
func TestRegisterListener(t *testing.T) {
70+
t.Skip("Need to write test")
71+
}
72+
73+
func TestUnregisterListener(t *testing.T) {
74+
t.Skip("Need to write test")
75+
}
76+
77+
func TestFetchEvents(t *testing.T) {
78+
t.Skip("Need to write test")
79+
}

kizcool_test.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@ type SpyClient struct {
1818
}
1919

2020
func newSpyClient(username, password, baseURL, sessionID string, hc *http.Client) (client.APIClient, error) {
21-
realClient, err := client.NewWithHC(username, password, baseURL, sessionID, hc)
21+
realClient, err := client.NewWithHTTPClient(username, password, baseURL, sessionID, hc)
2222
if err != nil {
2323
return nil, err
2424
}

0 commit comments

Comments
 (0)