summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorPaul Buetow <paul@buetow.org>2026-07-07 14:53:53 +0300
committerPaul Buetow <paul@buetow.org>2026-07-07 14:53:53 +0300
commit1f28ff5ac4a8a466113296d9510fe91f8cd13bc3 (patch)
tree5739ceca594a5310f199ffbadd32923cb1c52941
parent4dd00e26756300c0280ba4a724b1dcfa7e5ea33d (diff)
ychat: redirect to login page on invalid session (not blank page)
When a chat request carried an invalid/expired tmpid (no matching session), reqp::parse returned early with an empty response, leaving the browser with a blank page -- e.g. after a server restart (sessions are in-memory) or reloading a bookmarked frameset URL with a stale tmpid. Instead serve a small redirect.html page that does a top-level JS redirect (top.location.href) back to the login page (httpd.startsite, i.e. index.html). Using a *top-level* redirect matters because the chat UI is a frameset of iframes (stream/online/input) that each reload with ?tmpid=... ; a plain in-iframe redirect would render three stacked login forms inside the frameset, while top.location sends the whole chat window back to the login form. top === self when this page is loaded directly (no parent frameset), so one line covers both cases. A noscript <a> link is included as a fallback. The redirect response is built in the p_sess==NULL branch (mirroring the header-wrapping at the end of parse()) and returned, so the normal template-render path -- which would re-render the originally-requested frame -- does not run.
-rw-r--r--ychat/html/redirect.html26
-rw-r--r--ychat/src/reqp.cpp22
2 files changed, 48 insertions, 0 deletions
diff --git a/ychat/html/redirect.html b/ychat/html/redirect.html
new file mode 100644
index 0000000..4a7f326
--- /dev/null
+++ b/ychat/html/redirect.html
@@ -0,0 +1,26 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
+<html>
+<head>
+ <meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1" />
+ <meta name="viewport" content="width=device-width, initial-scale=1.0" />
+ <title>Session expired</title>
+ <link rel="stylesheet" href="style.css" type="text/css" />
+ <script language="JavaScript">
+ <!--
+ // Served when a chat request carries an invalid/expired tmpid (no
+ // matching session). The chat UI is a frameset of iframes (stream,
+ // online, input), each of which reloads with ?tmpid=... ; rendering the
+ // login form *inside* each iframe would stack three login forms in the
+ // frameset. Instead redirect the top-level window so the whole chat
+ // window returns to the login page. top === self when this page is
+ // loaded directly (no parent frameset), so the same line covers both
+ // the in-iframe and the direct case.
+ top.location.href = "%%httpd.startsite%%";
+ //-->
+ </script>
+</head>
+<body>
+ <div>Your chat session is no longer valid.
+ <a href="%%httpd.startsite%%">Return to the login page</a>.</div>
+</body>
+</html> \ No newline at end of file
diff --git a/ychat/src/reqp.cpp b/ychat/src/reqp.cpp
index 907161d..aa60078 100644
--- a/ychat/src/reqp.cpp
+++ b/ychat/src/reqp.cpp
@@ -78,7 +78,29 @@ reqp::parse(context *p_context)
}
else
{
+ // The session is invalid/expired (no tmpid match). The old code
+ // returned here with an empty response, leaving the browser with a
+ // blank page. Instead serve a small redirect page (redirect.html)
+ // that does a *top-level* JS redirect back to the login page, so the
+ // whole chat window returns to the login form rather than rendering
+ // three stacked login forms inside the frameset's iframes.
wrap::system_message(SESSERR);
+ map_params["request"] = "redirect.html";
+ map_params["content-type"] = "text/html";
+
+ // Build the full HTTP response here (mirroring the header wrapping
+ // at the end of parse()) and return, so the normal template-render
+ // path below -- which would re-render the originally-requested frame
+ // (e.g. stream.html) -- doesn't run.
+ *p_response = wrap::HTML->parse( map_params );
+
+ string s_resp;
+ s_resp.append( s_http );
+ s_resp.append( s_http_colength + tool::int2string(p_response->size()) + "\r\n" +
+ s_http_cotype + map_params["content-type"] +
+ s_http_cotype_add + "\r\n" );
+ s_resp.append( *p_response );
+ *p_response = s_resp;
return;
}