2 * ws protocol handler plugin for "generic sessions"
4 * Copyright (C) 2010-2019 Andy Green <andy@warmcat.com>
6 * This program is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public
8 * License as published by the Free Software Foundation:
9 * version 2.1 of the License.
11 * This library is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * General Public License for more details.
16 * You should have received a copy of the GNU General Public
17 * License along with this library; if not, write to the Free Software
18 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
22 #include "private-lwsgs.h"
25 /* keep changes in sync with the enum in lwsgs.h */
26 static const char * const param_names[] = {
47 struct lwsgs_fill_args {
52 static const struct lws_protocols protocols[];
54 struct lwsgs_subst_args
56 struct per_session_data__gs *pss;
57 struct per_vhost_data__gs *vhd;
62 lwsgs_subst(void *data, int index)
64 struct lwsgs_subst_args *a = (struct lwsgs_subst_args *)data;
70 a->pss->result[0] = '\0';
72 if (!lwsgs_get_sid_from_wsi(a->wsi, &sid)) {
73 if (lwsgs_lookup_session(a->vhd, &sid, a->pss->result, 31)) {
74 lwsl_notice("sid lookup for %s failed\n", sid.id);
75 a->pss->delete_session = sid;
78 lws_snprintf(s, sizeof(s) - 1, "select username,email "
79 "from users where username = '%s';",
80 lws_sql_purify(esc, a->pss->result, sizeof(esc) - 1));
81 if (sqlite3_exec(a->vhd->pdb, s, lwsgs_lookup_callback_user,
82 &u, NULL) != SQLITE_OK) {
83 lwsl_err("Unable to lookup token: %s\n",
84 sqlite3_errmsg(a->vhd->pdb));
85 a->pss->delete_session = sid;
89 lwsl_notice("no sid\n");
91 lws_strncpy(a->pss->result + 32, u.email, 100);
95 return a->pss->result;
98 n = lwsgs_get_auth_level(a->vhd, a->pss->result);
99 sprintf(a->pss->result, "%d", n);
100 return a->pss->result;
102 return a->pss->result + 32;
109 lws_get_effective_host(struct lws *wsi, char *buf, size_t buflen)
112 if (lws_hdr_copy(wsi, buf, buflen - 1,
113 WSI_TOKEN_HTTP_COLON_AUTHORITY) > 0)
117 if (lws_hdr_copy(wsi, buf, buflen - 1, WSI_TOKEN_HOST) > 0)
124 callback_generic_sessions(struct lws *wsi, enum lws_callback_reasons reason,
125 void *user, void *in, size_t len)
127 struct per_session_data__gs *pss = (struct per_session_data__gs *)user;
128 const struct lws_protocol_vhost_options *pvo;
129 struct per_vhost_data__gs *vhd = (struct per_vhost_data__gs *)
130 lws_protocol_vh_priv_get(lws_get_vhost(wsi),
131 lws_vhost_name_to_protocol(lws_get_vhost(wsi),
132 "protocol-generic-sessions"));
133 char cookie[1024], username[32], *pc = cookie;
134 unsigned char buffer[LWS_PRE + LWSGS_EMAIL_CONTENT_SIZE];
135 struct lws_process_html_args *args = in;
136 struct lws_session_info *sinfo;
137 char s[LWSGS_EMAIL_CONTENT_SIZE];
138 unsigned char *p, *start, *end;
139 const char *cp, *cp1;
146 case LWS_CALLBACK_PROTOCOL_INIT: /* per vhost */
148 vhd = lws_protocol_vh_priv_zalloc(lws_get_vhost(wsi),
149 lws_get_protocol(wsi), sizeof(struct per_vhost_data__gs));
152 vhd->context = lws_get_context(wsi);
155 vhd->timeout_idle_secs = 600;
156 vhd->timeout_absolute_secs = 36000;
157 vhd->timeout_anon_absolute_secs = 1200;
158 vhd->timeout_email_secs = 24 * 3600;
161 strcpy(vhd->helo, "unconfigured.com");
162 strcpy(vhd->ip, "127.0.0.1");
163 strcpy(vhd->email_from, "noreply@unconfigured.com");
164 strcpy(vhd->email_title, "Registration Email from unconfigured");
165 vhd->urlroot[0] = '\0';
167 pvo = (const struct lws_protocol_vhost_options *)in;
169 if (!strcmp(pvo->name, "admin-user"))
170 lws_strncpy(vhd->admin_user, pvo->value,
171 sizeof(vhd->admin_user));
172 if (!strcmp(pvo->name, "urlroot"))
173 lws_strncpy(vhd->urlroot, pvo->value,
174 sizeof(vhd->urlroot));
175 if (!strcmp(pvo->name, "admin-password-sha256"))
176 lws_strncpy(vhd->admin_password_sha256.id, pvo->value,
177 sizeof(vhd->admin_password_sha256.id));
178 if (!strcmp(pvo->name, "session-db"))
179 lws_strncpy(vhd->session_db, pvo->value,
180 sizeof(vhd->session_db));
181 if (!strcmp(pvo->name, "confounder"))
182 lws_strncpy(vhd->confounder, pvo->value,
183 sizeof(vhd->confounder));
184 if (!strcmp(pvo->name, "email-from"))
185 lws_strncpy(vhd->email_from, pvo->value,
186 sizeof(vhd->email_from));
187 if (!strcmp(pvo->name, "email-helo"))
188 lws_strncpy(vhd->helo, pvo->value, sizeof(vhd->helo));
189 if (!strcmp(pvo->name, "email-template"))
190 lws_strncpy(vhd->email_template, pvo->value,
191 sizeof(vhd->email_template));
192 if (!strcmp(pvo->name, "email-title"))
193 lws_strncpy(vhd->email_title, pvo->value,
194 sizeof(vhd->email_title));
195 if (!strcmp(pvo->name, "email-contact-person"))
196 lws_strncpy(vhd->email_contact_person, pvo->value,
197 sizeof(vhd->email_contact_person));
198 if (!strcmp(pvo->name, "email-confirm-url-base"))
199 lws_strncpy(vhd->email_confirm_url, pvo->value,
200 sizeof(vhd->email_confirm_url));
201 if (!strcmp(pvo->name, "email-server-ip"))
202 lws_strncpy(vhd->ip, pvo->value, sizeof(vhd->ip));
204 if (!strcmp(pvo->name, "timeout-idle-secs"))
205 vhd->timeout_idle_secs = atoi(pvo->value);
206 if (!strcmp(pvo->name, "timeout-absolute-secs"))
207 vhd->timeout_absolute_secs = atoi(pvo->value);
208 if (!strcmp(pvo->name, "timeout-anon-absolute-secs"))
209 vhd->timeout_anon_absolute_secs = atoi(pvo->value);
210 if (!strcmp(pvo->name, "email-expire"))
211 vhd->timeout_email_secs = atoi(pvo->value);
214 if (!vhd->admin_user[0] ||
215 !vhd->admin_password_sha256.id[0] ||
216 !vhd->session_db[0]) {
217 lwsl_err("generic-sessions: "
218 "You must give \"admin-user\", "
219 "\"admin-password-sha256\", "
220 "and \"session_db\" per-vhost options\n");
224 if (lws_struct_sq3_open(lws_get_context(wsi),
225 vhd->session_db, &vhd->pdb)) {
226 lwsl_err("Unable to open session db %s: %s\n",
227 vhd->session_db, sqlite3_errmsg(vhd->pdb));
232 if (sqlite3_prepare(vhd->pdb,
233 "create table if not exists sessions ("
235 " username varchar(32),"
238 -1, &sm, NULL) != SQLITE_OK) {
239 lwsl_err("Unable to prepare session table init: %s\n",
240 sqlite3_errmsg(vhd->pdb));
245 if (sqlite3_step(sm) != SQLITE_DONE) {
246 lwsl_err("Unable to run session table init: %s\n",
247 sqlite3_errmsg(vhd->pdb));
251 sqlite3_finalize(sm);
253 if (sqlite3_exec(vhd->pdb,
254 "create table if not exists users ("
255 " username varchar(32),"
256 " creation_time integer,"
258 " email varchar(100),"
259 " pwhash varchar(65),"
260 " pwsalt varchar(65),"
261 " pwchange_time integer,"
262 " token varchar(65),"
264 " token_time integer,"
265 " last_forgot_validated integer,"
266 " primary key (username)"
268 NULL, NULL, NULL) != SQLITE_OK) {
269 lwsl_err("Unable to create user table: %s\n",
270 sqlite3_errmsg(vhd->pdb));
275 memset(&abs, 0, sizeof(abs));
276 abs.vh = lws_get_vhost(wsi);
278 /* select the protocol and bind its tokens */
280 abs.ap = lws_abs_protocol_get_by_name("smtp");
284 vhd->protocol_tokens[0].name_index = LTMI_PSMTP_V_HELO;
285 vhd->protocol_tokens[0].u.value = vhd->helo;
287 abs.ap_tokens = vhd->protocol_tokens;
289 /* select the transport and bind its tokens */
291 abs.at = lws_abs_transport_get_by_name("raw_skt");
295 vhd->transport_tokens[0].name_index = LTMI_PEER_V_DNS_ADDRESS;
296 vhd->transport_tokens[0].u.value = vhd->ip;
297 vhd->transport_tokens[1].name_index = LTMI_PEER_LV_PORT;
298 vhd->transport_tokens[1].u.lvalue = 25;
300 abs.at_tokens = vhd->transport_tokens;
302 vhd->smtp_client = lws_abs_bind_and_create_instance(&abs);
303 if (!vhd->smtp_client)
306 lwsl_notice("%s: created SMTP client\n", __func__);
309 case LWS_CALLBACK_PROTOCOL_DESTROY:
310 // lwsl_notice("gs: LWS_CALLBACK_PROTOCOL_DESTROY: v=%p, ctx=%p\n", vhd, vhd->context);
312 sqlite3_close(vhd->pdb);
315 if (vhd->smtp_client)
316 lws_abs_destroy_instance(&vhd->smtp_client);
319 case LWS_CALLBACK_HTTP_WRITEABLE:
320 if (!pss->check_response)
322 pss->check_response = 0;
323 n = lws_write(wsi, (unsigned char *)&pss->check_response_value,
324 1, LWS_WRITE_HTTP | LWS_WRITE_H2_STREAM_END);
329 case LWS_CALLBACK_HTTP:
331 lwsl_err("%s: no valid pss\n", __func__);
335 pss->login_session.id[0] = '\0';
339 if ((*(const char *)in == '/'))
342 if (lws_get_effective_host(wsi, cookie, sizeof(cookie))) {
343 lwsl_err("%s: HTTP: no effective host\n", __func__);
347 lwsl_notice("LWS_CALLBACK_HTTP: %s, HOST '%s'\n",
348 (const char *)in, cookie);
352 lws_snprintf(pss->onward, sizeof(pss->onward),
353 "%s%s", vhd->urlroot, (const char *)in);
356 !strcmp(cp + n - 12, "lwsgs-forgot")) {
357 lwsgs_handler_forgot(vhd, wsi, pss);
358 goto redirect_with_cookie;
362 !strcmp(cp + n - 13, "lwsgs-confirm")) {
363 lwsgs_handler_confirm(vhd, wsi, pss);
364 goto redirect_with_cookie;
366 cp = strstr(cp, "lwsgs-check/");
368 lwsgs_handler_check(vhd, wsi, pss, cp + 12);
369 /* second, async part will complete transaction */
373 if (n >= 11 && !strcmp(cp + n - 11, "lwsgs-login"))
375 if (n >= 12 && !strcmp(cp + n - 12, "lwsgs-logout"))
377 if (n >= 12 && !strcmp(cp + n - 12, "lwsgs-forgot"))
379 if (n >= 12 && !strcmp(cp + n - 12, "lwsgs-change"))
382 /* if no legitimate url for GET, return 404 */
384 lwsl_err("http doing 404 on %s\n", cp);
385 lws_return_http_status(wsi, HTTP_STATUS_NOT_FOUND, NULL);
390 case LWS_CALLBACK_FILTER_PROTOCOL_CONNECTION:
391 args = (struct lws_process_html_args *)in;
394 case LWS_CALLBACK_CHECK_ACCESS_RIGHTS:
398 args = (struct lws_process_html_args *)in;
399 lwsl_notice("%s: LWS_CALLBACK_CHECK_ACCESS_RIGHTS: need 0x%x\n",
400 __func__, args->max_len);
401 if (!lwsgs_get_sid_from_wsi(wsi, &sid)) {
402 if (lwsgs_lookup_session(vhd, &sid, username,
406 * if we're authenticating for ws, we don't
407 * want to redirect it or gain a cookie on that,
408 * he'll need to get the cookie from http
409 * interactions outside of this.
412 lwsl_notice("%s: ws auth failed\n",
418 lwsl_notice("session lookup for %s failed, "
419 "probably expired\n", sid.id);
420 pss->delete_session = sid;
421 args->final = 1; /* signal we dealt with it */
422 lws_snprintf(pss->onward, sizeof(pss->onward) - 1,
423 "%s%s", vhd->urlroot, args->p);
424 lwsl_notice("redirecting to ourselves with "
426 /* we need a redirect to ourselves,
427 * session cookie is expired */
428 goto redirect_with_cookie;
431 lwsl_notice("failed to get sid from wsi\n");
433 n = lwsgs_get_auth_level(vhd, username);
435 if ((args->max_len & n) != args->max_len) {
436 lwsl_notice("Access rights fail 0x%X vs 0x%X (cookie %s)\n",
437 args->max_len, n, sid.id);
440 lwsl_debug("Access rights OK\n");
443 case LWS_CALLBACK_SESSION_INFO:
446 sinfo = (struct lws_session_info *)in;
447 sinfo->username[0] = '\0';
448 sinfo->email[0] = '\0';
450 sinfo->session[0] = '\0';
454 lwsl_debug("LWS_CALLBACK_SESSION_INFO\n");
455 if (lwsgs_get_sid_from_wsi(wsi, &sid))
457 if (lwsgs_lookup_session(vhd, &sid, username, sizeof(username)))
460 lws_snprintf(s, sizeof(s) - 1,
461 "select username, email from users where username='%s';",
463 if (sqlite3_exec(vhd->pdb, s, lwsgs_lookup_callback_user, &u, NULL) !=
465 lwsl_err("Unable to lookup token: %s\n",
466 sqlite3_errmsg(vhd->pdb));
469 lws_strncpy(sinfo->username, u.username, sizeof(sinfo->username));
470 lws_strncpy(sinfo->email, u.email, sizeof(sinfo->email));
471 lws_strncpy(sinfo->session, sid.id, sizeof(sinfo->session));
472 sinfo->mask = lwsgs_get_auth_level(vhd, username);
473 lws_get_peer_simple(wsi, sinfo->ip, sizeof(sinfo->ip));
478 case LWS_CALLBACK_PROCESS_HTML:
480 args = (struct lws_process_html_args *)in;
482 static const char * const vars[] = {
487 struct lwsgs_subst_args a;
493 pss->phs.vars = vars;
494 pss->phs.count_vars = LWS_ARRAY_SIZE(vars);
495 pss->phs.replace = lwsgs_subst;
498 if (lws_chunked_html_process(args, &pss->phs))
503 case LWS_CALLBACK_HTTP_BODY:
508 pss->spa = lws_spa_create(wsi, param_names,
509 LWS_ARRAY_SIZE(param_names), 1024,
515 if (lws_spa_process(pss->spa, in, len)) {
516 lwsl_notice("spa process blew\n");
521 case LWS_CALLBACK_HTTP_BODY_COMPLETION:
526 cp1 = (const char *)pss->onward;
531 lws_spa_finalize(pss->spa);
534 if (lws_get_effective_host(wsi, cookie, sizeof(cookie)))
537 if (!strcmp(cp1 + n - 12, "lwsgs-change")) {
538 if (!lwsgs_handler_change_password(vhd, wsi, pss)) {
539 cp = lws_spa_get_string(pss->spa, FGS_GOOD);
543 cp = lws_spa_get_string(pss->spa, FGS_BAD);
544 lwsl_notice("user/password no good %s\n",
545 lws_spa_get_string(pss->spa, FGS_USERNAME));
546 lws_snprintf(pss->onward, sizeof(pss->onward),
547 "%s%s", vhd->urlroot, cp);
549 pss->onward[sizeof(pss->onward) - 1] = '\0';
550 goto completion_flow;
553 if (!strcmp(cp1 + n - 11, "lwsgs-login")) {
554 lwsl_err("%s: lwsgs-login\n", __func__);
555 if (lws_spa_get_string(pss->spa, FGS_FORGOT) &&
556 lws_spa_get_string(pss->spa, FGS_FORGOT)[0]) {
557 if (lwsgs_handler_forgot_pw_form(vhd, wsi, pss)) {
561 /* get the email monitor to take a look */
562 lws_smtp_client_kick(vhd->smtp_client);
567 if (!lws_spa_get_string(pss->spa, FGS_USERNAME) ||
568 !lws_spa_get_string(pss->spa, FGS_PASSWORD)) {
569 lwsl_notice("username '%s' or pw '%s' missing\n",
570 lws_spa_get_string(pss->spa, FGS_USERNAME),
571 lws_spa_get_string(pss->spa, FGS_PASSWORD));
575 if (lws_spa_get_string(pss->spa, FGS_REGISTER) &&
576 lws_spa_get_string(pss->spa, FGS_REGISTER)[0]) {
578 if (lwsgs_handler_register_form(vhd, wsi, pss))
583 /* get the email monitor to take a look */
584 lws_smtp_client_kick(vhd->smtp_client);
587 lws_snprintf(pss->onward, sizeof(pss->onward),
588 "%s%s", vhd->urlroot,
589 lws_spa_get_string(pss->spa, n));
591 pss->login_expires = 0;
592 pss->logging_out = 1;
593 goto completion_flow;
596 /* we have the username and password... check if admin */
597 if (lwsgw_check_admin(vhd, lws_spa_get_string(pss->spa, FGS_USERNAME),
598 lws_spa_get_string(pss->spa, FGS_PASSWORD))) {
599 if (lws_spa_get_string(pss->spa, FGS_ADMIN))
600 cp = lws_spa_get_string(pss->spa, FGS_ADMIN);
602 if (lws_spa_get_string(pss->spa, FGS_GOOD))
603 cp = lws_spa_get_string(pss->spa, FGS_GOOD);
605 lwsl_info("No admin or good target url in form\n");
608 lwsl_debug("admin\n");
612 /* check users in database */
614 if (!lwsgs_check_credentials(vhd,
615 lws_spa_get_string(pss->spa, FGS_USERNAME),
616 lws_spa_get_string(pss->spa, FGS_PASSWORD))) {
617 lwsl_notice("pw hash check met\n");
618 cp = lws_spa_get_string(pss->spa, FGS_GOOD);
621 lwsl_notice("user/password no good %s %s\n",
622 lws_spa_get_string(pss->spa, FGS_USERNAME),
623 lws_spa_get_string(pss->spa, FGS_PASSWORD));
625 if (!lws_spa_get_string(pss->spa, FGS_BAD)) {
626 lwsl_info("No admin or good target url in form\n");
630 lws_snprintf(pss->onward, sizeof(pss->onward),
631 "%s%s", vhd->urlroot,
632 lws_spa_get_string(pss->spa, FGS_BAD));
634 lwsl_notice("failed: %s\n", pss->onward);
636 goto completion_flow;
639 if (!strcmp(cp1 + n - 12, "lwsgs-logout")) {
641 lwsl_notice("/logout\n");
643 if (lwsgs_get_sid_from_wsi(wsi, &pss->login_session)) {
644 lwsl_notice("not logged in...\n");
649 * We keep the same session, but mark it as not
650 * being associated to any authenticated user
653 lwsgw_update_session(vhd, &pss->login_session, "");
655 if (!lws_spa_get_string(pss->spa, FGS_GOOD)) {
656 lwsl_info("No admin or good target url in form\n");
660 lws_snprintf(pss->onward, sizeof(pss->onward),
661 "%s%s", vhd->urlroot,
662 lws_spa_get_string(pss->spa, FGS_GOOD));
664 pss->login_expires = 0;
665 pss->logging_out = 1;
667 goto completion_flow;
673 lws_snprintf(pss->onward, sizeof(pss->onward),
674 "%s%s", vhd->urlroot, cp);
676 if (lwsgs_get_sid_from_wsi(wsi, &sid))
679 pss->login_expires = lws_now_secs() +
680 vhd->timeout_absolute_secs;
683 /* we need to create a new, authorized session */
685 if (lwsgs_new_session_id(vhd, &pss->login_session,
686 lws_spa_get_string(pss->spa, FGS_USERNAME),
690 lwsl_notice("Creating new session: %s\n",
691 pss->login_session.id);
694 * we can just update the existing session to be
697 lwsl_notice("Authorizing existing session %s", sid.id);
698 lwsgw_update_session(vhd, &sid,
699 lws_spa_get_string(pss->spa, FGS_USERNAME));
700 pss->login_session = sid;
704 lwsgw_expire_old_sessions(vhd);
705 goto redirect_with_cookie;
707 case LWS_CALLBACK_HTTP_DROP_PROTOCOL:
708 if (pss && pss->spa) {
709 lws_spa_destroy(pss->spa);
714 case LWS_CALLBACK_ADD_HEADERS:
715 lwsgw_expire_old_sessions(vhd);
717 lwsl_warn("ADD_HEADERS\n");
719 args = (struct lws_process_html_args *)in;
722 if (pss->delete_session.id[0]) {
724 lwsgw_cookie_from_session(&pss->delete_session, 0, &pc,
725 cookie + sizeof(cookie) - 1);
727 lwsl_notice("deleting cookie '%s'\n", cookie);
729 if (lws_add_http_header_by_name(wsi,
730 (unsigned char *)"set-cookie:",
731 (unsigned char *)cookie, pc - cookie,
732 (unsigned char **)&args->p,
733 (unsigned char *)args->p + args->max_len))
737 if (!pss->login_session.id[0])
738 lwsgs_get_sid_from_wsi(wsi, &pss->login_session);
740 if (!pss->login_session.id[0] && !pss->logging_out) {
742 pss->login_expires = lws_now_secs() +
743 vhd->timeout_anon_absolute_secs;
744 if (lwsgs_new_session_id(vhd, &pss->login_session, "",
748 lwsgw_cookie_from_session(&pss->login_session,
749 pss->login_expires, &pc,
750 cookie + sizeof(cookie) - 1);
752 lwsl_info("LWS_CALLBACK_ADD_HEADERS: setting cookie '%s'\n", cookie);
753 if (lws_add_http_header_by_name(wsi,
754 (unsigned char *)"set-cookie:",
755 (unsigned char *)cookie, pc - cookie,
756 (unsigned char **)&args->p,
757 (unsigned char *)args->p + args->max_len))
768 redirect_with_cookie:
769 p = buffer + LWS_PRE;
771 end = p + sizeof(buffer) - LWS_PRE;
773 lwsl_warn("%s: redirect_with_cookie\n", __func__);
775 if (lws_add_http_header_status(wsi, HTTP_STATUS_SEE_OTHER, &p, end))
779 char loc[1024], uria[128];
782 lws_hdr_copy_fragment(wsi, uria, sizeof(uria),
783 WSI_TOKEN_HTTP_URI_ARGS, 0);
784 n = lws_snprintf(loc, sizeof(loc), "%s?%s",
786 lwsl_notice("%s: redirect to '%s'\n", __func__, loc);
787 if (lws_add_http_header_by_token(wsi, WSI_TOKEN_HTTP_LOCATION,
788 (unsigned char *)loc, n, &p, end))
792 if (lws_add_http_header_by_token(wsi, WSI_TOKEN_HTTP_CONTENT_TYPE,
793 (unsigned char *)"text/html", 9, &p, end))
795 if (lws_add_http_header_content_length(wsi, 0, &p, end))
798 if (pss->delete_session.id[0]) {
799 lwsgw_cookie_from_session(&pss->delete_session, 0, &pc,
800 cookie + sizeof(cookie) - 1);
802 lwsl_notice("deleting cookie '%s'\n", cookie);
804 if (lws_add_http_header_by_name(wsi,
805 (unsigned char *)"set-cookie:",
806 (unsigned char *)cookie, pc - cookie,
813 if (!pss->login_session.id[0]) {
814 pss->login_expires = lws_now_secs() +
815 vhd->timeout_anon_absolute_secs;
816 if (lwsgs_new_session_id(vhd, &pss->login_session, "",
817 pss->login_expires)) {
822 pss->login_expires = lws_now_secs() +
823 vhd->timeout_absolute_secs;
825 if (pss->login_session.id[0] || pss->logging_out) {
827 * we succeeded to login, we must issue a login
828 * cookie with the prepared data
832 lwsgw_cookie_from_session(&pss->login_session,
833 pss->login_expires, &pc,
834 cookie + sizeof(cookie) - 1);
836 lwsl_err("%s: setting cookie '%s'\n", __func__, cookie);
838 pss->logging_out = 0;
840 if (lws_add_http_header_by_name(wsi,
841 (unsigned char *)"set-cookie:",
842 (unsigned char *)cookie, pc - cookie,
849 if (lws_finalize_http_header(wsi, &p, end))
852 // lwsl_hexdump_notice(start, p - start);
854 n = lws_write(wsi, start, p - start, LWS_WRITE_H2_STREAM_END |
855 LWS_WRITE_HTTP_HEADERS);
862 if (lws_http_transaction_completed(wsi))
868 static const struct lws_protocols protocols[] = {
870 "protocol-generic-sessions",
871 callback_generic_sessions,
872 sizeof(struct per_session_data__gs),
877 LWS_EXTERN LWS_VISIBLE int
878 init_protocol_generic_sessions(struct lws_context *context,
879 struct lws_plugin_capability *c)
881 if (c->api_magic != LWS_PLUGIN_API_MAGIC) {
882 lwsl_err("Plugin API %d, library API %d", LWS_PLUGIN_API_MAGIC,
887 c->protocols = protocols;
888 c->count_protocols = LWS_ARRAY_SIZE(protocols);
889 c->extensions = NULL;
890 c->count_extensions = 0;
895 LWS_EXTERN LWS_VISIBLE int
896 destroy_protocol_generic_sessions(struct lws_context *context)