27
27
static const char * TAG = "protocomm_httpd" ;
28
28
static protocomm_t * pc_httpd ; /* The global protocomm instance for HTTPD */
29
29
static bool pc_ext_httpd_handle_provided = false;
30
- static uint32_t session_id = PROTOCOMM_NO_SESSION_ID ;
30
+ /* The socket session id, which is basically just the socket number */
31
+ static uint32_t sock_session_id = PROTOCOMM_NO_SESSION_ID ;
32
+ /* Cookie session id, which is a random number passed through HTTP cookies */
33
+ static uint32_t cookie_session_id = PROTOCOMM_NO_SESSION_ID ;
31
34
32
35
#define MAX_REQ_BODY_LEN 4096
33
36
34
37
static void protocomm_httpd_session_close (void * ctx )
35
38
{
36
- if (pc_httpd -> sec && pc_httpd -> sec -> close_transport_session ) {
37
- ESP_LOGW (TAG , "Closing session as socket %d was closed" , session_id );
38
- if (pc_httpd -> sec -> close_transport_session ((protocomm_security_handle_t )ctx , session_id ) != ESP_OK ) {
39
- ESP_LOGW (TAG , "Error closing session with ID: %d" , session_id );
40
- }
39
+ /* When a socket session closes, we just reset the sock_session_id value.
40
+ * Thereafter, only cookie_session_id would get used to check if the subsequent
41
+ * request is for the same session.
42
+ */
43
+ if (sock_session_id != PROTOCOMM_NO_SESSION_ID ) {
44
+ ESP_LOGW (TAG , "Resetting socket session id as socket %d was closed" , sock_session_id );
45
+ sock_session_id = PROTOCOMM_NO_SESSION_ID ;
41
46
}
42
- session_id = PROTOCOMM_NO_SESSION_ID ;
43
47
}
44
48
45
49
static esp_err_t common_post_handler (httpd_req_t * req )
@@ -50,36 +54,66 @@ static esp_err_t common_post_handler(httpd_req_t *req)
50
54
const char * ep_name = NULL ;
51
55
ssize_t outlen ;
52
56
53
- int cur_session_id = httpd_req_to_sockfd (req );
54
-
55
- if (cur_session_id != session_id ) {
56
- ESP_LOGD (TAG , "Creating new session: %d" , cur_session_id );
57
- /* Initialize new security session */
58
- if (session_id != PROTOCOMM_NO_SESSION_ID ) {
59
- ESP_LOGD (TAG , "Closing session with ID: %d" , session_id );
60
- /* Presently HTTP server doesn't support callback on socket closure so
61
- * previous session can only be closed when new session is requested */
57
+ int cur_sock_session_id = httpd_req_to_sockfd (req );
58
+ int cur_cookie_session_id = 0 ;
59
+ char cookie_buf [20 ] = {0 };
60
+ bool same_session = false;
61
+
62
+ /* Check if any cookie is available in the received headers */
63
+ if (httpd_req_get_hdr_value_str (req , "Cookie" , cookie_buf , sizeof (cookie_buf )) == ESP_OK ) {
64
+ ESP_LOGD (TAG , "Received cookie %s" , cookie_buf );
65
+ char session_cookie [20 ] = {0 };
66
+ snprintf (session_cookie , sizeof (session_cookie ), "session=%u" , cookie_session_id );
67
+ /* If a cookie is found, check it against the session id. If it matches,
68
+ * it means that this is a continuation of the same session.
69
+ */
70
+ if (strcmp (session_cookie , cookie_buf ) == 0 ) {
71
+ ESP_LOGD (TAG , "Continuing Session %u" , cookie_session_id );
72
+ cur_cookie_session_id = cookie_session_id ;
73
+ /* If we reach here, it means that the client supports cookies and so the
74
+ * socket session id would no more be required for checking.
75
+ */
76
+ sock_session_id = PROTOCOMM_NO_SESSION_ID ;
77
+ same_session = true;
78
+ }
79
+ } else if (cur_sock_session_id == sock_session_id ) {
80
+ /* If the socket number matches, we assume it to be the same session */
81
+ ESP_LOGD (TAG , "Continuing Socket Session %u" , sock_session_id );
82
+ cur_cookie_session_id = cookie_session_id ;
83
+ same_session = true;
84
+ }
85
+ if (!same_session ) {
86
+ /* If the received request is not a continuation of an existing session,
87
+ * first close any existing sessions as applicable.
88
+ */
89
+ if (cookie_session_id != PROTOCOMM_NO_SESSION_ID ) {
90
+ ESP_LOGW (TAG , "Closing session with ID: %u" , cookie_session_id );
62
91
if (pc_httpd -> sec && pc_httpd -> sec -> close_transport_session ) {
63
- ret = pc_httpd -> sec -> close_transport_session (pc_httpd -> sec_inst , session_id );
92
+ ret = pc_httpd -> sec -> close_transport_session (pc_httpd -> sec_inst , cookie_session_id );
64
93
if (ret != ESP_OK ) {
65
- ESP_LOGW (TAG , "Error closing session with ID: %d " , session_id );
94
+ ESP_LOGW (TAG , "Error closing session with ID: %u " , cookie_session_id );
66
95
}
67
96
}
68
- session_id = PROTOCOMM_NO_SESSION_ID ;
97
+ cookie_session_id = PROTOCOMM_NO_SESSION_ID ;
98
+ sock_session_id = PROTOCOMM_NO_SESSION_ID ;
69
99
}
100
+ /* Initialize new security session. A random number will be assigned to the session */
101
+ cur_cookie_session_id = esp_random ();
102
+ ESP_LOGD (TAG , "Creating new session: %u" , cur_cookie_session_id );
70
103
if (pc_httpd -> sec && pc_httpd -> sec -> new_transport_session ) {
71
- ret = pc_httpd -> sec -> new_transport_session (pc_httpd -> sec_inst , cur_session_id );
104
+ ret = pc_httpd -> sec -> new_transport_session (pc_httpd -> sec_inst , cur_cookie_session_id );
72
105
if (ret != ESP_OK ) {
73
- ESP_LOGE (TAG , "Failed to launch new session with ID: %d " , cur_session_id );
106
+ ESP_LOGE (TAG , "Failed to launch new session with ID: %u " , cur_cookie_session_id );
74
107
ret = ESP_FAIL ;
75
108
goto out ;
76
109
}
77
110
req -> sess_ctx = pc_httpd -> sec_inst ;
78
111
req -> free_ctx = protocomm_httpd_session_close ;
79
112
80
113
}
81
- session_id = cur_session_id ;
82
- ESP_LOGD (TAG , "New session with ID: %d" , cur_session_id );
114
+ cookie_session_id = cur_cookie_session_id ;
115
+ sock_session_id = cur_sock_session_id ;
116
+ ESP_LOGD (TAG , "New socket session ID: %d" , sock_session_id );
83
117
}
84
118
85
119
if (req -> content_len <= 0 ) {
@@ -112,14 +146,20 @@ static esp_err_t common_post_handler(httpd_req_t *req)
112
146
/* Extract the endpoint name from URI string of type "/ep_name" */
113
147
ep_name = req -> uri + 1 ;
114
148
115
- ret = protocomm_req_handle (pc_httpd , ep_name , session_id ,
149
+ ret = protocomm_req_handle (pc_httpd , ep_name , cookie_session_id ,
116
150
(uint8_t * )req_body , recv_size , & outbuf , & outlen );
117
151
118
152
if (ret != ESP_OK ) {
119
153
ESP_LOGE (TAG , "Data handler failed" );
120
154
ret = ESP_FAIL ;
121
155
goto out ;
122
156
}
157
+ /* If this is a new session, send the session id in a cookie */
158
+ if (!same_session ) {
159
+ snprintf (cookie_buf , sizeof (cookie_buf ), "session=%u" , cookie_session_id );
160
+ ESP_LOGD (TAG , "Setting cookie %s" , cookie_buf );
161
+ httpd_resp_set_hdr (req , "Set-Cookie" , cookie_buf );
162
+ }
123
163
124
164
ret = httpd_resp_send (req , (char * )outbuf , outlen );
125
165
if (ret != ESP_OK ) {
@@ -254,7 +294,8 @@ esp_err_t protocomm_httpd_start(protocomm_t *pc, const protocomm_httpd_config_t
254
294
pc -> add_endpoint = protocomm_httpd_add_endpoint ;
255
295
pc -> remove_endpoint = protocomm_httpd_remove_endpoint ;
256
296
pc_httpd = pc ;
257
- session_id = PROTOCOMM_NO_SESSION_ID ;
297
+ cookie_session_id = PROTOCOMM_NO_SESSION_ID ;
298
+ sock_session_id = PROTOCOMM_NO_SESSION_ID ;
258
299
return ESP_OK ;
259
300
}
260
301
@@ -270,7 +311,8 @@ esp_err_t protocomm_httpd_stop(protocomm_t *pc)
270
311
}
271
312
pc_httpd -> priv = NULL ;
272
313
pc_httpd = NULL ;
273
- session_id = PROTOCOMM_NO_SESSION_ID ;
314
+ cookie_session_id = PROTOCOMM_NO_SESSION_ID ;
315
+ sock_session_id = PROTOCOMM_NO_SESSION_ID ;
274
316
return ESP_OK ;
275
317
}
276
318
return ESP_ERR_INVALID_ARG ;
0 commit comments