Two questions about HTTP sessions

27 views
Skip to first unread message

Michael Ben Yosef

unread,
Mar 31, 2015, 8:42:17 AM3/31/15
to swi-p...@googlegroups.com
Firstly, what is a good way to use mutexes to make sure that the session data cannot be left in an inconsistent state by concurrent modifications? Is it OK to call create_mutex/1 on the session ID as shown below?

http_session_id(Id),
create_mutex
(Id),
with_mutex
(Id,
   
(   http_session_retractall(foo(X)),
        http_session_assert
(foo(42))
   
)),
...

If so, how does one check if a mutex with a given ID already exists before creating it?

Secondly, should library(http/http_session) not make sessions persistent by default? Obviously it makes little difference when the timeout is 10 minutes, as is the default, but nowadays I think it is common for people to stay logged in to their favourite services for weeks when using private computers. It's likely the server will have to be restarted for some reason over such a long period, inconveniencing clients who will find themselves logged out.

Jan Wielemaker

unread,
Mar 31, 2015, 9:10:04 AM3/31/15
to Michael Ben Yosef, swi-p...@googlegroups.com
Hi Michael,

On 03/31/2015 02:42 PM, Michael Ben Yosef wrote:
> Firstly, what is a good way to use mutexes to make sure that the session
> data cannot be left in an inconsistent state by concurrent
> modifications? Is it OK to call create_mutex/1on the session ID as shown
> below?
>
> |
> http_session_id(Id),
> create_mutex(Id),
> with_mutex(Id,
> ( http_session_retractall(foo(X)),
> http_session_assert(foo(42))
> )),
> ...
> |
>
> If so, how does one check if a mutex with a given ID already exists
> before creating it?

You do not have to create a mutex explicitly. Trying to lock it will
create it for you. So, you can simply leave the create_mutex(Id) out.

But ... as sessions are created with new unique identifiers, you'll
loose the mutex. You can define a hook that is called when the session
is reclaimed (due to timeout or explicitly) to remove the mutex. In
general though, I'd use a fixed mutex name for short possibly
conflicting updates. I often use the module name as mutex name
to protect all dynamic data managed by a module.

I also wonder about a realistic scenarion where the above would be
needed. Basically, this should only be needed if a single client
runs multiple requests concurrently that update the same session
data.

> Secondly, should library(http/http_session) not make sessions persistent
> by default? Obviously it makes little difference when the timeout is 10
> minutes, as is the default, but nowadays I think it is common for people
> to stay logged in to their favourite services for weeks when using
> private computers. It's likely the server will have to be restarted for
> some reason over such a long period, inconveniencing clients who will
> find themselves logged out.

I don't know. Staying logged on is only one of the things for which you
can use sessions. You may also want to share sessions over a cluster of
servers, etc. If you have persistency, you might want privacy using
encryption, etc. Maybe we need some hook that allows you to program how
sessions are stored.

On the other hand, nobody stops you from using library(persistency) or a
database interface for storing session data.

Cheers --- Jan

Raivo Laanemets

unread,
Mar 31, 2015, 9:53:14 AM3/31/15
to swi-p...@googlegroups.com
> Secondly, should library(http/http_session) not make sessions persistent by default?

An alternative way is to use your own cookie. You give it a defined Expires value, like date in 1 month ahead (without setting Expires you get a "session" cookie), and you update it as you see fit. You can update it in certain request handlers. Then you can store the user identifier in cookie, secured by a signature (can be created and verified using hmac_sha/4, the cookie would hold identifier + signature). This gives completely stateless session/user management that works with all kinds of load balancing. This also makes sessions survive server restarts, unless you store session-related data in memory (like http_session does). However, if you do, you need some mechanism to remove data or it just fills the whole memory (http_session has this mechanism built in, using the session timeout parameter).

Anne Ogborn

unread,
Mar 31, 2015, 11:36:53 AM3/31/15
to GoogleSWI-Prolog
I'm vastly puzzled

https://pbs.twimg.com/media/CBWtxwlUIAAPeYL.png:large


That is NOT our official 'Owlie'. Somebody took the time to draw a new version of him/her!

Michael Ben Yosef

unread,
Apr 1, 2015, 4:50:55 AM4/1/15
to swi-p...@googlegroups.com
Hi Jan!

Thanks for your reply!


You do not have to create a mutex explicitly.  Trying to lock it will
create it for you.  So, you can simply leave the create_mutex(Id) out.

But ... as sessions are created with new unique identifiers, you'll
loose the mutex. You can define a hook that is called when the session
is reclaimed (due to timeout or explicitly) to remove the mutex. In
general though, I'd use a fixed mutex name for short possibly
conflicting updates.  I often use the module name as mutex name
to protect all dynamic data managed by a module.
 
Does this not imply that one could simply do

http_session_id(Id),
with_mutex
(Id, ...),
catch(mutex_destroy(Id), _, true),

