diff options
| author | Paul Buetow <paul@buetow.org> | 2026-07-07 14:53:53 +0300 |
|---|---|---|
| committer | Paul Buetow <paul@buetow.org> | 2026-07-07 14:53:53 +0300 |
| commit | 1f28ff5ac4a8a466113296d9510fe91f8cd13bc3 (patch) | |
| tree | 5739ceca594a5310f199ffbadd32923cb1c52941 | |
| parent | 4dd00e26756300c0280ba4a724b1dcfa7e5ea33d (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.html | 26 | ||||
| -rw-r--r-- | ychat/src/reqp.cpp | 22 |
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; } |
