Skip to content

Commit 04f5edc

Browse files
committed
Make sessions work
User simonahac reported a thorny problem on discord yesterday. See discussion beginning at https://discord.com/channels/928484660785336380/928485908842426389/1210584191142723615 They want to use a service that relies on sessions. First you POST to a login URL. That sets a cookie and redirects to a resource. The resource only works if you provide the cookie value in the GET request. This works out of the box in python, Postman, and most other clients. But not pixlet. Looks like the underlying cause is the default behaviour of golang's http.Client. By default, it will ignore any cookies set in responses when making the redirect. When sending the redirected request, it would just copy over headers and cookies from the original outgoing response -- which won't have the cookie set. If the client has a CookieJar, however, it just works as expected. Cookies from responses will be added to the jar, and all the cookies from the jar will automatically be added to all outgoing requests from that point. https://cs.opensource.google/go/go/+/master:src/net/http/client.go;drc=b899e0b8cc1afc4534758c9ebe1e051e5220bfbd;l=88 I think this should be a safe change. There's only one existing community app (avatarsinpixels) that manually accesses the "Set-Cookie" header on a response. I've checked it works the same with and without this change.
1 parent 2e1ddcd commit 04f5edc

File tree

4 files changed

+58
-2
lines changed

4 files changed

+58
-2
lines changed

go.mod

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,7 @@ require (
4040
github.com/zachomedia/go-bdf v0.0.0-20220611021443-a3af701111be
4141
go.starlark.net v0.0.0-20231121155337-90ade8b19d09
4242
golang.org/x/image v0.14.0
43+
golang.org/x/net v0.19.0
4344
golang.org/x/oauth2 v0.15.0
4445
golang.org/x/sync v0.5.0
4546
golang.org/x/text v0.14.0
@@ -101,7 +102,6 @@ require (
101102
golang.org/x/crypto v0.16.0 // indirect
102103
golang.org/x/exp v0.0.0-20230905200255-921286631fa9 // indirect
103104
golang.org/x/mod v0.12.0 // indirect
104-
golang.org/x/net v0.19.0 // indirect
105105
golang.org/x/sys v0.15.0 // indirect
106106
golang.org/x/tools v0.13.0 // indirect
107107
google.golang.org/appengine v1.6.7 // indirect

runtime/modules/starlarkhttp/starlarkhttp.go

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -32,13 +32,15 @@ import (
3232
"io"
3333
"mime/multipart"
3434
"net/http"
35+
"net/http/cookiejar"
3536
"net/url"
3637
"strconv"
3738
"strings"
3839

3940
util "github.com/qri-io/starlib/util"
4041
"go.starlark.net/starlark"
4142
"go.starlark.net/starlarkstruct"
43+
"golang.org/x/net/publicsuffix"
4244
)
4345

4446
// AsString unquotes a starlark string value
@@ -51,9 +53,18 @@ func AsString(x starlark.Value) (string, error) {
5153
const ModuleName = "http.star"
5254

5355
var (
56+
// Providing a cookie jar allows sessions and redirects to work properly. With a
57+
// jar present, any cookies set in a response will automatically be added to
58+
// subsequent requests. This means that we can follow redirects after logging into
59+
// a session. Without a jar, any cookies will be dropped from redirects unless explicitly
60+
// set in the original outgoing request.
61+
// https://cs.opensource.google/go/go/+/master:src/net/http/client.go;drc=4c394b5638cc2694b1eff6418bc3e7db8132de0e;l=88
62+
jar, _ = cookiejar.New(&cookiejar.Options{PublicSuffixList: publicsuffix.List})
5463
// StarlarkHTTPClient is the http client used to create the http module. override with
5564
// a custom client before calling LoadModule
56-
StarlarkHTTPClient = http.DefaultClient
65+
StarlarkHTTPClient = &http.Client{
66+
Jar: jar,
67+
}
5768
// StarlarkHTTPGuard is a global RequestGuard used in LoadModule. override with a custom
5869
// implementation before calling LoadModule
5970
StarlarkHTTPGuard RequestGuard

runtime/modules/starlarkhttp/starlarkhttp_test.go

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -140,3 +140,41 @@ func TestSetBody(t *testing.T) {
140140
}
141141
}
142142
}
143+
144+
func TestSetCookieOnRedirect(t *testing.T) {
145+
ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
146+
// Requests to "/login" set a cookie and redirect to /destination
147+
if strings.HasSuffix(r.URL.Path, "/login") {
148+
w.Header().Set("Set-Cookie", "doodad=foobar; path=/; HttpOnly")
149+
w.Header().Set("Location", "/destination")
150+
w.WriteHeader(302)
151+
return
152+
}
153+
// Requests to /destination must have cookie set
154+
if strings.HasSuffix(r.URL.Path, "/destination") {
155+
c, err := r.Cookie("doodad")
156+
if err != nil {
157+
t.Errorf("Expected cookie `doodad` not present")
158+
}
159+
if c.Value != "foobar" {
160+
t.Errorf("Cookie `doodad` value mismatch. Expected foobar, got %s", c.Value)
161+
}
162+
if _, err := w.Write([]byte(`{"hello":"world"}`)); err != nil {
163+
t.Fatal(err)
164+
}
165+
return
166+
}
167+
t.Errorf("Unexpected path requested: %s", r.URL.Path)
168+
}))
169+
starlark.Universe["test_server_url"] = starlark.String(ts.URL)
170+
171+
thread := &starlark.Thread{Name: "unittests/setcookieonredirect", Load: testdata.NewLoader(starlarkhttp.LoadModule, starlarkhttp.ModuleName)}
172+
starlarktest.SetReporter(thread, t)
173+
174+
// Execute test file
175+
_, err := starlark.ExecFile(thread, "testdata/test_redirect.star", nil, nil)
176+
if err != nil {
177+
t.Error(err)
178+
}
179+
180+
}
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
load("http.star", "http")
2+
load("assert.star", "assert")
3+
4+
res_1 = http.post(test_server_url + "/login")
5+
assert.eq(res_1.status_code, 200)
6+
assert.eq(res_1.body(), '{"hello":"world"}')
7+
assert.eq(res_1.json(), {"hello": "world"})

0 commit comments

Comments
 (0)