Repository navigation
Expand file tree
/
Copy pathindex.html
More file actions
2410 lines (2184 loc) · 91.3 KB
/
Copy pathindex.html
File metadata and controls
2410 lines (2184 loc) · 91.3 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<title>Web Install</title>
<script
src="https://www.w3.org/Tools/respec/respec-w3c"
class="remove"></script>
<script class="remove">
var respecConfig = {
specStatus: "CG-DRAFT",
group: "wicg",
github: "WICG/install-element",
shortName: "web-install",
editors: [
{
name: "Lia Hiscock",
company: "Microsoft",
companyURL: "https://www.microsoft.com/",
url: "https://github.com/LiaHiscock",
},
{
name: "Lu Huang",
company: "Microsoft",
companyURL: "https://www.microsoft.com/",
url: "https://github.com/LuHuangMSFT",
},
{
name: "Rob Paveza",
company: "Microsoft",
companyURL: "https://www.microsoft.com/",
url: "https://github.com/robpaveza",
},
],
xref: {
specs: [
"appmanifest",
"CSP3",
"dom",
"fetch",
"html",
"infra",
"mimesniff",
"permissions",
"permissions-policy",
"secure-contexts",
"url",
"webidl",
],
profile: "web-platform",
},
localBiblio: {
"CAPABILITY-ELEMENTS": {
title: "The HTML Geolocation Element",
href: "https://wicg.github.io/PEPC/geolocation-element.html",
authors: ["Daniel Vogelheim"],
publisher: "WICG",
},
"MANIFEST-INCUBATIONS": {
title: "Manifest Incubations",
href: "https://wicg.github.io/manifest-incubations/",
authors: ["Daniel Murphy"],
publisher: "WICG",
},
"LAUNCH-HANDLER": {
title: "Web App Launch Handler API",
href: "https://wicg.github.io/web-app-launch/",
publisher: "WICG",
},
"LOCAL-NETWORK-ACCESS": {
title: "Local Network Access",
href: "https://wicg.github.io/local-network-access/",
publisher: "WICG",
},
"HTML-AAM": {
title: "HTML Accessibility API Mappings",
href: "https://www.w3.org/TR/html-aam-1.0/",
publisher: "W3C",
},
},
};
</script>
<style>
table {
width: 100%;
}
td,
th {
vertical-align: top;
}
.issue strong:first-child {
display: block;
margin-bottom: 0.25em;
}
</style>
</head>
<body>
<section id="abstract">
<p>
This specification defines Web Install, a user-mediated capability that
lets a website ask the user agent to install a web application. It
defines two entry points: the {{Navigator/install()}} method and the
HTML <code><<a data-link-type="element">install</a>></code>
element. Both entry points resolve a target
<a data-cite="appmanifest#dfn-manifest">application manifest</a>,
validate the target application, obtain
user consent, and invoke the same installation processing model.
</p>
</section>
<section id="sotd">
<p>
This document is an incubation draft. It intentionally records open
interoperability, privacy, and specification-ownership questions
inline. Those issues are part of the draft and do not indicate
implementer consensus.
</p>
</section>
<section class="informative">
<h2>Introduction</h2>
<p>
User agents can install web applications, but websites do not have a
consistent way to offer that action. Existing installation affordances
vary by user agent and platform, and script-driven installation
mechanisms are generally limited to the application associated with
the current document.
</p>
<p>
Web Install provides a common operation with two complementary entry
points:
</p>
<ul>
<li>
{{Navigator/install()}} is an imperative, promise-based API for sites
that provide their own installation user interface.
</li>
<li>
<code><<a data-link-type="element">install</a>></code> is a
declarative, user-agent-rendered control that gives
the user agent a stronger signal of the user's intent.
</li>
</ul>
<p>
Either entry point can target the web application associated with the
current document, or a web application identified by the URL of its
manifest. A user agent always remains responsible for presenting
trustworthy confirmation UI and for deciding how installation maps to
the host platform.
</p>
<section>
<h3>Goals</h3>
<ul>
<li>
Let a site offer installation of its current web application.
</li>
<li>
Let catalogs, search experiences, and application suites offer
installation of a web application identified by its manifest URL.
</li>
<li>
Require a user-mediated decision for every installation attempt.
</li>
<li>
Reuse one application-resolution, validation, consent,
installation, and privacy model across both entry points.
</li>
<li>
Avoid exposing whether an arbitrary web application is already
installed.
</li>
<li>
Allow basic declarative use without script while retaining
progressive fallback content.
</li>
</ul>
</section>
<section>
<h3>Non-goals</h3>
<ul>
<li>
Defining one platform-independent package format or one exact OS
meaning of "installed".
</li>
<li>
Silent, unattended, or policy-driven installation without a user
decision.
</li>
<li>
Installing native applications, browser extensions, or arbitrary
web content without an
<a data-cite="appmanifest#dfn-manifest">application manifest</a>.
</li>
<li>
Exposing a general installed-application enumeration API.
</li>
<li>
Requiring a service worker or offline download as part of
installation.
</li>
</ul>
</section>
</section>
<section id="examples" class="informative">
<h2>Examples</h2>
<p>
A site can offer installation of the web application associated with
its current document:
</p>
<pre class="example js"
title="Install the current web application with JavaScript">
await navigator.install();
</pre>
<pre class="example html" title="Install the current web application with HTML">
<install>
<a href="/install-help">How to install this app</a>
</install>
</pre>
<p>
A catalog can offer installation of an application identified by its
manifest URL:
</p>
<pre class="example js"
title="Install an application by manifest URL with JavaScript">
await navigator.install({
manifest: "https://music.example/manifest.webmanifest",
manifestId: "https://music.example/app"
});
</pre>
<pre class="example html"
title="Install an application by manifest URL with HTML">
<install
manifest="https://music.example/manifest.webmanifest"
manifestid="https://music.example/app">
<a href="https://music.example/">Open Music Example</a>
</install>
</pre>
</section>
<section id="dependencies">
<h2>Dependencies</h2>
<p>
This specification extends [[!HTML]] with {{Navigator/install()}} and
the <code><<a data-link-type="element">install</a>></code>
element. It reuses manifest concepts and processing from
[[!appmanifest]], permission concepts from [[!permissions]], policy
control from [[!permissions-policy]], content restrictions from
[[!CSP3]], and request processing from [[!FETCH]]. Explicit-manifest
retrieval is also subject to [[!LOCAL-NETWORK-ACCESS]].
</p>
<p>
The <code><<a data-link-type="element">install</a>></code>
element provisionally reuses
<a data-cite="!CAPABILITY-ELEMENTS#mixin-blockers">
activation blockers</a> and their rendering protections from
[[!CAPABILITY-ELEMENTS]].
</p>
<p class="issue">
<strong>Capability Elements ownership is unsettled.</strong>
The reusable activation-blocker algorithms currently live inside the
Geolocation Element draft, while Chromium's
<code><<a data-link-type="element">install</a>></code>
implementation
uses an older <code>InPagePermissionMixin</code> that also exposes
permission-state and prompt event members that
<code><<a data-link-type="element">install</a>></code> does not
use. This draft references only the narrower
<code>ActivationBlockersMixin</code>. Before advancement, that mixin
should have a maintained, independently referenceable specification
home, or the required behavior must be defined here.
</p>
<p>
[[MANIFEST-INCUBATIONS]] is an informative dependency at present. If
this specification later reuses an incubating manifest member or
algorithm, that dependency must be made normative at the exact point of
use.
</p>
</section>
<section id="terminology">
<h2>Terminology</h2>
<p>
A user agent that does not support web application installation on a
particular platform or profile is not required to expose these entry
points. Platform support is implementation status, not a
desktop-specific conformance requirement. If an entry point is exposed,
its observable behavior MUST conform to this specification.
</p>
<p>
An <dfn data-export="">initiating document</dfn> is the {{Document}}
whose {{Navigator}} or
<code><<a data-link-type="element">install</a>></code> element
initiated a Web Install request.
</p>
<p>
An <dfn data-export="">entry-point kind</dfn> is either
<dfn data-dfn-for="entry-point kind" data-export="">imperative</dfn>,
for a request initiated by {{Navigator/install()}}, or
<dfn data-dfn-for="entry-point kind" data-export="">declarative</dfn>,
for a request initiated by the
<code><<a data-link-type="element">install</a>></code> element's
[=EventTarget/activation behavior=].
</p>
<p>
A <dfn data-export="">application source</dfn> is either
<dfn data-export="">current document</dfn> or
<dfn data-export="">explicit manifest</dfn>.
</p>
<p>
A <dfn data-export="">manifest ID assertion</dfn> is an optional URL
supplied by the caller representing the expected processed
<a data-cite="appmanifest#dfn-id">manifest id</a>.
</p>
</section>
<section id="model">
<h2>Web Install model</h2>
<p>
A <dfn data-export="">web install request</dfn> is a struct with the
following [=struct/items=]:
</p>
<dl>
<dt><dfn data-dfn-for="web install request">document</dfn></dt>
<dd>The [=initiating document=].</dd>
<dt><dfn data-dfn-for="web install request">entry point</dfn></dt>
<dd>The request's [=entry-point kind=].</dd>
<dt><dfn data-dfn-for="web install request">application source</dfn></dt>
<dd>The request's [=application source=].</dd>
<dt><dfn data-dfn-for="web install request">manifest URL</dfn></dt>
<dd>
The manifest URL for an [=explicit manifest=] request; otherwise null.
</dd>
<dt><dfn data-dfn-for="web install request">manifest ID</dfn></dt>
<dd>The request's optional [=manifest ID assertion=].</dd>
</dl>
<p>
A <dfn data-export="">web install candidate</dfn> is a struct with the
following [=struct/items=]:
</p>
<dl>
<dt><dfn data-dfn-for="web install candidate">manifest</dfn></dt>
<dd>
A
<a data-cite="appmanifest#dfn-processed-manifest">
processed manifest</a>.
</dd>
<dt><dfn data-dfn-for="web install candidate">manifest URL</dfn></dt>
<dd>The URL from which the manifest was obtained.</dd>
<dt><dfn data-dfn-for="web install candidate">identity</dfn></dt>
<dd>
The processed <a data-cite="appmanifest#dfn-id">manifest id</a>.
</dd>
<dt><dfn data-dfn-for="web install candidate">start URL</dfn></dt>
<dd>
The processed
<a data-cite="appmanifest#dfn-start_url">start URL</a>.
</dd>
</dl>
<p>
A <dfn data-export="">web install outcome</dfn> is one of:
</p>
<dl>
<dt><dfn data-export="">installation succeeded</dfn></dt>
<dd>
The user agent completed installation, or completed processing a
user-approved action for an already-installed application.
</dd>
<dt><dfn data-export="">invalid install data</dfn></dt>
<dd>
The supplied URL, manifest, identity assertion, or required
installation metadata was invalid or unavailable.
</dd>
<dt><dfn data-export="">installation aborted</dfn></dt>
<dd>
The request did not complete for a reason other than
[=invalid install data=], including user dismissal, permission or
policy denial, an invalid initiating document, an unsupported
environment, a concurrent operation, navigation, destruction, or
internal failure.
</dd>
</dl>
<p>
The outcome vocabulary is shared by both entry points. Each entry point
maps an outcome to its corresponding public result.
</p>
<p>
Every [=top-level traversable=] has an
<dfn data-dfn-for="top-level traversable">
active web install request</dfn>, which is null or a
[=web install request=] and is initially null.
</p>
<p class="issue">
<strong>The public outcome taxonomy remains unresolved.</strong>
Current proposal text and Chromium expose success, invalid data, and a
broad aborted result. Developer feedback asks for user cancellation to
be distinguishable from internal failure, while privacy review prefers
exposing less cross-origin information. The algorithms below
provisionally retain the coarse current behavior and mark the
entry-point mappings explicitly.
</p>
</section>
<section id="shared-algorithm">
<h2>Shared Web Install processing</h2>
<aside class="note" title="How a request is processed">
<p>
Both {{Navigator/install()}} and
<code><<a data-link-type="element">install</a>></code> create a
[=web install request=] and use the same processing flow. The sections
following this one define each stage in the same order:
</p>
<ol>
<li>
Check that the calling page may initiate installation and that no
other install request is active in its tab or window.
</li>
<li>
Identify and validate the application to install. A
current-document request uses its processed manifest; an
explicit-manifest request fetches and processes the supplied
manifest URL.
</li>
<li>Obtain installation permission when the request requires it.</li>
<li>
Present user-controlled confirmation UI and, if accepted, install
the application or perform an approved action for an
already-installed application.
</li>
<li>
Finish the request. The initiating entry point then maps the
internal outcome to its public result.
</li>
</ol>
<p>
For a new application, installation is the last required operation.
The user agent may launch it afterward, but launching is not part of
the required shared flow.
</p>
</aside>
<p>
To <dfn>finish a web install request</dfn> given a
[=web install request=] <var>request</var> and
[=web install outcome=] <var>outcome</var>, run the following steps:
</p>
<ol class="algorithm">
<li>
Let <var>traversable</var> be <var>request</var>'s
[=web install request/document=]'s [=top-level traversable=], if it
has one; otherwise null.
</li>
<li>
If <var>traversable</var> is not null and its
[=top-level traversable/active web install request=] is
<var>request</var>, set it to null.
</li>
<li>Return <var>outcome</var>.</li>
</ol>
<p>
To <dfn>run a web install request</dfn> given a
[=web install request=] <var>request</var>, run the following steps:
</p>
<ol class="algorithm">
<li>
Let <var>document</var> be <var>request</var>'s
[=web install request/document=].
</li>
<li>
If <var>document</var> is not an [=eligible initiating document=],
return the result of [=finish a web install request=] with
<var>request</var> and [=installation aborted=].
</li>
<li>
Let <var>traversable</var> be <var>document</var>'s
[=top-level traversable=].
</li>
<li>
If <var>traversable</var>'s
[=top-level traversable/active web install request=] is not null,
return
the result of [=finish a web install request=] with
<var>request</var> and [=installation aborted=].
</li>
<li>
Set <var>traversable</var>'s
[=top-level traversable/active web install request=] to
<var>request</var>.
</li>
<li>
If <var>request</var>'s [=web install request/application source=] is
[=current document=], let <var>candidateResult</var> be the result of
[=resolve a web install candidate from the current document=] for
<var>request</var>. Otherwise, let <var>candidateResult</var> be the
result of [=resolve a web install candidate from an explicit
manifest=] for <var>request</var>.
</li>
<li>
If <var>candidateResult</var> is a [=web install outcome=], return the
result of [=finish a web install request=] with
<var>request</var> and <var>candidateResult</var>.
</li>
<li>Let <var>candidate</var> be <var>candidateResult</var>.</li>
<li>
If <var>document</var> is no longer an
[=eligible initiating document=]:
<ol>
<li>
If <var>traversable</var>'s
[=top-level traversable/active web install request=] is
<var>request</var>, set it to null.
</li>
<li>
Return the result of [=finish a web install request=] with
<var>request</var> and [=installation aborted=].
</li>
</ol>
</li>
<li>
Let <var>permissionGranted</var> be the result of
[=obtain web install permission=] for <var>request</var>.
</li>
<li>
If <var>permissionGranted</var> is false, return the result of
[=finish a web install request=] with <var>request</var> and
[=installation aborted=].
</li>
<li>
Let <var>outcome</var> be the result of
[=perform a Web Install action=] with <var>request</var> and
<var>candidate</var>.
</li>
<li>
Return the result of [=finish a web install request=] with
<var>request</var> and <var>outcome</var>.
</li>
</ol>
<p>
For explicit-manifest requests, manifest retrieval and validation
precede installation-permission and unsupported-profile handling. This
ensures that invalid manifest data produces the same
[=invalid install data=] outcome regardless of permission or profile
state. Consequently, the target origin may observe a manifest request
before installation permission is granted; the request omits
credentials and referrer information.
</p>
<p class="issue">
<strong>Concurrency scope is provisional.</strong>
Chromium has document-service and WebContents-level guards, while the
capability-element implementation also caps registered install
elements. This draft defines one active operation per top-level
traversable because that is the visible dialog scope. Per-profile,
per-origin, cooldown, and quota controls remain user-agent anti-abuse
policy.
</p>
<p>
If the [=initiating document=] navigates, is destroyed, ceases to be
fully active, or ceases to be the active document of its top-level
traversable before processing completes, the user agent MUST cancel
associated user interface and complete the request with
[=installation aborted=].
</p>
<p class="issue">
<strong>Navigation and BFCache lifetime need exact HTML integration.</strong>
Chromium cancels on every cross-document navigation, including
same-origin navigation and BFCache transitions. This draft preserves
the active-document invariant but does not yet define whether a BFCache
restoration can resume an operation.
</p>
</section>
<section id="preconditions">
<h2>Common request preconditions</h2>
<p>
To determine whether a {{Document}} <var>document</var> is an
<dfn>eligible initiating document</dfn>, run the following steps:
</p>
<ol class="algorithm">
<li>
If <var>document</var> is not [=Document/fully active=], return false.
</li>
<li>
If <var>document</var> is not the
<a data-cite="html/document-sequences.html#active-document">
active document</a> of a
[=top-level traversable=], return false.
</li>
<li>
If the [=navigable/traversable navigable=] of
<var>document</var>'s [=node navigable=] is a
<a data-cite=
"!FENCED-FRAME#fenced-navigable-container-fenced-navigable">
fenced navigable</a>, return false.
</li>
<li>
If <var>document</var>'s
<a data-cite="html/browsers.html#active-sandboxing-flag-set">
active sandboxing flag set</a> is not empty, return false.
</li>
<li>
If the <code>web-app-installation</code> [=policy-controlled feature=]
is disabled in <var>document</var>, return false.
</li>
<li>Return true.</li>
</ol>
<p class="issue">
<strong>Frame and sandbox scope needs multi-implementer review.</strong>
Chromium currently requires the primary top-level document and rejects
every sandboxed context. Proposal text leaves same-origin frames and a
future sandbox opt-in open. This draft preserves Chromium's restrictive
behavior until a safe delegation model is designed.
</p>
<p class="issue">
<strong>Secure-context exposure is inconsistent.</strong>
Chromium's IDL lacks <code>[SecureContext]</code>, but browser bindings
and manifest URL checks effectively restrict use to trustworthy HTTP(S)
contexts. This draft checks trustworthy contexts in processing rather
than changing interface exposure. The final API should decide whether
secure-context gating belongs in WebIDL.
</p>
</section>
<section id="candidate-resolution">
<h2>Resolving a web install candidate</h2>
<section id="current-document-candidate">
<h3>Resolving from the current document</h3>
<p>
To <dfn>resolve a web install candidate from the current
document</dfn> for a [=web install request=] <var>request</var>, run
the following steps:
</p>
<ol class="algorithm">
<li>
Let <var>document</var> be <var>request</var>'s
[=web install request/document=].
</li>
<li>
Let <var>manifest</var> be <var>document</var>'s
<a data-cite="appmanifest#dfn-processed-manifest">
processed manifest</a>.
</li>
<li>
If <var>manifest</var> is null, return
[=invalid install data=].
</li>
<li>
Let <var>manifestURL</var> be <var>manifest</var>'s
<a data-cite="appmanifest#dfn-manifest-url">manifest URL</a>.
</li>
<li>
Let <var>identity</var> be <var>manifest</var>'s
<a data-cite="appmanifest#dfn-id">manifest id</a>.
</li>
<li>
If the manifest did not explicitly contain an
<code>id</code> member, return [=invalid install data=].
</li>
<li>
If <var>identity</var> is not [=same origin=] with
<var>document</var>'s [=Document/URL=], return
[=invalid install data=].
</li>
<li>
Let <var>candidate</var> be a new [=web install candidate=] whose
[=web install candidate/manifest=] is <var>manifest</var>,
[=web install candidate/manifest URL=] is <var>manifestURL</var>,
[=web install candidate/identity=] is <var>identity</var>, and
[=web install candidate/start URL=] is <var>manifest</var>'s
<a data-cite="appmanifest#dfn-start_url">start URL</a>.
</li>
<li>
Return the result of [=validate a web install candidate=] with
<var>request</var> and <var>candidate</var>.
</li>
</ol>
<p class="issue">
<strong>Manifest readiness is underspecified.</strong>
The no-argument API can be activated before the document's linked
manifest finishes loading. Chromium reads the current document's
processed manifest without waiting for a service worker. The final
algorithm must define whether it waits for an in-flight manifest,
fails immediately, or reuses the installation-prompt discovery
processing currently incubated in [[MANIFEST-INCUBATIONS]].
</p>
</section>
<section id="explicit-manifest-candidate">
<h3>Resolving from an explicit manifest</h3>
<p>
To <dfn>resolve a web install candidate from an explicit
manifest</dfn> for a [=web install request=] <var>request</var>, run
the following steps:
</p>
<ol class="algorithm">
<li>
Let <var>manifestURL</var> be <var>request</var>'s
[=web install request/manifest URL=].
</li>
<li>
If <var>manifestURL</var> is not an HTTP(S) URL whose
[=url/origin=] is
<a data-cite="secure-contexts#is-origin-trustworthy">
potentially trustworthy</a>, return
[=invalid install data=].
</li>
<li>
Let <var>bodyBytes</var> be the result of
[=fetch an install manifest=] from <var>manifestURL</var>.
</li>
<li>
If <var>bodyBytes</var> is failure, return
[=invalid install data=].
</li>
<li>
Let <var>manifest</var> be the result of
[=process install manifest bytes=] with <var>bodyBytes</var> and
<var>manifestURL</var>.
</li>
<li>
If <var>manifest</var> is failure, return
[=invalid install data=].
</li>
<li>
Let <var>identity</var> be <var>manifest</var>'s
<a data-cite="appmanifest#dfn-id">manifest id</a>.
</li>
<li>
If <var>request</var>'s [=web install request/manifest ID=] is not
null, and it is not equal to <var>identity</var>, return
[=invalid install data=].
</li>
<li>
If <var>request</var>'s [=web install request/manifest ID=] is null,
and the fetched manifest did not explicitly contain an
<code>id</code> member, return [=invalid install data=].
</li>
<li>
Let <var>candidate</var> be a new [=web install candidate=] whose
[=web install candidate/manifest=] is <var>manifest</var>,
[=web install candidate/manifest URL=] is <var>manifestURL</var>,
[=web install candidate/identity=] is <var>identity</var>, and
[=web install candidate/start URL=] is <var>manifest</var>'s
<a data-cite="appmanifest#dfn-start_url">start URL</a>.
</li>
<li>
Return the result of [=validate a web install candidate=] with
<var>request</var> and <var>candidate</var>.
</li>
</ol>
</section>
</section>
<section id="manifest-fetch">
<h2>Fetching and processing a manifest</h2>
<section>
<h3>Fetching an install manifest</h3>
<p>
To <dfn>fetch an install manifest</dfn> from a URL
<var>manifestURL</var>, run the following steps:
</p>
<ol class="algorithm">
<li>
Let <var>response</var> be the result of the user agent internally
retrieving <var>manifestURL</var> using <code>GET</code>.
</li>
<li>
The retrieval MUST omit credentials and referrer information.
</li>
<li>
The retrieval MUST NOT require a
<a data-cite="fetch#cors-check">CORS check</a> to succeed.
</li>
<li>
The retrieval MUST comply with the
<a data-cite="CSP3#directive-manifest-src">
<code>manifest-src</code> directive</a> of the Content Security
Policy applicable to the [=initiating document=].
</li>
<li>
The retrieval MUST NOT be intercepted by a service worker.
</li>
<li>
The retrieval MUST be subject to
<a data-cite=
"!LOCAL-NETWORK-ACCESS#local-network-access-check">
Local Network Access checks</a> as if it were initiated by the
[=initiating document=].
</li>
<li>
If the retrieval uses cached data, it MUST use the
[=network partition key=] associated with the
[=initiating document=]'s [=relevant settings object=].
</li>
<li>
The information observable by the [=initiating document=] as a
result of this retrieval is limited as described in
<a href="#privacy">Privacy considerations</a>.
</li>
<li>
If the retrieval encounters a redirect, return failure.
</li>
<li>
If <var>response</var> is a [=network error=], return failure.
</li>
<li>
If <var>response</var>'s [=response/status=] is not an
[=ok status=], return failure.
</li>
<li>
If <var>response</var>'s <code>Content-Type</code> metadata is not a
<a data-cite="mimesniff#json-mime-type">JSON MIME type</a>, return
failure.
</li>
<li>
Let <var>bodyBytes</var> be the result of
<a data-cite="fetch#body-fully-read">fully reading</a>
<var>response</var>'s [=response/body=].
</li>
<li>If fully reading the body failed, return failure.</li>
<li>
The user agent MUST NOT expose <var>response</var> or
<var>bodyBytes</var> to the [=initiating document=].
</li>
<li>Return <var>bodyBytes</var>.</li>
</ol>
<p class="issue">
<strong>Exact Fetch integration remains unresolved.</strong>
The steps above describe the intended network and exposure behavior
directly. Chromium implements them using an internal browser-process
request. This draft does not yet define the request destination,
or response tainting model. These details require coordination with
Fetch before advancement.
</p>
<p>
A user agent MAY impose implementation-defined response-size,
retry, cache, and resource limits. Such limits MUST NOT expose
installed state or private-browsing state.
</p>
<p>
If the user agent fetches icons or other target resources before the
user accepts installation, those requests MUST omit credentials and
caller-specific authentication state. Their referrer, cache behavior,
and cross-origin requirements need the same integration review as the
manifest retrieval.
</p>
</section>
<section>
<h3>Processing an install manifest</h3>
<p>
To <dfn>process install manifest bytes</dfn> given a byte sequence
<var>bodyBytes</var> and URL <var>manifestURL</var>, run the following
steps:
</p>
<ol class="algorithm">
<li>
Let <var>manifest</var> be the result of running
<a data-cite="appmanifest#dfn-processing-a-manifest">
process a manifest</a> with
<var>bodyBytes</var>, <var>manifestURL</var> as both the
<var>manifest URL</var> and <var>document URL</var>, and null as
the <var>client</var>.
</li>
<li>
If processing the manifest failed, return failure.
</li>
<li>Return <var>manifest</var>.</li>
</ol>
<p class="issue">
<strong>This is an explicit Web App Manifest integration.</strong>
Chromium passes the manifest URL as both the document URL and manifest
URL so relative members resolve against the manifest. Web App
Manifest permits processing without a client but recommends evidence
that a document was historically associated with the manifest. Direct
installation deliberately has no loaded target document. WebApps WG
should decide whether this call is a supported parameterization or a
monkeypatch requiring a new processing entry point.
</p>
<p class="issue">
<strong>Source-member presence must survive processing.</strong>
Both application sources need to distinguish an explicitly declared
<code>id</code> or <code>start_url</code> from Web App Manifest's
computed defaults. The current processed-manifest model does not
clearly export those presence bits. This specification needs either
an enriched processing result or an explicit pre-processing step that
records them.
</p>
</section>
<section>
<h3>Validating a web install candidate</h3>
<p>
To <dfn>validate a web install candidate</dfn> given a
[=web install request=] <var>request</var> and
[=web install candidate=] <var>candidate</var>, run the following
steps:
</p>
<ol class="algorithm">
<li>
Let <var>manifest</var> be <var>candidate</var>'s
[=web install candidate/manifest=].
</li>
<li>
If the source manifest did not explicitly contain a valid
<code>start_url</code> member, return [=invalid install data=].
</li>
<li>
If neither <a data-cite="appmanifest#dfn-name">name</a> nor
<a data-cite="appmanifest#dfn-short_name">short name</a> is a
non-empty string, return [=invalid install data=].
</li>
<li>
If <var>manifest</var>'s
<a data-cite="appmanifest#dfn-icons">icons</a> list does not contain
at least one valid image resource whose
<a data-cite="appmanifest#dfn-purpose">purpose</a> contains
<code>any</code>, return [=invalid install data=].
</li>
<li>
If <var>request</var>'s [=web install request/application source=]
is [=explicit manifest=], and <var>candidate</var>'s
[=web install candidate/start URL=] is not [=same origin=] with
<var>candidate</var>'s [=web install candidate/manifest URL=],
return [=invalid install data=].