Class BrowserGate
java.lang.Object
com.iizix.jetty.BrowserGate
The Browser gate of
iiziApp.html (work order CC-BROWSER-GATE). It decides whether a Browser is KNOWN not to run IIZI, and it builds the iiziAppSorry.html page that is served instead: the iiziRun app in the App Store or Google Play, or the advice to update.Two rules, both fail-open, unknown always passes:
rejects(String)matches theUser-Agentagainst a CLOSED list of discontinued Browsers that lack WebSocket with binary frames, or the ECMAScript level the client JavaScript needs (ES2020, measured in the order's report). No version number is read out of a User-Agent: every entry names a Browser whose string can never change again, so the list never needs a version bump. A missing header, or one matching nothing, passes.buildSorryPage(String,AppInfo)substitutes the app's name, description and store links into the page between its comment markers, keeping the markers. Every value is HTML-escaped; the two URLs are attribute-escaped and must behttps:, else their block is removed.
The client gate, an ES5 script at the top of iiziApp.html, catches what no list can by testing the capabilities in the Browser itself; the appID it needs reaches it through APP_ID_MARKER.
- Author:
- Christopher Mindus
Nested Class Summary
Nested ClassesModifier and TypeClassDescriptionstatic final recordWhat the sorry page shows for one application.static final recordOne entry of the list: a discontinued Browser family, how its User-Agent is recognized, and an exclusion for a later engine that kept the family's tokens.static final classThe INFO line of a rejected load, throttled to one per User-Agent per interval, so that production shows how many users the sorry page reaches without a bot filling the log.Field Summary
FieldsModifier and TypeFieldDescriptionstatic final StringThe marker iniiziApp.htmlthat the servlet replaces, per response, with the URL-encoded appID of the request, or with nothing when there is none: "%%APPID%%".static final List<BrowserGate.Entry> The list, CLOSED: discontinued Browsers only.static final BrowserGate.RejectionLogThe rejection INFO line of the server: once per User-Agent per hour, logged by the servlet where it serves the sorry page, and by any later handler that gates a load the same way.Method Summary
Modifier and TypeMethodDescriptionstatic StringbuildSorryPage(String template, BrowserGate.AppInfo info) Builds the sorry page for an application from theiiziAppSorry.htmltemplate.static StringencodeAppID(String appID) URL-encodes an appID for the query string of the client gate.static StringescapeHTML(String s) Escapes text for HTML content and attribute values:&,<,>,"and'.static BrowserGate.EntryThe server gate: tests whether a User-Agent belongs to a Browser KNOWN not to run IIZI.static StringvalidHttpsURL(String url) Validates a store URL: trimmed, at mostMAX_URL_LENGTHcharacters, an absolutehttps:URL with a host, and nothing a URI parser rejects, so no quote, no space, no angle bracket and no control character.
Field Details
APP_ID_MARKER
The marker iniiziApp.htmlthat the servlet replaces, per response, with the URL-encoded appID of the request, or with nothing when there is none: "%%APPID%%".- See Also:
REJECTIONS
The rejection INFO line of the server: once per User-Agent per hour, logged by the servlet where it serves the sorry page, and by any later handler that gates a load the same way.LIST
The list, CLOSED: discontinued Browsers only. The specific entries come before the general ones so that the entry reported is the most telling one: an Opera Mini User-Agent is also a Presto one, a Windows Phone 7 one is also an "MSIE" one.
Method Details
rejects
The server gate: tests whether a User-Agent belongs to a Browser KNOWN not to run IIZI.- Parameters:
userAgent- TheUser-Agentheader, null when the request carried none.- Returns:
- The entry that matched, or null: no header, an empty one, or a Browser not in the list all pass, since unknown always passes.
buildSorryPage
Builds the sorry page for an application from theiiziAppSorry.htmltemplate.Substitution is by comment marker: the text between
<!--NAME-BEGIN-->and<!--NAME-END-->is replaced and the markers stay, so the result is as valid a file as the template. Every pair of a name is processed.App-Name: the escaped name; the template's default text stays when there is none.App-Title: the whole<title>element, in whose text the template's default name - the text of theApp-Namepair - is replaced by the escaped name, so that the title carries no marker: a comment inside<title>is text there, not a comment, anddocument.titleshowed the markers (CC-FIX-PWA-FOLLOWUPS, PWA-D-3). Nothing when the template has no such pair or its text does not carry the default name.App-Description: a<p class="desc">with the escaped description, or nothing, so the block collapses.iOS-LinkandAndroid-Link: the template's own block with itshref="#"replaced by the attribute-escaped URL, or nothing when the URL is absent or nothttps:.Has-App: kept when at least one link is written, else removed.No-App: kept ONLY when neither link is written.
- Parameters:
template- The template, the contents ofiiziAppSorry.html.info- The application's information, null for an unknown application.- Returns:
- The page.
validHttpsURL
Validates a store URL: trimmed, at mostMAX_URL_LENGTHcharacters, an absolutehttps:URL with a host, and nothing a URI parser rejects, so no quote, no space, no angle bracket and no control character. A URL is typed by a customer and is not trusted.- Parameters:
url- The URL, null for none.- Returns:
- The trimmed URL, or null when absent or refused.
escapeHTML
encodeAppID