Skip to content

Commit 219a0cb

Browse files
committed
feat: opt-in session store + example
1 parent 052ffe4 commit 219a0cb

File tree

11 files changed

+121
-0
lines changed

11 files changed

+121
-0
lines changed

core.sh

Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ declare -A QUERY_PARAMS
88
declare -A FORM_DATA
99
declare -A PATH_VARS
1010
declare -A COOKIES
11+
declare -A SESSION
1112

1213
[[ -f 'config.sh' ]] && source config.sh
1314

@@ -28,6 +29,9 @@ respond() {
2829
shift
2930
printf "HTTP/1.1 %s %s\r\n" "$CODE" "$*"
3031
header Server "bash-stack ${VERSION:-devbuild}"
32+
[[ ! -z "$SESSION_HEADER_TO_BE_WRITTEN" ]] && \
33+
printf "%s" "$SESSION_HEADER_TO_BE_WRITTEN"
34+
3135
}
3236

3337
end_headers() {
@@ -64,6 +68,39 @@ urldecode() {
6468
printf '%b\n' "${_//%/\\x}"
6569
}
6670

71+
function create_or_resume_session() {
72+
local KEY
73+
local VAL
74+
if [[ -z "${COOKIES[_session]}" ]]; then
75+
SESSION_ID="$(tr -dc A-Za-z0-9 </dev/urandom | head -c 32 ; echo '')"
76+
SESSION_HEADER_TO_BE_WRITTEN=$(header Set-Cookie "_session=$SESSION_ID; Path=/; Secure; HttpOnly")
77+
else
78+
SESSION_ID=$(echo "${COOKIES[_session]}" | tr -dc A-Za-z0-9)
79+
fi
80+
if [[ -f "sessions/$SESSION_ID" ]]; then
81+
while IFS= read -r line; do
82+
KEY="$(echo "$line" | cut -f1)"
83+
VAL="$(echo "$line" | cut -f2-)"
84+
SESSION["$KEY"]="$VAL"
85+
done < "sessions/$SESSION_ID"
86+
fi
87+
}
88+
89+
function save_session() {
90+
if [[ "${ENABLE_SESSIONS:-false}" != true ]]; then
91+
debug "Error: You must set ENABLE_SESSIONS=true before calling save_session!"
92+
return
93+
fi
94+
local KEY
95+
if [[ -z "$SESSION_ID" ]]; then
96+
return
97+
fi
98+
touch "sessions/$SESSION_ID"
99+
for KEY in ${!SESSION[@]}; do
100+
printf "%s\t%s\n" "$KEY" "${SESSION[$KEY]}"
101+
done > "sessions/$SESSION_ID"
102+
}
103+
67104
function _inject_hmr() {
68105
if [[ -z "$USE_HMR" ]]; then
69106
return
@@ -348,6 +385,9 @@ writeHttpResponse() {
348385
return
349386
fi
350387
matchRoute "$REQUEST_PATH"
388+
389+
[[ "${ENABLE_SESSIONS:-false}" == "true" ]] && create_or_resume_session
390+
351391
if [[ ! -z "$USE_HMR" ]] && [[ "$REQUEST_PATH" == "/hmr" ]]; then
352392
if [[ "$REQUEST_METHOD" == "POST" ]]; then
353393
respond 204 OK
@@ -391,6 +431,7 @@ writeHttpResponse() {
391431
return
392432
fi
393433

434+
394435
if directive_test=$(head -1 "pages/${ROUTE_SCRIPT}"); then
395436
if [[ "$directive_test" == "# sse" ]]; then
396437
respond 200 OK
@@ -550,6 +591,7 @@ export -f findPredefinedRoutes
550591
export -f findDynamicRoutes
551592
export -f findCatchAllRoutes
552593
export -f matchRoute
594+
export -f save_session
553595

554596
parseHttpRequest
555597
writeHttpResponse

examples/sessions/.gitignore

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
data/
2+
pubsub/
3+
uploads/
4+
sessions/

examples/sessions/Dockerfile

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
FROM ubuntu
2+
3+
ENV DEV false
4+
5+
RUN apt-get update && apt-get install ucspi-tcp
6+
7+
EXPOSE 3000
8+
9+
COPY . /app
10+
11+
CMD [ "/app/start.sh" ]

examples/sessions/config.sh

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
PROJECT_NAME="Session Store Demo"
2+
ENABLE_SESSIONS=true # note: consult your lawyer before enabling this in your project!

examples/sessions/core.sh

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
../../core.sh

examples/sessions/pages/false.sh

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
# headers
2+
header HX-Refresh true
3+
end_headers
4+
5+
SESSION[test]=false
6+
save_session

examples/sessions/pages/index.sh

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
2+
source config.sh
3+
4+
htmx_page << EOF
5+
<h1>${PROJECT_NAME}</h1>
6+
<p>Your session ID: ${SESSION_ID:-not yet set}</p>
7+
<p>Your session value: ${SESSION[test]:-not yet set}</p>
8+
<button hx-post="/true" hx-swap="none">True</button>
9+
<button hx-post="/false" hx-swap="none">False</button>
10+
EOF

examples/sessions/pages/true.sh

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
# headers
2+
header HX-Refresh true
3+
end_headers
4+
5+
SESSION[test]=true
6+
save_session

examples/sessions/start.sh

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
../../start.sh

examples/sessions/static/style.css

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
body {
2+
padding: 0 40px;
3+
}
4+
#signature {
5+
position: absolute;
6+
z-index: 100;
7+
right: 20px;
8+
top: 20px;
9+
display: flex;
10+
align-items: center;
11+
justify-content: center;
12+
}
13+
14+
#signature a {
15+
text-decoration: none;
16+
}
17+
18+
#signature a:hover {
19+
text-decoration: underline;
20+
}
21+
22+
#signature svg {
23+
width: 36px;
24+
height: 36px;
25+
margin-top: -4px;
26+
vertical-align: middle;
27+
}
28+
29+
#form {
30+
display: flex;
31+
max-width: 400px;
32+
flex-direction: column;
33+
}
34+
35+
#count {
36+
font-size: 24px;
37+
}

start.sh

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ fi
1313
# remove any old subscriptions; they are no longer valid
1414
rm -rf pubsub
1515

16+
mkdir -p sessions
1617
mkdir -p pubsub
1718
mkdir -p data
1819
mkdir -p uploads

0 commit comments

Comments
 (0)