Per-window Private Browsing
Status
| Per-window Private Browsing | |
| Stage | Feature Inbox |
| Status | In progress |
| Release target | ` |
| Health | OK |
| Status note | This project is currently being developed by a university student in his free time. |
{{#set:Feature name=Per-window Private Browsing
|Feature stage=Feature Inbox |Feature status=In progress |Feature version=` |Feature health=OK |Feature status note=This project is currently being developed by a university student in his free time. }}
Team
| Product manager | ` |
| Directly Responsible Individual | Josh Matthews |
| Lead engineer | Josh Matthews |
| Security lead | Dan Veditz |
| Privacy lead | ` |
| Localization lead | ` |
| Accessibility lead | ` |
| QA lead | ` |
| UX lead | ` |
| Product marketing lead | ` |
| Operations lead | ` |
| Additional members | ` |
{{#set:Feature product manager=`
|Feature feature manager=Josh Matthews |Feature lead engineer=Josh Matthews |Feature security lead=Dan Veditz |Feature privacy lead=` |Feature localization lead=` |Feature accessibility lead=` |Feature qa lead=` |Feature ux lead=` |Feature product marketing lead=` |Feature operations lead=` |Feature additional members=` }}
Open issues/risks
The proposed design will break every addon that uses the existing privite browsing implementation in any way (even just attempting to play nicely with entering/existing).
Stage 1: Definition
1. Feature overview
We want to move away from a global flag model of PB being enabled to a per-window model more in line with other browsers. The implementation should support per-tab private browsing as an implementation detail, but that functionality will not be exposed by default.
2. Users & use cases
Users should be able to open up a new private browsing window without interacting with their existing browsing session in any way (especially through leakage of data from one context to the other).
3. Dependencies
`
4. Requirements
`
Non-goals
We do not want to expose per-tab UI for enabling/disabling private browsing.
Stage 2: Design
5. Functional specification
`
6. User experience design
`
Stage 3: Planning
7. Implementation plan
https://wiki.mozilla.org/Per-window_Private_Browsing has a discussion of various consumers of the existing service and the ways they will be modified.
Unresolved design issues:
- API design for consumers that don't have access to a channel or docshell - duplicate relevant Add/RemoveFoo APIs with Add/RemovePrivateFoo? Something else?
Resolved design issues:
Can't we use a temporary profile in a separate Firefox instance instead?
- It's assumed that we want things like extensions, history, bookmarks, etc. from the user's profile to continue to exist in the private window. A separate profile won't provide these, so this is not a feasible quick and dirty solution.
8. Reviews
Security review
`
Privacy review
`
Localization review
`
Accessibility
`
Quality Assurance review
`
Operations review
`
Stage 4: Development
9. Implementation
Up to date patch queue available at http://hg.mozilla.org/users/josh_joshmatthews.net/pb-per-window/
The metabug for this work is https://bugzilla.mozilla.org/show_bug.cgi?id=pbngen with individual bugs filed for existing consumers of the global service.
Stage 5: Release
10. Landing criteria
` {{#set:Feature open issues and risks=The proposed design will break every addon that uses the existing privite browsing implementation in any way (even just attempting to play nicely with entering/existing). |Feature overview=We want to move away from a global flag model of PB being enabled to a per-window model more in line with other browsers. The implementation should support per-tab private browsing as an implementation detail, but that functionality will not be exposed by default. |Feature users and use cases=Users should be able to open up a new private browsing window without interacting with their existing browsing session in any way (especially through leakage of data from one context to the other). |Feature dependencies=` |Feature requirements=` |Feature non-goals=We do not want to expose per-tab UI for enabling/disabling private browsing. |Feature functional spec=` |Feature ux design=` |Feature implementation plan=https://wiki.mozilla.org/Per-window_Private_Browsing has a discussion of various consumers of the existing service and the ways they will be modified.
Unresolved design issues:
- API design for consumers that don't have access to a channel or docshell - duplicate relevant Add/RemoveFoo APIs with Add/RemovePrivateFoo? Something else?
Resolved design issues:
Can't we use a temporary profile in a separate Firefox instance instead?
- It's assumed that we want things like extensions, history, bookmarks, etc. from the user's profile to continue to exist in the private window. A separate profile won't provide these, so this is not a feasible quick and dirty solution.
|Feature security review=` |Feature privacy review=` |Feature localization review=` |Feature accessibility review=` |Feature qa review=` |Feature operations review=` |Feature implementation notes=Up to date patch queue available at http://hg.mozilla.org/users/josh_joshmatthews.net/pb-per-window/
The metabug for this work is https://bugzilla.mozilla.org/show_bug.cgi?id=pbngen with individual bugs filed for existing consumers of the global service. |Feature landing criteria=` }}
Feature details
| Priority | Unprioritized |
| Rank | 999 |
| Theme / Goal | ` |
| Roadmap | Privacy |
| Secondary roadmap | Firefox Desktop |
| Feature list | ` |
| Project | ` |
| Engineering team | ` |
{{#set:Feature priority=Unprioritized
|Feature rank=999 |Feature theme=` |Feature roadmap=Privacy |Feature secondary roadmap=Firefox Desktop |Feature list=` |Feature project=` |Feature engineering team=` }}
Team status notes
| status | notes | |
| Products | ` | ` |
| Engineering | ` | ` |
| Security | sec-review-needed | Security review requested for Feb 22 |
| Privacy | ` | ` |
| Localization | ` | ` |
| Accessibility | ` | ` |
| Quality assurance | ` | ` |
| User experience | ` | ` |
| Product marketing | ` | ` |
| Operations | ` | ` |
{{#set:Feature products status=`
|Feature products notes=` |Feature engineering status=` |Feature engineering notes=` |Feature security status=sec-review-needed |Feature security health=` |Feature security notes=Security review requested for Feb 22 |Feature privacy status=` |Feature privacy notes=` |Feature localization status=` |Feature localization notes=` |Feature accessibility status=` |Feature accessibility notes=` |Feature qa status=` |Feature qa notes=` |Feature ux status=` |Feature ux notes=` |Feature product marketing status=` |Feature product marketing notes=` |Feature operations status=` |Feature operations notes=` }}
Rationale
The current Private Browsing (PB) implementation in Firefox is very disruptive, because it closes all of your open tabs and windows. Although we do a relatively good job at restoring everything back to the state before initiating the PB session, we should really not require the user to give up their existing session.
This page summarizes the design which can lead to a per-window Private Browsing implementation for Desktop Firefox.
Global Private Browsing Mode Design
The global mode PB implementation is basically an application wide boolean flag which designates whether the PB mode is on or off. The private browsing service manages this global flag, and sends a bunch of notifications when the global mode is changing (for example, when the user invokes the Private Browsing flag). Each module which needs to store data which can identify the websites that a user has previously visited needs to handle these notifications in order to adjust its behavior depending on the PB mode flag, and refrain from storing such data inside this mode. For more information on how the existing API works, see this document.
Per-window Private Browsing Mode Design
In order to move towards a per-window PB design, we can't represent the PB state as a global flag any more. At a birds-eye view, we need to store a per-window boolean flag and each module which needs to handle its storage needs based on the PB status should somehow be able to know which window is ultimately responsible for the request at hand.
The per-window flag is going to be handled by a Gecko object called a docshell. A docshell is simply an object which stores the information associated which every document that Gecko loads which has a presentation. Each docshell can either be a content or a chrome docshell. A chrome docshell represents a document which has chrome privileges, such as browser.xul which renders Firefox's main window, or about:addons. A content docshell represents a document which does not have chrome privileges, which is most often used to load a website inside the browser.
The docshells are arranged in a tree. For example, in a simple browser window rendering Google's homepage, there is a chrome docshell representing the browser window, and a content docshell rendering the google.com homepage (plus another content docshell as its child reprenting an iframe inside Google's home page).
We will leverage this structure in order to provide a per-tab Private Browsing API. Firefox is probably not going to expose per-tab PB mode, as it will be too confusing to users, but we can have a more flexible API which add-ons can leverage.
Specification
Here is a per-module specification for how the per-window Private Browsing mode will be implemented. This specification is borrowing from the specification for the global private browsing mode.
DocShell
Each docshell maintains a privateBrowsing boolean flag.
- Upon docshell creation:
- For chrome docshells, the flag is initialized to false.
- For content docshells, the flag is initialized to the value of the parent docshell's privateBrowsing flag.
- On getting, the docshell returns the last value set for that flag.
- On setting, the following happens:
- If the docshell is a content docshell, the set operation fails, returning NS_ERROR_FAILURE, unless the set operation is being invoked by a parent docshell.
- If the docshell is a chrome docshell, the set operation succeeds. The docshell will look into all of its child subtree, and set the privateBrowsing flag on each element in its subtree with its own flag.
History
Cache
Cookies
The Cookie Service will maintain an in-memory hashtable for the cookies set in PB mode. This table will be completely separate from the normal cookie storage that it uses, and it is possible for cookies with the same hostname and the same name to be stored in both tables.
- On setting a cookie, the Cookie Service tries to get a docshell for the channel setting the cookie (hint: we may be able to borrow some code from nsCookiePermission::GetOriginatingURI). If there is a docshell associated with the channel, and its privateBrowsing flag is set to true, the Cookie Service will store the cookie in its in-memory PB mode hashtable. Otherwise, it will use its normal storage.
- On getting a cookie, the Cookie Service tries to get a docshell for the channel getting the cookie. If there is a docshell associated with the channel, and its privateBrowsing flag is set to true, the Cookie Service will use its in-memory PB hashtable. Otherwise, it will use its normal storage.
Downloads
Implementation concerns
Channels
The design which requires access to docshells is fundamentally broken for e10s, where networking occurs in the parent process and the relevant docshell is in a content process. This patch demonstrates a correct implementation for HTTP channels, whereby a concrete nsHttpChannel object can be reliably queried as to its PB usage, regardless of process. Possible solutions:
- add a new interface (or modify nsIChannel) to add private browsing status to every channel type, and propagate the information from the child to the parent as in the previously-linked HTTP patch
- make docshells implement IPDL actors, so that querying the docshell on the parent gives something useful. probably a non-starter.
I've chosen to make a clean break and create an nsIPrivateBrowserConsumer interface. This patch demonstrates the application of this to FTP and HTTP channels in a very elegant manner.
Cookies
The cookie service already has a non-PB DB and a PB DB. However, functions like GetEnumerator assume that they can enumerate all the cookies of the currently active DB - how should this interact with the cookie list, which call this to list all cookies?
"Grouping"
Ehsan and I agreed that there should be more of a separation than just PB vs. non-PB for some concepts like cache sessions, downloads, HTTP connectinos, etc. These should be grouped based on root docshell, so that when a root docshell in PB is closed, the corresponding session data should be destroyed.