sessions.inc (3520B)
1 This chapter discusses how one should manage sessions, that is, share state between multiple 2 HTTP requests from the same user. We use a simple example where the user submits multiple 3 forms and the server is supposed to accumulate state from all of these forms. Naturally, as 4 this is a network protocol, our session mechanism must support having many users with 5 many concurrent sessions at the same time. 6 7 In order to track users, we use a simple session cookie. A session cookie expires when the 8 user closes the browser. Changing from session cookies to persistent cookies only requires 9 adding an expiration time to the cookie. The server creates a fresh session cookie whenever 10 a request without a cookie is received, or if the supplied session cookie is not known to 11 the server. 12 13 @heading Looking up the cookie 14 15 Since MHD parses the HTTP cookie header for us, looking up an existing cookie 16 is straightforward: 17 18 @verbatim 19 const char *value; 20 21 value = MHD_lookup_connection_value (connection, 22 MHD_COOKIE_KIND, 23 "KEY"); 24 @end verbatim 25 26 Here, "KEY" is the name we chose for our session cookie. 27 28 29 @heading Setting the cookie header 30 31 MHD requires the user to provide the full cookie format string in order to set 32 cookies. In order to generate a unique cookie, our example creates a random 33 32-character text string to be used as the value of the cookie: 34 35 @verbatim 36 char value[128]; 37 char raw_value[33]; 38 39 for (unsigned int i=0;i<sizeof (raw_value) - 1;i++) 40 raw_value[i] = 'A' + (rand () % 26); /* bad PRNG! */ 41 raw_value[sizeof (raw_value) - 1] = '\0'; 42 snprintf (value, sizeof (value), 43 "%s=%s", 44 "KEY", 45 raw_value); 46 @end verbatim 47 48 Given this cookie value, we can then set the cookie header in our HTTP response 49 as follows: 50 51 @verbatim 52 if (MHD_NO == 53 MHD_add_response_header (response, 54 MHD_HTTP_HEADER_SET_COOKIE, 55 value)) 56 fprintf (stderr, "Failed to set session cookie header!\n"); 57 @end verbatim 58 59 Note that the header has to be added @emph{before} the response is queued with 60 @code{MHD_queue_response}; MHD refuses to modify a response that is already 61 queued. 62 63 64 @heading Remark: Session expiration 65 66 It is of course possible that clients stop their interaction with the 67 server at any time. In order to avoid using too much storage, the 68 server must thus discard inactive sessions at some point. Our example 69 implements this by discarding inactive sessions after a certain amount 70 of time. Alternatively, the implementation may limit the total number 71 of active sessions. Which bounds are used for idle sessions or the 72 total number of sessions obviously depends largely on the type of 73 the application and available server resources. 74 75 @heading Example code 76 77 A sample application implementing a website with multiple 78 forms (which are dynamically created using values from previous 79 POST requests from the same session) is available 80 as the example @code{sessions.c}. 81 82 Note that the example uses a simple, @math{O(n)} linked list traversal to 83 look up sessions and to expire old sessions. Using a hash table and a 84 heap would be more appropriate if a large number of concurrent 85 sessions is expected. 86 87 @heading Remarks 88 89 Naturally, it is quite conceivable to store session data in a database 90 instead of in memory. Still, having mechanisms to expire data 91 associated with long-time idle sessions (where the business process 92 has still not finished) is likely a good idea.