with the catch/3 being used in case of a repeated attempt to destroy the mutex due to concurrency? Or does repeatedly creating and destroying such mutexes involve too much overhead and one should rather use a single mutex, as you suggest?

I also wonder about a realistic scenarion where the above would be
needed.  Basically, this should only be needed if a single client
runs multiple requests concurrently that update the same session
data.

Relying on clients to behave normally opens up security issues, of course.

On the other hand, nobody stops you from using library(persistency) or a
database interface for storing session data.
 
Indeed, but making the server recognise session cookies it sent out during a previous execution requires plumbing to library(http/http_session), or handling cookies oneself, as Raivo suggests.

Michael

Michael Ben Yosef

unread,
Apr 1, 2015, 5:09:19 AM4/1/15
to swi-p...@googlegroups.com

On Tuesday, 31 March 2015 15:53:14 UTC+2, Raivo Laanemets wrote:
> Secondly, should library(http/http_session) not make sessions persistent by default?

An alternative way is to use your own cookie. You give it a defined Expires value, like date in 1 month ahead (without setting Expires you get a "session" cookie), and you update it as you see fit. You can update it in certain request handlers. Then you can store the user identifier in cookie, secured by a signature (can be created and verified using hmac_sha/4, the cookie would hold identifier + signature). This gives completely stateless session/user management that works with all kinds of load balancing. This also makes sessions survive server restarts, unless you store session-related data in memory (like http_session does). However, if you do, you need some mechanism to remove data or it just fills the whole memory (http_session has this mechanism built in, using the session timeout parameter).

Thanks, Raivo! I considered this, but rejected it for what may be a misconception regarding how involved it is. Maybe you can clarify.

If I write a Set-Cookie header, does that not mean that I have to manually handle all the headers for the response? For example, by the time I write Set-Cookie, the server must already have written 200 OK, so I cannot rely on subsequent exceptions to be caught and SWI automatically generating an error page with a different Status, nor can I use http_reply/3 by throwing one of the various response types it handles. Do I have that right?

Jan Wielemaker

unread,
Apr 1, 2015, 5:15:40 AM4/1/15
to Michael Ben Yosef, swi-p...@googlegroups.com
On 04/01/2015 10:50 AM, Michael Ben Yosef wrote:
> Hi Jan!
>
> Thanks for your reply!
>
> You do not have to create a mutex explicitly. Trying to lock it will
> create it for you. So, you can simply leave the create_mutex(Id) out.
>
> But ... as sessions are created with new unique identifiers, you'll
> loose the mutex. You can define a hook that is called when the session
> is reclaimed (due to timeout or explicitly) to remove the mutex. In
>
> general though, I'd use a fixed mutex name for short possibly
> conflicting updates. I often use the module name as mutex name
> to protect all dynamic data managed by a module.
>
>
> Does this not imply that one could simply do
>
> |
> http_session_id(Id),
> with_mutex(Id,...),
> catch(mutex_destroy(Id),_,true),

Hadn't even thought about that. In fact, you should be able to do

with_mutex(Id,
( mutex_destroy(Id),
...
)).

No need for catch as you hold the mutex while you destroy it, so
it must exist. Recreating the mutex is of course protected by another
mutex, so if ... is a quick operation you won't gain anything. On the
other hand, if ... is slow, you indeed only synchronize within the
session.

Cheers --- Jan

Jan Wielemaker

unread,
Apr 1, 2015, 5:18:28 AM4/1/15
to Michael Ben Yosef, swi-p...@googlegroups.com
> I use http_reply/3by throwing one of the various response types it
> handles. Do I have that right?

You can write any HTTP header field. The user supplied field will be
merged with the system fields before the result is sent to the client.
This also allows for e.g.,

format('Status: 404~n'),
<formulate your own 404 event>

Does require a fairly recent 7.x version.

Cheers --- Jan

Raivo Laanemets

unread,
Apr 1, 2015, 5:37:18 AM4/1/15
to swi-p...@googlegroups.com
> If I write a Set-Cookie header, does that not mean that I have to manually handle all the headers for the response?

You mean when you write the header and throw reply then your custom header disappears? Try and see it. I'm not even sure whether Set-Cookie header stays when you use http_session and exception-based response. Also, you do not have to update the cookie in every handler and for every request. I'm not sure if there was generic way to do that. However, the incoming request cookie for user id and signature could be processed in http:request_expansion hook, the same way as http_session does (https://github.com/SWI-Prolog/packages-http/blob/a485ac80a5d0ef599870c6cd0bdb1c0af59a744d/http_session.pl#L355). Here it actually writes Set-Cookie to response too. I usually avoid exception-based responses.

Michael Ben Yosef

unread,
Apr 1, 2015, 5:58:56 AM4/1/15
to swi-p...@googlegroups.com
Thanks Jan and Raivo! Your answers have been very helpful.
Reply all
Reply to author
Forward
0 new messages