2

motivation and context

I am designing and implementing the web interface of my bismon server program (a research prototype; in a few words: an orthogonally persistent, reflexive, homoiconic, dynamically-typed, multi-threaded, domain-specific language for static source code analysis; it runs on Linux only). It is free software (on http://github.com/bstarynk/bismon ...), GPLv3+ licensed, still officially unreleased (so 𝛂 stage). A draft report (a draft deliverable for some H2020 research project) describing it in some details is available on http://starynkevitch.net/Basile/bismon-chariot-doc.pdf (whose section §4.1 describes the web interface internals).

The web interface is for some kind of syntactic editor (grossly speaking, imagine "emacs" thru HTTP). I want it to be a single-page web application. I am not very familiar with web technologies (even if I read dozen of books about them). I am using the HTTP server library libonion in bismon, so the bismon process becomes a specialized web server.

My bismon is not a usual web application: it is expected to be used, by a small team (3 to 10 colleagues working on the same project) of trusted people. So there are only a dozen of browsers connected -on a trusted local area network- to a given bismon process. During several months, I would be the only user of that bismon thru the http://localhost:8086/ URL (but I might open that URL in two tabs of the same firefox browser window). There is already a login mechanism which sets a BISMONCOOKIE cookie identifying the web session. And a websocket is used. The web browser is Firefox 65 on Linux, if that matters.

question

how can such a Web application distinguish two tabs on the same browser?

My understanding is that both tabs will share the same URL (e.g. http://localhost:8086/) and the same cookie (e.g. BISMONCOOKIE being the same string, such as n000041R970099188t330716425o_6IHYL1fOROi_58xJPnBLCTe and that string corresponds to some web session object inside the bismon server). The two tabs could show two different views into the global state of my bismon.

Is there some programmatic way, browser side, to uniquely identify a tab? What exactly happens at the level of the HTTP protocol itself? I don't know any HTTP request header field uniquely identifying the tab. Or is it known in the DOM? How?

Let's suppose, for simplicity, that there is some equivalent of <a href='http://localhost:8086/'>link</a> in the DOM (of the dynamic page served by the bookmarked http://localhost:8086/ URL). How can the bismon server separate the action "click to follow the link" from the menu "open link in new tab", assuming a recent Firefox browser? My incomplete understanding is that the same HTTP exchange happens in both cases, and I really want to separate them.

It is well known that a modern browser (like Firefox) makes several TCP connections simultaneously for the same tab; so I cannot use that reliably.

As a simpler example, this very question has some "edit" link. What is happening server-side or protocol-side when I "open that link in other tab" two times?

(perhaps I need to use the websocket -which would be reopened in every different tab and might not be shared between tabs? this could be an answer)

PS. Queinnec's paper Inverting back the inversion of control or, Continuations versus page-centric programming could be related to my question, but I don't yet understand how.

  • 3
    The server doesn't know anything about the tabs. It just knows a stateless request was made, and is able to map that stateless request to a stateful scenario via an identifier like your cookie. You can track that state via the cookie, each websocket connection, an authentication token, some temporary data created upon login, etc. – bitsoflogic Feb 1 at 15:00
  • Ok, but how could the browser create a variant of that state when e.g. "opening a link in a new tab"? Do you recommend setting another cookie? – Basile Starynkevitch Feb 1 at 15:01
  • 1
    I can think of a couple ways that might kind of work depending on the use case. Why do you want to do this? – Jacob Raihle Feb 1 at 15:15
  • 1
    Just a note, probably, you wont be able to make your SPA aware of the multi-tab session since each tab is executed as a fork and exec of the main process. In theory, they are agnostic to each other. As others commented, you will have to implement your own sessions system (you already have It) and some sort of correlation id to correlate user sessions. Binding the browser' User-Agent to the correlation id might help. For example: 1 id token (user) with N different session ids each of wich bound to a User-Agent. – Laiv Feb 1 at 22:56
  • 1
    Different User-Agents probably means different devices (clients). 2 different sessions with the same user id and the very same User-Agent probably means 1 user with multi-tab session or 2 instances of the same browser. – Laiv Feb 1 at 22:58
2

You may create a unique ID (for example a UUID) at the client or let the server create it (and send it to the client at some occasion).

Each request at which the server needs to discern the particular tab should contain that ID.

To transfer that ID in the request you may include it in its parameters or (in case of AJAX) add a custom header.

If the server itself is building all URLs (for example when rendering HTML pages or JSON including URLs), you may have to build the ID server-side if none was given in the request or use the one given in the request and add it to all built URLs (query parameters for GET requests) and forms (hidden form fields for POST requests) to already have them in the first page load. Of course it's possible to modify URLs with a client-side executed script afterwards to contain your ID, too.

If the first page delivered by the server does not have to include any ID and you are really building a Single Page Application, the client usually builds the URLs by itself (or has the ability to add parameters at will) and you have to write your own JavaScript function which stores the ID in some place you can access it to actually augment the requests when building them.

Actually without further ado this lets the server distinguish between single executions of the client and not between the tabs. If you reload the page within the same tab, you would create a new ID instead of reusing the previous one.

You may store that ID in the SessionStorage (client-side) to reuse the ID within the tab across page reloads. Your script may then first lookup that ID in the storage and create a new one if there is none found.

  • I already have such a UID in the BISMONCOOKIE, so I don't entirely understand your suggestion – Basile Starynkevitch Feb 1 at 15:06
  • The cookie is global to all tabs. You need to distinguish the tabs. The question is whether or not you want users to label and retrieve specific tabs, or if every tab / connection is a fresh connection. – bitsoflogic Feb 1 at 15:10
  • Assume a new tab is "fresh" by menu action "open link in new tab" in Firefox. – Basile Starynkevitch Feb 1 at 15:15
  • The creation of the ID I had in mind would be per-execution of your client application - saved in memory. This is totally unrelated to cookies. – Hero Wanders Feb 1 at 15:17
  • How would you translate that ID in HTTP protocol or DOM parlance? – Basile Starynkevitch Feb 1 at 15:17
3

Session storage is tab specific (i.e. not shared across tabs). So you can check session storage for a given key value, create it if it doesn't exist, and include it in any requests you send to your server. This will let both your server-side and client-side applications identify specific tabs.

1

Scopes (lifetimes)

Request scope

  • all info is give as request parameters

Session scope

  • a session is maintained, probably by cookie

Application scope

  • (irrelevant) info is maintained globally

For tabs typically:

Conversation scope

  • As mentioned typically works with maintaining a UUID (for the conversation).

On the server side one could have a thread-safe map by UUID as session attribute for instance. All kind of efficiency considerations. This solution is motivated by the fact that a conversation scope hangs under a session, above a request.

If your server does not provide a conversation scope, one can implement itself.

  • How and when would you create the conversation-specific UUID? I want to keep (and possibly bookmark) the same http://localhost:8086/ URL? – Basile Starynkevitch Feb 1 at 15:30
  • In other words, what is such a "conversation" server-side and browser-side, programmatically speaking? I'm probably ignorant of some simple feature in HTTP or HTML5 or DOM. – Basile Starynkevitch Feb 1 at 15:33
  • It is a passed token (UUID for instance) that identifies the "conversation". A hidden form field. So several "conversations" are created and stored in the session scope and the tokens communicated over the request scope. If there is no provision in the software, one has to code it oneself. HTML & co will not help there I am afraid. See Hero Wanders. – Joop Eggen Feb 1 at 15:39

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.