Internet Browser: Difference between revisions
(30 intermediate revisions by 3 users not shown) | |||
Line 1: | Line 1: | ||
Nintendo Switch does not have a normal Internet Browser for user usage. However, there is multiple browser applets. It is the [https://web.archive.org/web/20170304075230/https://gl.access-company.com/news_event/archives/2017/170303/ NetFront NX] browser, which is based on Webkit. | Nintendo Switch does not have a normal Internet Browser for user usage. However, there is multiple browser applets. It is the [https://web.archive.org/web/20170304075230/https://gl.access-company.com/news_event/archives/2017/170303/ NetFront NX] browser, which is based on Webkit. | ||
When linking the Nintendo Account with Facebook, the Facebook Auth website will open, offering a search box that can be used to browse the Internet ("LoginApplet"). Alternatively, it can be accessed with | When linking the Nintendo Account with Facebook, the Facebook Auth website will open, offering a search box that can be used to browse the Internet ("LoginApplet"). Alternatively, it can be accessed with custom DNS settings which simulate a Wi-Fi login page ([[#WifiWebAuthApplet|WifiWebAuthApplet]] for captive-portal). | ||
== Known User Agent Strings == | == Known User Agent Strings == | ||
Line 34: | Line 34: | ||
| [[6.1.0]] | | [[6.1.0]] | ||
| Mozilla/5.0 (Nintendo Switch; <appletname>) AppleWebKit/601.6 (KHTML, like Gecko) NF/4.0.0.10.14 NintendoBrowser/5.1.0.17806 | | Mozilla/5.0 (Nintendo Switch; <appletname>) AppleWebKit/601.6 (KHTML, like Gecko) NF/4.0.0.10.14 NintendoBrowser/5.1.0.17806 | ||
|- | |||
| [[10.0.0]] | |||
| Mozilla/5.0 (Nintendo Switch; <appletname>) AppleWebKit/606.4 (KHTML, like Gecko) NF/6.0.1.15.4 NintendoBrowser/5.1.0.20389 | |||
|} | |} | ||
Line 86: | Line 89: | ||
| Just displays an error-code. | | Just displays an error-code. | ||
| Yes | | Yes | ||
| 0100000000001010 | |||
| | |||
|- | |||
| NsoApplet | |||
| Nintendo Switch Online menu | |||
| | |||
| | |||
| 0100000000001010 | | 0100000000001010 | ||
| | | | ||
Line 120: | Line 130: | ||
Prior to version [[3.0.0]], this applet was launched when attempting a system update from recovery mode if needed. This was changed to display a "This feature is not available." popup instead. | Prior to version [[3.0.0]], this applet was launched when attempting a system update from recovery mode if needed. This was changed to display a "This feature is not available." popup instead. | ||
The conntest URL from [[#WebWifiPageArg]] is used to poll whether the connection is usable, with the SDK [[libcurl]]. | |||
In later versions the above domain was replaced with [[Network|ctest.{...}]]. | |||
==Whitelisted Applets== | ==Whitelisted Applets== | ||
Line 155: | Line 169: | ||
You can invite friends to the room via | You can invite friends to the room via | ||
the Nintendo Switch Online Lounge app. | the Nintendo Switch Online Lounge app. | ||
=== NsoApplet === | |||
[11.0.0+] This applet handles the new Nintendo Switch Online menu, which is launched from qlaunch. | |||
The initial page loaded by this applet is: <nowiki>"https://%.nso.nintendo.net/</nowiki>{string from [[#TLVs|TLV]] 0x2}" | |||
== ShopN == | == ShopN == | ||
Line 201: | Line 220: | ||
== Heap == | == Heap == | ||
The size used for [[SVC|svcSetHeapSize]] by the web-applets is 0x15600000. Under ShopN, the largest size that can be passed to this without an error being returned, is 0x1B400000. | |||
The size used by title 010000000000100A (on 10.0.0 at least) is 0x14200000. | |||
The heap for the main-codebin (<code>malloc</code>/<code>operator new</code>) uses nn::lmem::*ExpHeap. [8.0.0+] <code>malloc</code>/<code>operator new</code> now checks the return-addr (addr located in a relevant NRO), with wkc_malloc_crashonfailure being called for the allocation if the check passes, otherwise a normal allocation is done (the code which runs for this will Abort if allocation fails). | |||
<code>malloc</code> passes the input size directly to the called func. <code>operator new</code> when handling normal non-wkc allocations passes the following to the called func: <code>sxtw x1, {inw0}</code> (for wkc allocations the size is passed directly). [12.1.0+] The size is now passed directly (64bit) without using sxtw. | |||
[11.0.0+] There's now optional code for using [[SVC|svcMapPhysicalMemoryUnsafe]] etc, however it's unknown what sets the flag for this. An Abort string used this is: "{path}/TransferredMemoryManager.cpp" | |||
== Applet Launching == | == Applet Launching == | ||
The web-applets are launched using a storage containing the input arg data, on exit the output storage contains the "*ReturnValue" reply data | The web-applets are launched using a storage containing the input arg data, on exit the output storage contains the "*ReturnValue" reply data. | ||
Input/output storage size for TLV data is 0x2000-bytes. | |||
=== Library Applet Versions === | === Library Applet Versions === | ||
Line 217: | Line 245: | ||
|- | |- | ||
| [5.0.0+] || 0x50000 | | [5.0.0+] || 0x50000 | ||
|- | |||
| [6.0.0+] || 0x60000 | |||
|- | |||
| [8.0.0+] || 0x80000 | |||
|} | |} | ||
Line 236: | Line 268: | ||
| 2 | | 2 | ||
| Login | | Login | ||
|- | |||
| 3 | |||
| Offline | |||
|- | |- | ||
| 4 | | 4 | ||
Line 248: | Line 283: | ||
| 7 | | 7 | ||
| Lobby | | Lobby | ||
|- | |||
| 8 | |||
| [[#NsoApplet|Lhub]] | |||
|} | |} | ||
=== WebSession === | === WebSession === | ||
With [5.0.0+] sdk-nso added <code>nn::web::Session::</code>. | With [5.0.0+] sdk-nso added <code>nn::web::Session::</code>. With [6.0.0+] this was removed, however it was reintroduced with [7.0.0+] as <code>nn::web::*WebSession</code> (for ShimKind Offline and Web). | ||
This is for sending/receiving [[#SessionMessage]]s via applet Interactive storage. | This is for sending/receiving [[#SessionMessage]]s via applet Interactive storage. | ||
During state init, max_messages is set to 0xA | During state init, max_messages is set to 0xA ([7.0.0+] 0x10), with message_count=0 and cur_size=0. [5.0.0-5.1.0] max_size is set to 0x5000. [7.0.0+] Two queues are used for message_count/cur_size: first one is for BrowserEngineContent (max_size 0x8000 is used), the second one is for non-BrowserEngineContent (max_size 0x1000 is used). | ||
When sending messages, there has to be an available message slot available (<code>max_messages!=message_count</code>), and there has to be enough space | When sending messages, there has to be an available message slot available (<code>max_messages!=message_count</code>), and there has to be enough space available (<code>msghdr_contentsize+0x10 + cur_size <= max_size</code>). After pushing the storage, message_count is incremented and cur_size is increased by <code>msghdr_contentsize+0x10</code>. | ||
When receiving messages, it will repeatedly pop Interactive output storage until no more are available. | When receiving messages, it will repeatedly pop Interactive output storage until no more are available. Non-Ack messages are Acked. | ||
* Ack: Verifies that message_count is not already 0, then decrements it. Then cur_size is decreased by the u32 loaded from msgcontent+0. | * Ack: Verifies that message_count is not already 0, then decrements it. Then cur_size is decreased by the u32 loaded from msgcontent+0. | ||
* 0x0: Does some validation | * 0x0: Does some validation. Reads the message content into the user buffer, when contentsize is non-zero. The original contentsize is written to an user output param. The last byte in the user buffer (contentsize clamped to the user max-buf-size, -1) is set to 0 for NUL-termination. | ||
Next info was tested in 9.0.0 | |||
In the js side (which is only available when enabled via the JsExtensionEnabled TLV), there is a method called <code>window.nx.sendMessage(arg)</code> that sends data to the native side, this method returns a boolean indicating if sending was successful and accepts a string as an argument. The string is encoded like a C null terminated string in the message content. For receive messages from native part, there is a dom event called <code>message</code> which is dispatched when a message arrives. The event can be listened using <code>window.nx.addEventListener("message", callback)</code> being callback a function which first parameter is like a dom event arg and contains a member called <code>data</code> which contains the string decoded from the arrived message. | |||
If messages aren't acked by the native part, js side will not longer receive messages. Ack to web applet '''must''' have 4 bytes after the message content or the applet will Abort. | |||
==== SessionMessage ==== | ==== SessionMessage ==== | ||
Line 277: | Line 321: | ||
| Size from header | | Size from header | ||
| Message content | | Message content | ||
|- | |||
| After message content | |||
| 0x4 if message is ack, 0x0 otherwise | |||
| Padding | |||
|} | |} | ||
Line 288: | Line 336: | ||
| 0x0 | | 0x0 | ||
| 0x4 | | 0x4 | ||
| Message | | Message Kind ([[#WebSessionSendMessageKind]] / [[#WebSessionReceiveMessageKind]]) | ||
|- | |- | ||
| 0x4 | | 0x4 | ||
| 0x4 | | 0x4 | ||
| | | Data size following the header. | ||
|- | |- | ||
| 0x8 | | 0x8 | ||
Line 299: | Line 347: | ||
|} | |} | ||
==== | ==== WebSessionSendMessageKind ==== | ||
This is "nn::web::detail::WebSessionSendMessageKind". | |||
{| class="wikitable" border="1" | {| class="wikitable" border="1" | ||
|- | |- | ||
Line 308: | Line 358: | ||
| 0x0 | | 0x0 | ||
| Arbitrary | | Arbitrary | ||
| | | BrowserEngine Content, NUL-terminated string. Used to communicate with the applet via JsExtensions used by the Js being run by the applet on the current page. | ||
|- | |||
| 0x100 | |||
| 0x0 | |||
| SystemMessage Appear. Requests the applet to Appear, this is only needed with [[#WebSessionBootMode]] AllForegroundInitiallyHidden. | |||
|- | |- | ||
| 0x1000 | | 0x1000 | ||
| | | 0xC | ||
| Ack. Content: first u32 is the entire storage size of the message being acked, | | Ack. Content: first u32 is the entire storage size of the message being acked, the rest is not used. | ||
|} | |||
==== WebSessionReceiveMessageKind ==== | |||
This is "nn::web::detail::WebSessionReceiveMessageKind". | |||
{| class="wikitable" border="1" | |||
|- | |||
! ID | |||
! Content size | |||
! Description | |||
|- | |||
| 0x0 | |||
| Arbitrary | |||
| BrowserEngine Content, see [[#WebSessionSendMessageKind]]. | |||
|- | |||
| 0x1000 | |||
| 0xC | |||
| Ack BrowserEngine | |||
|- | |||
| 0x1001 | |||
| 0xC | |||
| Ack SystemMessage | |||
|} | |} | ||
Line 328: | Line 404: | ||
| 0x104 || 0x400 || Initial URL navigated to by the applet. | | 0x104 || 0x400 || Initial URL navigated to by the applet. | ||
|- | |- | ||
| 0x504 || 0x10 || NIFM Network UUID. Can be value zero. Only used by the applet when conntest_url | | 0x504 || 0x10 || NIFM Network UUID. Can be value zero. Only used by the applet when conntest_url is set. | ||
|- | |- | ||
| 0x514 || 0x4 || Input value for nifm cmd SetRequirementByRevision. Can be value zero. Only used by the applet when conntest_url | | 0x514 || 0x4 || Input value for nifm cmd SetRequirementByRevision. Can be value zero. Only used by the applet when conntest_url is set. | ||
|} | |} | ||
This is the input struct for WifiWebAuthApplet. This is a total of 0x518-bytes. | This is the input struct for WifiWebAuthApplet. This is a total of 0x518-bytes. | ||
When the conntest_url is empty, the applet will test the connection with nifm and throw an error on failure. | |||
=== WebWifiReturnValue === | === WebWifiReturnValue === | ||
Line 367: | Line 443: | ||
|} | |} | ||
This is the 0x1010-byte output storage used by all non-WebWifi applets - except for Share which returns a TLV storage on [3.0.0+]. | This is the 0x1010-byte output storage used by all non-WebWifi applets - except for Share which returns a TLV storage on [3.0.0+], and Web on [8.0.0+]. | ||
=== WebArgHeader === | === WebArgHeader === | ||
Line 401: | Line 477: | ||
Web TLV used in the input web Arg storage, after [[#WebArgHeader]]. This is a total of 0x8-bytes. | Web TLV used in the input web Arg storage, after [[#WebArgHeader]]. This is a total of 0x8-bytes. | ||
=== WebBootFooterButtonEntry === | |||
{| class="wikitable" border="1" | |||
|- | |||
! Offset | |||
! Size | |||
! Description | |||
|- | |||
| 0x0 || 0x4 || [[#FooterButtonId]] | |||
|- | |||
| 0x4 || 0x1 || u8 bool visible flag | |||
|- | |||
| 0x5 || 0x2 || ? | |||
|- | |||
| 0x7 || 0x1 || ? | |||
|} | |||
=== TLVs === | === TLVs === | ||
Line 497: | Line 588: | ||
| 0x20 | | 0x20 | ||
| [[Capture_services|AlbumEntry]] | | [[Capture_services|AlbumEntry]] | ||
| | | AlbumEntry0 | ||
|- | |- | ||
| [1.0.0+] | | [1.0.0+] | ||
Line 623: | Line 714: | ||
| 0x1 | | 0x1 | ||
| u8 bool | | u8 bool | ||
| MediaPlayerUserGestureRestrictionEnabled | | [6.0.0+] MediaAutoPlayEnabled ([2.0.0-5.1.0] MediaPlayerUserGestureRestrictionEnabled) | ||
|- | |- | ||
| [2.0.0+] | | [2.0.0+] | ||
Line 672: | Line 763: | ||
| 0x10 | | 0x10 | ||
| u8 array | | u8 array | ||
| | | AdditionalMediaData0 (If the user-input size is less than 0x10, the remaining tmp data used for the TLV is cleared) | ||
|- | |- | ||
| [4.0.0+] | | [4.0.0+] | ||
Line 743: | Line 834: | ||
| u8 bool | | u8 bool | ||
| PageScrollIndicatorEnabled | | PageScrollIndicatorEnabled | ||
|- | |||
| [6.0.0+] | |||
| | |||
| 0x37 | |||
| 0x1 | |||
| u8 bool | |||
| MediaPlayerSpeedControlEnabled | |||
|- | |||
| [6.0.0+] | |||
| Share | |||
| 0x38 | |||
| 0x20 | |||
| [[Capture_services|AlbumEntry]] | |||
| AlbumEntry1 | |||
|- | |||
| [6.0.0+] | |||
| Share | |||
| 0x39 | |||
| 0x20 | |||
| [[Capture_services|AlbumEntry]] | |||
| AlbumEntry2 | |||
|- | |||
| [6.0.0+] | |||
| Share | |||
| 0x3A | |||
| 0x20 | |||
| [[Capture_services|AlbumEntry]] | |||
| AlbumEntry3 | |||
|- | |||
| [6.0.0+] | |||
| Share | |||
| 0x3B | |||
| 0x10 | |||
| u8 array | |||
| AdditionalMediaData1 | |||
|- | |||
| [6.0.0+] | |||
| Share | |||
| 0x3C | |||
| 0x10 | |||
| u8 array | |||
| AdditionalMediaData2 | |||
|- | |||
| [6.0.0+] | |||
| Share | |||
| 0x3D | |||
| 0x10 | |||
| u8 array | |||
| AdditionalMediaData3 | |||
|- | |||
| [6.0.0+] | |||
| BootFooterButton | |||
| 0x3E | |||
| 0x80 | |||
| Array of [[#WebBootFooterButtonEntry]] with 0x10 entries. | |||
| BootFooterButton | |||
|- | |||
| [6.0.0+] | |||
| | |||
| 0x3F | |||
| 0x4 | |||
| float | |||
| OverrideWebAudioVolume | |||
|- | |||
| [6.0.0+] | |||
| | |||
| 0x40 | |||
| 0x4 | |||
| float | |||
| OverrideMediaAudioVolume | |||
|- | |||
| [7.0.0+] | |||
| | |||
| 0x41 | |||
| 0x4 | |||
| u32 enum [[#WebSessionBootMode]] | |||
| BootMode | |||
|- | |||
| [7.0.0+] | |||
| | |||
| 0x42 | |||
| 0x1 | |||
| u8 bool | |||
| Enables using [[#WebSession]] when set. | |||
|- | |||
| [8.0.0+] | |||
| Offline | |||
| 0x43 | |||
| 0x1 | |||
| u8 bool | |||
| MediaPlayerUiEnabled | |||
|- | |||
| [11.0.0+] | |||
| | |||
| 0x44 | |||
| 0x1 | |||
| bool | |||
| TransferMemoryEnabled | |||
|} | |} | ||
Offline: title to load the content from is controlled by ApplicationId/SystemDataId. With DocumentKind_OfflineHtmlPage, it will ignore this and only load from the user-process title. | Offline: title to load the content from is controlled by ApplicationId/SystemDataId. With DocumentKind_OfflineHtmlPage, it will ignore this and only load from the user-process title. | ||
Offline DocumentPath: Initial document path in RomFS, without the leading '/'. For DocumentKind_OfflineHtmlPage, this is relative to "html-document/" in RomFS. For the other DocumentKind values, this is relative to "/" in RomFS. | Offline DocumentPath: Initial document path in RomFS, without the leading '/'. For DocumentKind_OfflineHtmlPage, this is relative to "html-document/" in RomFS. For the other DocumentKind values, this is relative to "/" in RomFS. This path must contain ".htdocs/". | ||
Share/Lobby: if a non-zero userID isn't set, the applet will launch the profile-selector applet to select an account. | Share/Lobby: if a non-zero userID isn't set, the applet will launch the profile-selector applet to select an account. | ||
Share: An error will be displayed if neither AlbumEntry or ApplicationAlbumEntry are set, with [[#ShareStartPage|ShareStartPage_Default]]. | Share: An error will be displayed if neither AlbumEntry or ApplicationAlbumEntry are set, with [[#ShareStartPage|ShareStartPage_Default]]. | ||
[6.0.0+] <code>AddAlbumEntryAndMediaData</code> was added: | |||
* Looks for AlbumEntry{N} TLVs, when a TLV is not found it is written, then the associated AdditionalMediaData{N} TLV is written the same way as AdditionalMediaData0. If all AlbumEntry{N} TLVs already exist, this returns without writing anything. | |||
TransferMemoryEnabled: sdknso only exposes this for the Web applet. The sdknso func uses <code>nn::os::QueryMemoryInfo</code> at the start of the func, however the output is unused. The applet doesn't seem to parse this TLV. | |||
==== Output TLVs ==== | ==== Output TLVs ==== | ||
Line 757: | Line 951: | ||
|- | |- | ||
! System Version | ! System Version | ||
! Applets | |||
! Type | ! Type | ||
! Size | ! Size | ||
Line 763: | Line 958: | ||
|- | |- | ||
| [3.0.0+] | | [3.0.0+] | ||
| Share, Web | |||
| 0x1 | | 0x1 | ||
| 0x4 | | 0x4 | ||
Line 769: | Line 965: | ||
|- | |- | ||
| [3.0.0+] | | [3.0.0+] | ||
| Share, Web | |||
| 0x2 | | 0x2 | ||
| | | | ||
Line 775: | Line 972: | ||
|- | |- | ||
| [3.0.0+] | | [3.0.0+] | ||
| Share, Web | |||
| 0x3 | | 0x3 | ||
| 0x8 | | 0x8 | ||
Line 781: | Line 979: | ||
|- | |- | ||
| [3.0.0+] | | [3.0.0+] | ||
| Share | |||
| 0x4 | | 0x4 | ||
| 0x4 | | 0x4 | ||
Line 787: | Line 986: | ||
|- | |- | ||
| [3.0.0+] | | [3.0.0+] | ||
| Share | |||
| 0x5 | | 0x5 | ||
| | | | ||
Line 793: | Line 993: | ||
|- | |- | ||
| [3.0.0+] | | [3.0.0+] | ||
| Share | |||
| 0x6 | | 0x6 | ||
| 0x8 | | 0x8 | ||
Line 799: | Line 1,000: | ||
|- | |- | ||
| [3.0.0+] | | [3.0.0+] | ||
| Share | |||
| 0x7 | | 0x7 | ||
| | | | ||
Line 805: | Line 1,007: | ||
|- | |- | ||
| [3.0.0+] | | [3.0.0+] | ||
| Share | |||
| 0x8 | | 0x8 | ||
| 0x8 | | 0x8 | ||
| u64 | | u64 | ||
| PostIdSize | | PostIdSize | ||
|- | |||
| [8.0.0+] | |||
| Web | |||
| 0x9 | |||
| 0x1 | |||
| u8 bool | |||
| MediaPlayerAutoClosedByCompletion | |||
|} | |} | ||
These are used for Share-applet. Official user-processes doesn't check the TLV size for any of these. | These are used for Share-applet on [3.0.0+], and with Web on [8.0.0+]. Official user-processes doesn't check the TLV size for any of these. | ||
==== DocumentKind ==== | ==== DocumentKind ==== | ||
Line 929: | Line 1,139: | ||
Controls the initial mode, this can be toggled by the user via the pressing the left-stick button. If the Pointer flag is set to false, only LeftStickMode_Cursor will be used and mode toggle by the user is disabled (input value ignored). | Controls the initial mode, this can be toggled by the user via the pressing the left-stick button. If the Pointer flag is set to false, only LeftStickMode_Cursor will be used and mode toggle by the user is disabled (input value ignored). | ||
==== FooterButtonId ==== | |||
{| class="wikitable" border="1" | |||
|- | |||
! Value | |||
! Name | |||
! Description | |||
|- | |||
| 0 | |||
| None | |||
| None, for empty [[#WebBootFooterButtonEntry]]. Invalid for use as an input Id. | |||
|- | |||
| 1 | |||
| | |||
| | |||
|- | |||
| 2 | |||
| | |||
| | |||
|- | |||
| 3 | |||
| | |||
| | |||
|- | |||
| 4 | |||
| | |||
| | |||
|- | |||
| 5 | |||
| | |||
| | |||
|- | |||
| 6 | |||
| | |||
| | |||
|- | |||
| 7 | |||
| | |||
| Values starting with this are invalid. | |||
|- | |||
|} | |||
==== WebSessionBootMode ==== | |||
This is "nn::web::WebSessionBootMode". | |||
{| class="wikitable" border="1" | |||
|- | |||
! Value | |||
! Name | |||
! Description | |||
|- | |||
| 0 | |||
| | |||
| Normal/default (AllForeground) | |||
|- | |||
| 1 | |||
| | |||
| AllForegroundInitiallyHidden | |||
|} | |||
This controls which [[Applet_Manager_services|LibraryAppletMode]] the applet will be launched with, by the user-process. The TLV for this seems to be ignored by the applet. | |||
==== LastUrl ==== | ==== LastUrl ==== |