공유 저장소 API

커뮤니티 그룹 보고서 초안,

이 버전:
https://github.com/WICG/shared-storage
이슈 추적:
GitHub
명세 내 인라인
편집자:
(Google)

개요

공유 저장소는 의도적으로 최상위 순회 가능 사이트별로 분할되지 않는 저장소 API이다(물론 여전히 컨텍스트 출처별로는 분할된다!). 사용자의 사이트 간 재식별을 제한하기 위해, 공유 저장소의 데이터는 신중하게 구성된 출력 게이트가 있는 제한된 환경에서만 읽을 수 있다.

이 문서의 상태

이 명세는 Web Platform Incubator Community Group에서 공개했다. 이는 W3C 표준이 아니며 W3C 표준화 트랙에 있지도 않다. W3C Community Contributor License Agreement (CLA)에 따라 제한적인 거부권 및 기타 조건이 적용된다는 점에 유의하라. W3C 커뮤니티 및 비즈니스 그룹에 대해 자세히 알아보라.

1. 소개

이 절은 규범적이지 않다.

사이트 간 사용자 추적을 방지하기 위해, 브라우저는 모든 형태의 저장소를 top-level traversable 사이트별로 분할하고 있다. Client-Side Storage Partitioning을 보라. 그러나 현재 분할되지 않은 저장소에 의존하는 정당한 사용 사례가 많이 있다.

이 문서는 분할되지 않은 저장소가 필요한 여러 사용 사례를 지원하기 위해, 의도적으로 top-level traversable 사이트별로 분할되지 않는 새로운 저장소 API를 소개한다(다만 여전히 context origin별로는 분할된다). 사용자의 사이트 간 재식별을 제한하기 위해, Shared Storage의 데이터는 두 개의 제한된 환경에서만 읽을 수 있다. 그중 하나는 worklet이라고 하며, worklet의 모든 출력은 fenced frame 또는 Private Aggregation 보고서 형태이다. 시간이 지나면서 표준에 추가적인 worklet 출력 게이트가 포함될 수 있다. 다른 제한된 환경은 fenced frame의 콘텐츠 내부이며, 이 환경은 disableUntrustedNetwork() 호출이 resolve된 뒤에 해당된다. 이는 읽은 데이터가 프레임 밖으로 공유되는 것을 방지한다.

a.example은 사이트 간에 일관된 방식으로 사용자를 그룹에 무작위로 할당한다.

a.example iframe 내부:

function generateSeed() {}
await window.sharedStorage.worklet.addModule('experiment.js');

// a.example의 저장소에 사이트 간 seed가 아직 없을 때만 쓴다.
window.sharedStorage.set('seed', generateSeed(), { ignoreIfPresent: true });

let fencedFrameConfig = await window.sharedStorage.selectURL(
  'select-url-for-experiment',
  [
    {url: "blob:https://a.example/123…", reportingMetadata: {"click": "https://report.example/1..."}},
    {url: "blob:https://b.example/abc…", reportingMetadata: {"click": "https://report.example/a..."}},
    {url: "blob:https://c.example/789…"}
  ],
  { data: { name: 'experimentA' } }
);

// fenced frame 'my-fenced-frame'가 이미 연결되어 있다고 가정한다.
document.getElementById('my-fenced-frame').config = fencedFrameConfig;

experiment.js worklet 스크립트 내부:

class SelectURLOperation {
  hash(experimentName, seed) {}

  async run(urls, data) {
    const seed = await this.sharedStorage.get('seed');
    return hash(data.name, seed) % urls.length;
  }
}
register('select-url-for-experiment', SelectURLOperation);

2. SharedStorageWorklet 인터페이스

SharedStorageWorklet 객체는 개발자가 module script를 제공하여 Shared Storage 데이터를 처리한 뒤, 하나 이상의 출력 게이트를 통해 결과를 출력할 수 있게 한다. 현재 두 개의 출력 게이트가 있으며, Private Aggregation 출력 게이트와 URL-selection 출력 게이트이다.
typedef (USVString or FencedFrameConfig) SharedStorageResponse;
[Exposed=(Window)]
interface SharedStorageWorklet : Worklet {
  Promise<SharedStorageResponse> selectURL(DOMString name,
                               sequence<SharedStorageUrlWithMetadata> urls,
                               optional SharedStorageRunOperationMethodOptions options = {});
  Promise<any> run(DOMString name,
                   optional SharedStorageRunOperationMethodOptions options = {});
};

SharedStorageWorklet은 연결된 boolean addModule initiated를 가지며, false로 초기화된다.

SharedStorageWorklet은 연결된 USVString data origin을 가지며, "context-origin"으로 초기화된다.

SharedStorageWorklet은 연결된 boolean has cross-origin data origin을 가지며, false로 초기화된다.

동일한 SharedStorageWorklet에 대해 addModule()를 통해 여러 module script를 추가하면, 호출자가 Shared Storage의 데이터를 module script에 정의된 전역 변수에 저장한 뒤, 나중의 addModule() 호출을 통해 그 데이터를 유출할 수 있게 되므로, 각 SharedStorageWorkletaddModule()를 한 번만 호출할 수 있다. addModule initiated boolean은 이 제한을 강제할 수 있게 한다.

worklet에 대해 addModule()가 호출되면, addModule이 허용되는지 확인하고 상태 갱신을 실행하며, 그 결과가 "DisallowedDueToNonPreferenceError"이거나, 그 결과가 "DisallowedDueToPreferenceError"이고 worklet의 has cross-origin data origin이 false이면, § 2.2.6 addModule()에 대한 Monkey Patch에 자세히 설명된 대로 addModule()가 실패하게 한다.

사용자 환경설정이 공유 저장소에 대한 접근을 허용하는지 확인하려면, environment settings object environmentorigin origin이 주어졌을 때, 다음 단계를 실행한다:
  1. 필요에 따라 environmentorigin에서 사용할 수 있는 값을 사용하여, true 또는 false를 반환하는 implementation-defined 알고리즘을 수행한다.

context에 의해 공유 저장소가 허용되는지 결정하려면, environment settings object environment, origin origin, 그리고 boolean allowedInOpaqueOriginContext가 주어졌을 때, 다음 단계를 실행한다:
  1. environmentsecure context가 아니면 false를 반환한다.

  2. allowedInOpaqueOriginContext가 false이고 environmentoriginopaque origin이면 false를 반환한다.

  3. originopaque origin이면 false를 반환한다.

  4. globalObjectcurrent realmglobal object로 둔다.

  5. Assert: globalObjectWindow 또는 SharedStorageWorkletGlobalScope이다.

  6. globalObjectWindow이고, "shared-storage", globalObjectassociated document, 그리고 origin에 대해 Is feature enabled in document for origin?을 실행한 결과가 false를 반환하면 false를 반환한다.

  7. origin으로 obtain a site를 실행한 결과가 enrolled가 아니면 false를 반환한다.

  8. true를 반환한다.

다음은 알고리즘 context에 의해 공유 저장소가 허용되는지 결정사용자 환경설정이 공유 저장소에 대한 접근을 허용하는지 확인이 사용되는 시나리오이다:
addModule이 허용되는지 확인하고 상태 갱신하려면, SharedStorageWorklet workletURL moduleURLRecord가 주어졌을 때, 다음 단계를 실행한다:
  1. workletaddModule initiated가 true이면, "DisallowedDueToNonPreferenceError"를 반환한다.

  2. workletaddModule initiated를 true로 설정한다.

  3. workletDataOrigincurrent settings objectorigin으로 둔다.

  4. workletdata origin"script-origin"이면, workletDataOriginmoduleURLRecordorigin으로 설정한다.

  5. 그렇지 않고, workletdata origin"context-origin"이 아니면:

    1. customOriginUrlworkletdata origin에 대해 URL parser를 실행한 결과로 둔다.

    2. customOriginUrl이 유효한 URL이 아니면, "DisallowedDueToNonPreferenceError"를 반환한다.

    3. workletDataOrigincustomOriginUrlorigin으로 설정한다.

  6. hasCrossOriginDataOrigin을 false로 둔다.

  7. workletDataOrigincurrent settings objectoriginsame origin이 아니면, hasCrossOriginDataOrigin을 true로 설정한다.

  8. allowedInOpaqueOriginContexthasCrossOriginDataOrigin으로 둔다.

  9. context에 의해 공유 저장소가 허용되는지 결정current settings object, workletDataOrigin, 그리고 allowedInOpaqueOriginContext와 함께 실행한 결과가 false이면, "DisallowedDueToNonPreferenceError"를 반환한다.

  10. worklethas cross-origin data originhasCrossOriginDataOrigin으로 설정한다.

  11. 사용자 환경설정이 공유 저장소에 대한 접근을 허용하는지 확인current settings objectworkletDataOrigin과 함께 실행한 결과가 false이면, "DisallowedDueToPreferenceError"를 반환한다.

  12. "Allowed"를 반환한다.

또한 각 SharedStorageWorkletglobal scopes 목록은 처음에는 비어 있으며, 해당 worklet global scope type의 인스턴스인 SharedStorageWorkletGlobalScope를 최대 하나만 포함할 수 있다.

2.1. SharedStorageWorklet에서 작업 메서드 실행하기

select-url 결과 인덱스 가져오기를 하려면, SharedStorageWorklet worklet, DOMString operationName, list of strings urlList, origin workletDataOrigin, navigable navigable, SharedStorageRunOperationMethodOptions options, pre-specified report parameters 또는 null인 preSpecifiedParamsaggregation coordinator 또는 null인 aggregationCoordinator가 주어졌을 때, 다음 단계를 실행한다. 이 알고리즘은 urlList에서 선택된 URL의 인덱스를 값으로 하는 unsigned long으로 resolve되는 promise와, top-level traversable의 예산charged되어야 하는지 나타내는 boolean으로 구성된 tuple을 반환한다.
  1. promise를 새 promise로 둔다.

  2. windowworkletrelevant settings object로 둔다.

  3. Assert: windowWindow이다.

  4. windowbrowsing context가 null이면, (TypeErrorrejected된 promise, true)의 tuple을 반환한다.

  5. windowassociated documentfully active가 아니면, (TypeErrorrejected된 promise, true)의 tuple을 반환한다.

  6. Assert: workletglobal scopessize는 1이다.

  7. globalScopeworkletglobal scopes[0]으로 둔다.

  8. moduleMapKeyTuplesglobalScoperelevant settings objectmodule map에 대해 get the keys를 실행한 결과로 둔다.

  9. Assert: moduleMapKeyTuplessize는 1이다.

  10. moduleURLRecordmoduleMapKeyTuples[0][0]으로 둔다.

  11. savedQueryNameoptions["savedQuery"]로 둔다.

  12. savedQueryName이 빈 문자열이 아닌 string이면:

    1. callbackTaskwindow, urlListpromise가 주어졌을 때 저장된 인덱스 결과를 처리할 callback 얻기를 실행한 결과로 둔다.

    2. savedIndexnavigable, workletDataOrigin, moduleURLRecord, operationName, savedQueryNamecallbackTask에 대해 저장된 질의에 대한 인덱스 가져오기를 실행한 결과로 둔다.

    3. savedIndex가 "pending callback"이면, tuple (promise, false)를 반환한다.

      Note: 이제 callbackTask는 이전에 얻은 worklet agent가 이 질의에 대한 인덱스를 선택하는 작업을 완료할 때 실행되도록 저장된다. callbackTask의 단계가 실행되면, promise가 resolve된다.

    4. savedIndexunsigned long이면:

      1. window가 주어졌을 때, DOM manipulation task sourceglobal task를 queue하여, savedIndex가 주어졌을 때 callbackTask의 단계를 실행한다.

        Note: callbackTask의 단계를 실행하면 promise가 resolve된다.

      2. tuple (promise, false)를 반환한다.

    5. Assert: savedIndex는 "pending current operation"이다.

  13. globalScopeworklet event looptask를 queue하여 다음 단계를 수행한다:

    1. operationMapglobalScopeoperation map으로 둔다.

    2. operationMapoperationNamecontain하지 않으면, window가 주어졌을 때 DOM manipulation task sourceglobal task를 queue하여, promiseTypeErrorreject하고, 이 단계를 중단한다.

      Note: 이는 register()operationName으로 호출된 적이 없는 경우 발생할 수 있다.

    3. Assert: operationMap[operationName]의 associated realmthisrelevant realm이다.

    4. operationoperationMap[operationName]을 RunFunctionForSharedStorageSelectURLOperationconverted한 값으로 둔다.

    5. privateAggregationCompletionTaskworkletDataOrigin, preSpecifiedParamsaggregationCoordinator가 주어졌을 때 Private Aggregation scope 설정의 결과로 둔다.

    6. argumentsList를 « urlList »인 list로 둔다.

    7. options["data"]가 exists하면, 이를 argumentsListappend한다.

    8. indexPromiseargumentsList와 함께 operationinvoking한 결과로 둔다.

    9. indexPromisereact한다:

      index로 fulfilled된 경우:
      1. indexurlListsize보다 크면:

        1. savedQueryName이 빈 문자열이 아닌 string이면, window, navigable, workletDataOrigin, moduleURLRecord, operationName, savedQueryName, 그리고 기본 selectURL index와 함께 저장된 질의에 대한 인덱스 저장을 실행한다.

        2. window가 주어졌을 때 DOM manipulation task sourceglobal task를 queue하여, promiseTypeErrorreject하고, 이 단계를 중단한다.

        Note: 결과 index가 입력 urls의 size를 벗어난다. 이는 selectURL() 프로토콜을 위반하며, 어느 url을 선택해야 하는지 알 수 없다.

        그렇지 않으면:

        1. savedQueryName이 빈 문자열이 아닌 string이면, window, navigable, workletDataOrigin, moduleURLRecord, operationName, savedQueryName, 그리고 index와 함께 저장된 질의에 대한 인덱스 저장을 실행한다.

        2. window가 주어졌을 때 DOM manipulation task sourceglobal task를 queue하여, promiseindexresolve한다.

        3. privateAggregationCompletionTask를 실행한다.

      rejected된 경우:
      1. savedQueryName이 빈 문자열이 아닌 string이면, window, navigable, workletDataOrigin, moduleURLRecord, operationName, savedQueryName, 그리고 기본 selectURL index와 함께 저장된 질의에 대한 인덱스 저장을 실행한다.

      2. window가 주어졌을 때 DOM manipulation task sourceglobal task를 queue하여, promiseTypeErrorreject한다.

        Note: 이는 operationCtor의 run() 메서드에서 오류가 발생했거나 (여기서 operationCtorregister()의 매개변수임), 결과 index가 정수가 아닌 값이어서 selectURL() 프로토콜을 위반하며, 어느 url을 선택해야 하는지 알 수 없음을 나타낸다.

      3. privateAggregationCompletionTask를 실행한다.

  14. tuple (promise, true)를 반환한다.

인덱스 선택 결과 처리를 하려면, SharedStorageWorklet worklet, environment settings object environment, Document document, sequence of SharedStorageUrlWithMetadata urls, list of strings urlList, navigable navigable, SharedStorageRunOperationMethodOptions options, fenced frame config mapping fencedFrameConfigMapping, urn uuid urn, boolean shouldChargeTopLevelBudgets, boolean shouldUseDefaultIndex, 그리고 unsigned long resultIndex가 주어졌을 때, 다음 단계를 수행한다:
  1. sitedocumentorigin으로 obtain a site를 실행한 결과로 둔다.

  2. remainingBudgetenvironmentsite와 함께 남은 navigation budget 결정을 실행한 결과로 둔다.

  3. pendingBitsurlListsize의 밑이 2인 로그로 둔다.

  4. shouldChargeTopLevelBudgets가 true이면:

    1. pageBudgetResultnavigable, site, 및 pendingBits와 함께 shared storage top-level traversable budgets 부과를 실행한 결과로 둔다.

    2. pageBudgetResult가 false이면 shouldUseDefaultIndex를 true로 설정한다.

  5. pendingBitsremainingBudget보다 크면, shouldUseDefaultIndex를 true로 설정한다.

  6. shouldUseDefaultIndex가 true이면, resultIndex기본 selectURL index로 설정한다.

  7. finalConfig를 새 fenced frame config로 둔다.

  8. finalConfigmapped urlurlList[resultIndex]로 설정한다.

  9. finalConfig"pending shared storage budget debit" fieldpendingBits로 설정한다.

  10. urnfinalConfig와 함께 fencedFrameConfigMapping에서 pending config finalize를 수행한다.

  11. resultURLWithMetadataurls[resultIndex]로 둔다.

  12. resultURLWithMetadata에 "reportingMetadata" 필드가 있으면, resultURLWithMetadata["reportingMetadata"]와 함께 reporting metadata 등록을 실행한다.

  13. options["keepAlive"]가 false이면, worklet와 함께 worklet global scope 종료를 실행한다.

selectURL(name, urls, options) 메서드 단계는 다음과 같다:
  1. resultPromise를 새 promise로 둔다.

  2. thisaddModule initiated가 false이면, TypeErrorrejected된 promise를 반환한다.

  3. windowthisrelevant settings object로 둔다.

  4. Assert: windowWindow이다.

  5. contextwindowbrowsing context로 둔다.

  6. context가 null이면, TypeErrorrejected된 promise를 반환한다.

  7. preSpecifiedParamsoptionscontext가 주어졌을 때 pre-specified report parameters 얻기의 결과로 둔다.

  8. preSpecifiedParamsDOMException이면, preSpecifiedParamsrejected된 promise를 반환한다.

  9. aggregationCoordinatoroptions가 주어졌을 때 aggregation coordinator 얻기의 결과로 둔다.

  10. aggregationCoordinatorDOMException이면, aggregationCoordinatorrejected된 promise를 반환한다.

  11. documentcontextactive document로 둔다.

  12. thisglobal scopesempty이면, TypeErrorrejected된 promise를 반환한다.

    Note: 이는 selectURL()addModule()보다 먼저 호출되는 경우 발생할 수 있다.

  13. Assert: thisglobal scopessize는 1이다.

  14. globalScopethisglobal scopes[0]으로 둔다.

  15. workletDataOriginglobalScoperealmsettings objectorigin으로 둔다.

  16. "shared-storage-select-url", document, 그리고 workletDataOrigin에 대해 Is feature enabled in document for origin?을 실행한 결과가 false를 반환하면, TypeErrorrejected된 promise를 반환한다.

  17. globalScope에 대해 addModule이 완료되었는지 확인을 실행한 결과가 false이면, TypeErrorrejected된 promise를 반환한다.

  18. urls가 비어 있거나 urlssize가 8보다 크면, TypeErrorrejected된 promise를 반환한다.

    Note: 여기서 8을 선택한 것은 결과 fenced frame이 클릭될 때 selectURL() 호출 하나가 최대 log2(8) = 3비트의 정보만 누설할 수 있도록 하기 위해서이다. 호출당 많은 정보는 아니다.

  19. urlList를 빈 list로 둔다.

  20. urls의 각 urlWithMetadata에 대해 for each:

    1. urlWithMetadata에 "url" 필드가 없으면, TypeErrorrejected된 promise를 반환한다.

    2. 그렇지 않으면, urlStringurlWithMetadata["url"]로 둔다.

    3. serializedUrlurlString과 함께 유효한 경우 canonical URL 문자열 가져오기를 실행한 결과로 둔다.

    4. serializedUrl가 undefined이면, TypeErrorrejected된 promise를 반환한다.

    5. 그렇지 않으면, serializedUrlurlListappend한다.

    6. urlWithMetadata에 "reportingMetadata" 필드가 있으면:

      1. reportingMetadataurlWithMetadata["reportingMetadata"]로 둔다.

      2. reportingMetadata와 함께 reporting metadata 검증을 실행한 결과가 false이면, resultPromiseTypeErrorreject하고 이 단계를 중단한다.

  21. navigablewindowassociated documentnode navigable로 둔다.

  22. fencedFrameConfigMappingnavigabletraversable navigablefenced frame config mapping으로 둔다.

  23. pendingConfig를 새 fenced frame config로 둔다.

  24. urnpendingConfig와 함께 fencedFrameConfigMapping에서 pending config 저장을 실행한 결과로 둔다.

  25. urn이 failure이면, TypeErrorrejected된 promise를 반환한다.

  26. environmentwindowrelevant settings object로 둔다.

  27. allowedInOpaqueOriginContextthishas cross-origin data origin으로 둔다.

  28. environment, workletDataOrigin, 그리고 allowedInOpaqueOriginContext가 주어졌을 때 context에 의해 공유 저장소가 허용되는지 결정을 실행한 결과가 false이면, TypeErrorrejected된 promise를 반환한다.

  29. environmentworkletDataOrigin가 주어졌을 때 사용자 환경설정이 공유 저장소에 대한 접근을 허용하는지 확인을 실행한 결과가 false이면:

    1. thishas cross-origin data origin이 false이면, TypeErrorrejected된 promise를 반환한다.

  30. options["resolveToConfig"]가 true이면, resultPromisependingConfigresolve한다.

  31. 그렇지 않으면, resultPromiseurn으로 resolve한다.

  32. (indexPromise, shouldChargeTopLevelBudgets)를 select-url 결과 인덱스 가져오기this, name, urlList, workletDataOrigin, navigable, options, preSpecifiedParamsaggregationCoordinator와 함께 실행한 결과로 둔다.

  33. indexPromiseresultIndexfulfillment되면, 인덱스 선택 결과 처리worklet, environment, document, urls, urlList, navigable, options, fencedFrameConfigMapping, urn, shouldChargeTopLevelBudgets, false, 그리고 resultIndex와 함께 실행한다.

  34. indexPromiserejection되면, 인덱스 선택 결과 처리worklet, environment, document, urls, urlList, navigable, options, fencedFrameConfigMapping, urn, shouldChargeTopLevelBudgets, true, 그리고 기본 selectURL index와 함께 실행한다.

  35. resultPromise를 반환한다.

run(name, options) 메서드 단계는 다음과 같다:
  1. promise를 새 promise로 둔다.

  2. thisaddModule initiated가 false이면, TypeErrorrejected된 promise를 반환한다.

  3. windowthisrelevant settings object로 둔다.

  4. Assert: windowWindow이다.

  5. contextwindowbrowsing context로 둔다.

  6. context가 null이면, TypeErrorrejected된 promise를 반환한다.

  7. preSpecifiedParamsoptionscontext가 주어졌을 때 pre-specified report parameters 얻기의 결과로 둔다.

  8. preSpecifiedParamsDOMException이면, preSpecifiedParamsrejected된 promise를 반환한다.

  9. aggregationCoordinatoroptions가 주어졌을 때 aggregation coordinator 얻기의 결과로 둔다.

  10. aggregationCoordinatorDOMException이면, aggregationCoordinatorrejected된 promise를 반환한다.

  11. thisglobal scopesempty이면, TypeErrorrejected된 promise를 반환한다.

    Note: 이는 run()addModule()보다 먼저 호출되는 경우 발생할 수 있다.

  12. Assert: thisglobal scopessize는 1이다.

  13. globalScopethisglobal scopes[0]으로 둔다.

  14. globalScope에 대해 addModule이 완료되었는지 확인을 실행한 결과가 false이면, TypeErrorrejected된 promise를 반환한다.

  15. workletDataOriginglobalScoperealmsettings objectorigin으로 둔다.

  16. allowedInOpaqueOriginContextthishas cross-origin data origin으로 둔다.

  17. window, workletDataOrigin, 그리고 allowedInOpaqueOriginContext가 주어졌을 때 context에 의해 공유 저장소가 허용되는지 결정을 실행한 결과가 false이면, promiseTypeErrorreject한다.

  18. windowworkletDataOrigin가 주어졌을 때 사용자 환경설정이 공유 저장소에 대한 접근을 허용하는지 확인을 실행한 결과가 false이면:

    1. thishas cross-origin data origin이 false이면, promiseTypeErrorreject한다.

    2. 그렇지 않으면, promise를 undefined로 resolve한다.

    3. promise를 반환한다.

  19. promise를 반환하고, 즉시 window가 주어졌을 때 worklet agent 얻기를 수행한 뒤, 그 agent에서 나머지 단계를 실행한다:

    Note: promise의 resolution은 SharedStorageWorkletGlobalScope 내부 실행보다 먼저 이루어져야 하며, 그 실행에 의존해서는 안 된다. 이는 shared storage가 분할되지 않은 저장소의 한 종류이고, SharedStorageWorkletGlobalScope가 사이트 간 데이터에 접근할 수 있으므로, 그 데이터가 run()을 통해 (성공/오류 결과를 통해) 누출되어서는 안 되기 때문이다.

    1. window가 주어졌을 때 DOM manipulation task sourceglobal task를 queue하여, promise를 undefined로 resolve한다.

    2. globalScoperelevant settings objectmodule mapempty가 아니면:

      1. operationMapthisSharedStorageWorkletGlobalScopeoperation map으로 둔다.

      2. operationMapnamecontains하면:

        1. Assert: operationMap[name]의 associated realmthisrelevant realm이다.

        2. operationoperationMap[name]을 Function으로 converted한 값으로 둔다.

        3. privateAggregationCompletionTaskworkletDataOrigin, preSpecifiedParamsaggregationCoordinator가 주어졌을 때 Private Aggregation scope 설정의 결과로 둔다.

        4. argumentsList를 새 list로 둔다.

        5. options["data"]가 exists하면, 이를 argumentsListappend한다.

        6. argumentsList 및 "report"와 함께 operationinvoke한다.

        7. 해당되는 경우, operation 실행이 끝날 때까지 기다린다.

        8. privateAggregationCompletionTask를 실행한다.

    3. options["keepAlive"]가 false이면:

      1. 해당되는 경우, operation 실행이 끝날 때까지 기다린다.

      2. worklet global scope 종료this와 함께 실행한다.

aggregation coordinator 얻기를 하려면, SharedStorageRunOperationMethodOptions options가 주어졌을 때, 다음 단계를 수행한다. 이 단계들은 aggregation coordinator, null 또는 DOMException을 반환한다:
  1. options["privateAggregationConfig"]가 exist하지 않으면, null을 반환한다.

  2. options["privateAggregationConfig"]["aggregationCoordinatorOrigin"]가 exist하지 않으면, null을 반환한다.

  3. options["privateAggregationConfig"]["aggregationCoordinatorOrigin"]가 주어졌을 때 Private Aggregation coordinator 얻기의 결과를 반환한다.

pre-specified report parameters 얻기를 하려면, SharedStorageRunOperationMethodOptions optionsbrowsing context context가 주어졌을 때, 다음 단계를 수행한다. 이 단계들은 pre-specified report parameters, null 또는 DOMException을 반환한다:
  1. options["privateAggregationConfig"]가 exist하지 않으면, null을 반환한다.

  2. privateAggregationConfigoptions["privateAggregationConfig"]로 둔다.

  3. contextId를 null로 둔다.

  4. privateAggregationConfig["contextId"]가 exists하면, contextIdprivateAggregationConfig["contextId"]로 설정한다.

  5. contextIdlength가 64보다 크면, 이름이 "DataError"인 새 DOMException을 반환한다.

  6. filteringIdMaxBytes기본 filtering ID max bytes로 둔다.

  7. privateAggregationConfig["filteringIdMaxBytes"]가 exists하면, filteringIdMaxBytesprivateAggregationConfig["filteringIdMaxBytes"]로 설정한다.

  8. filteringIdMaxBytescontained되어 있지 않으면, 유효한 filtering ID max bytes 범위 안에 포함되지 않은 것이므로, 이름이 "DataError"인 새 DOMException을 반환한다.

  9. contextfenced frame config instance가 null이 아니면:

    1. filteringIdMaxBytes기본 filtering ID max bytes가 아니거나 contextId가 null이 아니면, 이름이 "DataError"인 새 DOMException을 반환한다.

  10. maxContributions를 null로 둔다.

  11. privateAggregationConfig["maxContributions"]가 exists하면, maxContributionsprivateAggregationConfig["maxContributions"]로 설정한다.

  12. maxContributions가 0이면, 이름이 "DataError"인 새 DOMException을 반환한다.

  13. 다음 항목을 가진 새 pre-specified report parameters를 반환한다:

    context ID

    contextId

    filtering ID max bytes

    filteringIdMaxBytes

    max contributions

    maxContributions

Private Aggregation scope 설정을 하려면, origin workletDataOrigin, pre-specified report parameters 또는 null인 preSpecifiedParams, 그리고 aggregation coordinator 또는 null인 aggregationCoordinator가 주어졌을 때, 다음 단계를 수행한다. 이 단계들은 알고리즘을 반환한다.

Note: 반환된 알고리즘은 연결된 operation이 완료되었을 때 실행되어야 한다.

  1. batchingScope를 새 batching scope로 둔다.

  2. debugScope를 새 debug scope로 둔다.

  3. privateAggregationTimeout을 null로 둔다.

  4. hasRunPrivateAggregationCompletionTask를 false로 둔다.

  5. privateAggregationCompletionTask를 다음 단계를 수행하는 알고리즘으로 둔다:

    1. hasRunPrivateAggregationCompletionTask이면, 반환한다.

    2. hasRunPrivateAggregationCompletionTask를 true로 설정한다.

    3. debugScope가 주어졌을 때 debug scope 완료 표시를 수행한다.

    4. batchingScope, workletDataOrigin, "shared-storage" 및 privateAggregationTimeout가 주어졌을 때 batching scope에 대한 contribution 처리를 수행한다.

  6. aggregationCoordinator가 null이 아니면, aggregationCoordinatorbatchingScope가 주어졌을 때 batching scope에 대한 aggregation coordinator 설정을 수행한다.

  7. preSpecifiedParams가 null이 아니면:

    1. isDeterministicReportpreSpecifiedParams가 주어졌을 때 report를 결정론적으로 보내야 하는지 결정한 결과로 둔다.

    2. isDeterministicReport이면:

      1. privateAggregationTimeoutcurrent wall timedeterministic operation timeout duration을 더한 값으로 설정한다.

    3. preSpecifiedParamsbatchingScope가 주어졌을 때 batching scope에 대한 pre-specified report parameters 설정을 수행한다.

    4. isDeterministicReport이면, 다음 단계를 in parallel로 실행한다:

      1. privateAggregationTimeout까지 기다린다.

      2. privateAggregationCompletionTask를 실행한다.

  8. privateAggregationCompletionTask를 반환한다.

deterministic operation timeout durationimplementation-defined인 음수가 아닌 duration으로, Shared Storage operation이 deterministic report를 트리거하는 경우 Private Aggregation contribution을 할 수 있는 시간과, 동등하게는 그 report가 operation 시작 후 언제 전송되어야 하는지를 제어한다.

2.2. Worklets에 대한 Monkey Patch

이 명세는 Shared Storage의 필요를 수용하기 위해 Worklet 표준에 일부 수정을 가한다.

2.2.1. worklet environment settings object 설정에 대한 Monkey Patch

worklet environment settings object 설정 알고리즘은 추가 매개변수 Worklet worklet을 포함해야 한다. settingsObjectorigin을 정의하는 단계는 다음과 같이 수정되어야 한다:

  1. settingsObject를 다음과 같이 알고리즘이 정의된 새 environment settings object로 둔다:

    ......

    origin

    1. workletGlobalScoperealmExecutionContext의 Realm 구성요소의 global object로 둔다.

    2. workletGlobalScopeSharedStorageWorkletGlobalScope가 아니면, origin을 반환한다.

    3. Assert: workletSharedStorageWorklet이다.

    4. workletdata origin"context-origin"이면, outsideSettingsorigin을 반환한다.

    5. 그렇지 않고, data origin"script-origin"이면:

      1. pendingAddedModulesworkletadded modules listclone으로 둔다.

      2. Assert: pendingAddedModulessize는 1이다.

      3. moduleURLpendingAddedModules[0]으로 둔다.

      4. moduleURLorigin을 반환한다.

    6. 그렇지 않으면, customOriginUrldata origin에 대해 URL parser를 실행한 결과로 둔다.

    7. Assert: customOriginUrl은 유효한 URL이다.

    8. customOriginUrlorigin을 반환한다.

    ......

2.2.2. worklet global scope 생성에 대한 Monkey Patch

worklet global scope 생성 알고리즘은 worklet 매개변수를 전달하도록 수정되어야 한다:

  1. insideSettingsrealmExecutionContext, outsideSettings, 그리고 worklet이 주어졌을 때 worklet environment settings object 설정을 수행한 결과로 둔다.

2.2.3. worklet script graph 가져오기에 대한 Monkey Patch

worklet script graph 가져오기 알고리즘은 worklet/module worker script graph 가져오기 알고리즘을 호출하며, 이 알고리즘은 알고리즘 매개변수 processCustomFetchResponse를 받는다. 해당 processCustomFetchResponse 매개변수의 정의에는 "5. Fetch request, ..." 단계 앞에 다음 단계가 포함되어야 한다:

  1. fetchClientglobal objectSharedStorageWorkletGlobalScope이면:

    1. requestredirect mode를 "error"로 설정한다.

      Note: shared storage의 경우 module script request에 대해 redirect가 허용되지 않는다. 이 제한을 두면 SharedStorageWorkletGlobalScope가 생성되는 즉시 realmsettings objectorigin을 가져오는 알고리즘(§ 2.2.1 worklet environment settings object 설정에 대한 Monkey Patch에서 설명됨)을 정의하고 사용할 수 있다. origin은 변하지 않기 때문이다. 이 제한은 설계의 향후 반복에서 제거될 수 있다. redirect가 허용된다면, 아마도 realmsettings objectorigin을 가져오는 알고리즘은 최종 request의 response를 받은 후 최종 request의 URLorigin을 반환하도록 갱신되어야 하며, 사용자 환경설정 검사는 그 시점 이후에만 수행되어야 한다.

    2. fetchClientoriginsettingsObjectoriginsame origin이 아니면:

      1. dataOriginValuesettingsObjectoriginserialization으로 둔다.

      2. Assert: dataOriginValue는 null이 아니다.

      3. Append the header (`Sec-Shared-Storage-Data-Origin`, dataOriginValue) to requestheader list.

2.2.4. `Shared-Storage-Cross-Origin-Worklet-Allowed` HTTP 응답 헤더

`Shared-Storage-Cross-Origin-Worklet-Allowed` HTTP 응답 헤더는 기존 CORS 헤더와 함께 사용되어, cross-origin site에 module script의 URLorigin에서 worklet을 생성하고, 이후 해당 worklet에서 module script의 URLorigin을 shared storage data에 접근하기 위한 data partition origin으로 사용하여 후속 operation을 실행할 권한을 부여할 수 있다. 즉, 이는 § 2.2.1 worklet environment settings object 설정에 대한 Monkey Patch에서 설정되는 origin이며, 모든 SharedStorage 호출에서 shared storage bottle map 얻기에 사용되는 origin이 된다.

cross-origin script를 로드하는 worklet은 신뢰할 수 있는 외부 origin을 나타내는 기본 권한 메커니즘으로 CORS에 의존한다. 그러나 CORS만으로는 data partition origin이 script origin인 cross-origin script로 worklet을 생성하기에 충분하지 않다. 단순한 resource sharing과 달리, worklet은 creator site가 target origin의 context 안에서 JavaScript를 실행할 수 있게 한다. 보안을 보장하기 위해 script origin에서 추가 response header인 `Shared-Storage-Cross-Origin-Worklet-Allowed`가 필요하다.

2.2.5. HTTP fetch에 대한 Monkey Patch

단계HTTP fetch 알고리즘에 추가되어야 한다.

Note: module script를 제공하는 site는 보안상 함의를 신중히 고려할 책임이 있다. module script의 URLorigin과 worklet을 생성한 Window origin이 same origin이 아닐 때, module script response에 허용적인 CORS 헤더와 `Shared-Storage-Cross-Origin-Worklet-Allowed` 헤더를 보내면, 서버는 worklet의 생성 및 그 worklet에서의 후속 operation을 허가하는 동시에, worklet이 shared storage data에 접근하기 위한 origin, 즉 data partition origin으로 worklet script의 origin을 사용할 수 있게 허가하게 된다. 예를 들어, worklet을 생성한 WindowselectURL() 또는 run()을 호출하여, worklet origin의 siteremaining navigation budget을 오염시키고 소진시킬 수 있다. 여기서 worklet origin은 global scope의 realmsettings objectorigin이다.

2.2.6. addModule()에 대한 Monkey Patch

addModule() method steps for Worklet에는 "Let promise be a new promise" 단계 앞에 다음 단계가 포함되어야 한다:

  1. thisSharedStorageWorklet 타입이면:

    1. addModuleAllowedResultthismoduleURLRecord가 주어졌을 때 addModule이 허용되는지 확인하고 상태 갱신을 실행한 결과로 둔다.

    2. addModuleAllowedResult가 "DisallowedDueToNonPreferenceError"이면:

      1. TypeErrorrejected된 promise를 반환한다.

    3. 그렇지 않고 addModuleAllowedResult가 "DisallowedDueToPreferenceError"이면:

      1. thishas cross-origin data origin이 false이면, TypeErrorrejected된 promise를 반환한다.

    4. 그렇지 않으면:

      1. Assert: addModuleAllowedResult는 "Allowed"이다.

사용자 환경설정 오류 시 addModule()는 초기 단계에서 중단된다. 그러나 이 오류는 same-origin worklet(즉, initiator document의 origin이 module script의 origin과 same-origin인 경우)에 대해서만 호출자에게 노출된다. cross-origin worklet의 경우 오류는 숨겨진다. 이는 호출자가 사용자가 환경설정을 통해 어떤 origin에 대해 shared storage를 비활성화했는지 알지 못하게 하기 위한 것이다(해당 browser vendor에 per-origin preference가 존재하는 경우).

호출자는 여전히 timing attack을 사용해 이 정보를 알아낼 수 있지만, 이는 사소한 보안/개인정보 보호 문제이다. 실제로는 그러한 환경설정을 지정하는 사용자가 매우 적고, 광범위한 검색을 하면 worklet을 띄우는 데 상당한 성능 비용이 발생하기 때문이다.

이 근거는 selectURL()run()에서의 사용자 환경설정 오류 처리에도 적용된다.

"Let addedSuccessfully be false" 단계 뒤에는 다음 단계를 포함해야 한다:

  1. thisSharedStorageWorklet 타입이고, has cross-origin data origin이 true이며, data origin"script-origin"이 아니면:

    1. Assert: pendingTasks는 1이다.

    2. pendingTasks를 2로 설정한다.

    3. workletGlobalScope가 주어졌을 때 networking task sourceglobal task를 queue하여 다음 단계를 수행한다:

      1. customOriginUrldata origin에 대해 URL parser를 실행한 결과로 둔다.

      2. Assert: customOriginUrl은 유효한 URL이다.

      3. customOriginUrlpath를 ≪".well-known", "shared-storage", "trusted-origins"≫로 설정한다.

      4. request를 새 request로 둔다. 그 URLcustomOriginUrl, mode"cors", referrer"client", destination"json", initiator type"script", 그리고 clientoutsideSettings이다.

      5. Fetch request with processResponseConsumeBody set to the following algorithm, given response response and null, failure or a byte sequence bodyBytes:

        1. 다음 중 하나라도 true이면:

          • bodyBytes가 null 또는 failure이거나,

          • responsestatusok status가 아닌 경우,

          그러면:

          1. pendingTasks를 −1로 설정한다.

          2. promise를 "TypeError" DOMException으로 Reject한다.

          3. 이 단계를 중단한다.

        2. mimeTyperesponseheader list에서 MIME type 추출을 수행한 결과로 둔다.

        3. mimeTypeJSON MIME type이 아니면:

          1. pendingTasks를 −1로 설정한다.

          2. promise를 "TypeError" DOMException으로 Reject한다.

          3. 이 단계를 중단한다.

        4. sourceTextbodyBytes에 대해 UTF-8 decoding을 수행한 결과로 둔다.

        5. parsedsourceText가 주어졌을 때 JSON 문자열을 Infra 값으로 파싱한 결과로 둔다.

        6. parsedlist가 아니거나 parsedempty이면:

          1. pendingTasks를 −1로 설정한다.

          2. promise를 "TypeError" DOMException으로 Reject한다.

          3. 이 단계를 중단한다.

        7. doesMatch를 false로 둔다.

        8. parsed의 각 item에 대해:

          1. itemordered map이 아니거나, itemscriptOrigincontain하지 않거나, itemcontextOrigincontain하지 않으면:

            1. pendingTasks를 −1로 설정한다.

            2. promise를 "TypeError" DOMException으로 Reject한다.

            3. 이 단계를 중단한다.

          2. doesMatchitem[scriptOrigin], moduleURLRecordorigin, item[contextOrigin], 및 outsideSettingsorigin에 대해 script와 context origin 일치 여부 확인을 실행한 결과로 둔다.

          3. doesMatch가 true이면:

            1. thisrelevant global object가 주어졌을 때 networking task sourceglobal task를 queue하여 다음 단계를 수행한다:

              1. pendingTasks가 −1이 아니면:

                1. pendingTaskspendingTasks − 1로 설정한다.

                2. pendingTasks가 0이면, 다음 단계를 수행한다:

                  1. workletGlobalScope에 연결된 boolean addModule success가 있으면, workletGlobalScopeaddModule success를 true로 설정한다.

                  2. promiseResolve한다.

            2. 중단한다.

        9. doesMatch가 false이면:

          1. pendingTasks를 −1로 설정한다.

          2. promise를 "TypeError" DOMException으로 Reject한다.

Note: worklet data origin이 현재 context 및 script origin과 다르면 추가 검사가 수행된다. 이는 worklet data origin에서 configuration file을 가져와, 현재 context가 해당 script로 worklet을 로드하고 operation을 수행하도록 허용되어 있는지 확인하는 것을 포함한다.

끝에서 두 번째 단계(즉, 마지막으로 들여쓰기된 단계), 현재의 "If pendingTasks is 0, then resolve promise."는 다음과 같이 갱신되어야 한다:

  1. pendingTasks가 0이면, 다음 단계를 수행한다:

    1. workletGlobalScope에 연결된 boolean addModule success가 있으면, workletGlobalScopeaddModule success를 true로 설정한다.

    2. promiseResolve한다.

마지막 단계, 현재의 "Return promise." 바로 앞에 다음 단계를 추가한다:

  1. thisSharedStorageWorklet이면, promisefulfillment 시 또는 promiserejection 시, 다음 단계를 실행한다:

    1. globalScopesthisglobal scopes로 둔다.

    2. Assert: globalScopessize는 1과 같다.

    3. privateAggregationObjglobalScopes[0]의 privateAggregation으로 둔다.

    4. privateAggregationObjallowed to use를, thisrelevant global objectassociated document가 "private-aggregation" policy-controlled feature사용하도록 허용되어 있는지 결정한 결과로 설정한다.

      permissions policy 검사가 먼저 수행되는 경우 여기에서 early return을 추가하는 것을 고려한다.

    5. privateAggregationObjscoping details를 다음 항목을 가진 새 scoping details로 설정한다:

      get batching scope steps

      scope에서 현재 실행 중인 call이 반환될 때 batching scope에 대한 contribution 처리에 전달되도록 예약된 batching scope를 반환하는 알고리즘.

      get debug scope steps

      scope에서 현재 실행 중인 call이 반환될 때 debug scope 완료 표시에 전달되도록 예약된 debug scope를 반환하는 알고리즘.

      Note: 여러 operation invocation이 동시에 진행 중일 수 있으며, 각각 다른 batching scope와 debug scope를 가진다. 그러나 현재 실행 중인 것은 하나뿐일 수 있다.

trusted origin typestring 또는 list of strings이다.

script와 context origin 일치 여부 확인을 하려면, trusted origin type itemScriptOrigin, origin actualScriptOrigin, trusted origin type itemContextOrigin, 및 origin actualContextOrigin이 주어졌을 때, 다음 단계를 수행한다:
  1. itemScriptOriginactualScriptOrigin이 주어졌을 때 trusted origin 일치 여부 확인을 실행한 결과가 false이면, false를 반환한다.

  2. itemContextOriginactualContextOrigin이 주어졌을 때 trusted origin 일치 여부 확인을 실행한 결과를 반환한다.

trusted origin 일치 여부 확인을 하려면, trusted origin type itemOriginorigin actualOrigin이 주어졌을 때, 다음 단계를 수행한다:
  1. itemOriginstring이면, itemOriginactualOrigin이 주어졌을 때 문자열에 대한 trusted origin 일치 여부 확인을 실행한 결과를 반환한다.

  2. 그렇지 않으면, itemOrigin 안의 각 originString에 대해:

    1. originStringactualOrigin이 주어졌을 때 문자열에 대한 trusted origin 일치 여부 확인을 실행한 결과가 true이면, true를 반환한다.

  3. false를 반환한다.

문자열에 대한 trusted origin 일치 여부 확인을 하려면, string itemOriginorigin actualOrigin이 주어졌을 때, 다음 단계를 수행한다:
  1. itemOrigin"*"이면 true를 반환한다.

  2. itemOriginUrlitemOrigin에 대해 URL parser를 실행한 결과로 둔다.

  3. itemOriginUrl이 유효한 URL이 아니면 false를 반환한다.

  4. itemOriginUrloriginactualOriginsame origin이면 true를 반환한다.

  5. 그렇지 않으면 false를 반환한다.

out-of-process worklet에 대한 추가 monkey patch 조각을 추가한다.

2.3. SharedStorageWorkletGlobalScope

SharedStorageWorkletworklet global scope typeSharedStorageWorkletGlobalScope이다.

SharedStorageWorkletworklet destination type은 "sharedstorageworklet"이다.

2.3.1. request destination에 대한 Monkey Patch

fetch request의 destination 필드는 유효한 값으로 "sharedstorageworklet"을 추가로 포함해야 한다.

callback RunFunctionForSharedStorageSelectURLOperation = Promise<unsigned long>(sequence<USVString> urls, optional any data);
[Exposed=SharedStorageWorklet, Global=SharedStorageWorklet]
interface SharedStorageWorkletGlobalScope : WorkletGlobalScope {
  undefined register(DOMString name,
                     Function operationCtor);

  readonly attribute SharedStorage sharedStorage;
  readonly attribute PrivateAggregation privateAggregation;

  Promise<sequence<StorageInterestGroup>> interestGroups();

  readonly attribute SharedStorageWorkletNavigator navigator;
};

SharedStorageWorkletGlobalScope은 연결된 environment settings object outside settings를 가지며, 이는 연결된 SharedStorageWorkletrelevant settings object이다.

SharedStorageWorkletGlobalScope은 연결된 boolean addModule success를 가지며, false로 초기화된다.

SharedStorageWorkletGlobalScope은 또한 연결된 operation map을 가지며, 이는 처음에는 비어 있는 map으로, strings(operation 이름을 나타냄)를 function objects에 매핑한다.

SharedStorageWorkletGlobalScope은 연결된 SharedStorage 인스턴스 shared storage instance를 가진다.

SharedStorageWorkletGlobalScope은 연결된 SharedStorageWorkletNavigator 인스턴스 navigator instance를 가진다.

2.3.2. SharedStorageWorkletGlobalScope 알고리즘

register(name, operationCtor) 메서드 단계는 다음과 같다:
  1. name이 없거나 비어 있으면, TypeError를 throw한다.

  2. operationMap을 이 SharedStorageWorkletGlobalScopeoperation map으로 둔다.

  3. operationMapcontains an entry with key name이면, TypeError를 throw한다.

  4. operationCtor가 없으면, TypeError를 throw한다.

  5. operationClassInstance를 인수 없이 operationCtorconstructing한 결과로 둔다.

  6. runFunctionGet(operationClassInstance, "run")으로 둔다. 모든 예외는 다시 throw한다.

  7. IsCallable(runFunction)이 false이면, TypeError를 throw한다.

  8. operationMap[name]의 값을 runFunction으로 Set한다.

WebIDL을 고려하면 여기서 "name"과 "operationCtor"는 누락될 수 없다. default/empty 값만 확인해야 한다. [Issue #151]

interestGroups() 메서드 단계는 다음과 같다:
  1. promise를 새 promise로 둔다.

  2. SharedStorage의 연결된 SharedStorageWorkletGlobalScope에 대해 addModule이 완료되었는지 확인을 실행한 결과가 false이면, TypeErrorrejected된 promise를 반환한다.

  3. globalObjectcurrent realmglobal object로 둔다.

  4. contextglobalObjectbrowsing context로 둔다.

  5. context가 null이면, TypeErrorrejected된 promise를 반환한다.

  6. documentcontextactive windowassociated document로 둔다.

  7. documentfully active가 아니면, TypeErrorrejected된 promise를 반환한다.

  8. workletDataOrigincurrent realmsettings objectorigin으로 둔다.

  9. 다음 단계를 in parallel로 실행한다:

    1. interestGroupsworkletDataOrigin가 주어졌을 때 owner에 대한 storage interest group 가져오기를 실행한 결과로 둔다.

    2. interestGroups가 failure이면:

      1. realmglobal object가 주어졌을 때 DOM manipulation task sourceglobal task를 queue하여, promiseTypeErrorreject한다.

    3. 그렇지 않으면:

      1. realmglobal object가 주어졌을 때 DOM manipulation task sourceglobal task를 queue하여, promiseinterestGroupsresolve한다.

  10. promise를 반환한다.

sharedStorage getter steps는 다음과 같다:
  1. thisaddModule success가 true이면, thisshared storage instance를 반환한다.

  2. 그렇지 않으면, TypeError를 throw한다.

navigator getter steps는 다음과 같다:
  1. thisnavigator instance를 반환한다.

privateAggregation getter steps는 다음을 수행한다:
  1. privateAggregation 가져오기this가 주어졌을 때 수행한다.

addModule이 완료되었는지 확인하려면, 단계는 다음과 같다:
  1. addModule success의 값을 반환한다.

2.4. SharedStorageUrlWithMetadata 및 Reporting

dictionary SharedStorageUrlWithMetadata {
  required USVString url;
  object reportingMetadata;
};

SharedStorageUrlWithMetadata dictionary가 비어 있지 않은 reportingMetadata object를 포함하고, 그 형태가 dictionary이며, 그 keysFenceEventeventType들이고, 그 values가 유효한 URLs로 파싱되는 strings이면, 이러한 eventType-URL 쌍은 이 selectURL() 호출로부터 생긴 SharedStorageResponse를 로드하는 임의의 fenced frame 내에서 나중에 접근할 수 있도록 registered된다.

reportingMetadatadictionary여야 한다. [Issue #141]

selectURL()을 통해 reportingMetadata object들로 registeredeventType-URL 쌍이 있는 fenced frame 내부에서, reportEvent()가 "shared-storage-select-url"을 containing하는 destination을 가진 FenceEvent에서 호출되고, 그 FenceEvent의 대응하는 eventType이 트리거되면, 해당 FenceEventeventData는 그 eventType에 대해 등록된 URLbeacon으로 전송된다.

reporting metadata 검증을 하려면, object reportingMetadata가 주어졌을 때, 다음 단계를 실행한다:
  1. reportingMetadatadictionary가 아니면 false를 반환한다.

  2. reportingMetadataempty이면, true를 반환한다.

  3. reportingMetadata의 각 eventTypeurlString에 대해 For each, urlString과 함께 유효한 경우 canonical URL 문자열 가져오기를 실행한 결과가 undefined이면 false를 반환한다.

  4. true를 반환한다.

유효한 경우 canonical URL 문자열 가져오기를 하려면, string urlString이 주어졌을 때, 다음 단계를 실행한다:
  1. urlurlString에 대해 URL parser를 실행한 결과로 둔다.

  2. url이 유효한 URL이 아니면 undefined를 반환한다.

  3. 그렇지 않으면, url에 대해 URL serializer를 실행한 결과를 반환한다.

reporting metadata 등록을 하려면, object reportingMetadatafenced frame config fencedFrameConfigStruct가 주어졌을 때, 다음 단계를 실행한다:
  1. reportingMetadataempty이면, 반환한다.

  2. Assert: reportingMetadatadictionary이다.

  3. reportingUrlMap을 비어 있는 mapempty로 둔다.

  4. reportingMetadata의 각 eventTypeurlString에 대해 For each:

    1. urlurlString에 대해 URL parser를 실행한 결과로 둔다.

    2. Assert: url은 유효한 URL이다.

    3. reportingUrlMap[eventType]을 urlSet한다.

reportingUrlMapfencedFrameConfigStruct와 연결된 fenced frame reporter 클래스 내부에 저장한다. 이 둘은 아직 [Fenced-Frame] 초안에 추가되어야 한다. [Issue #144]

2.5. 엔트로피 예산

bits of entropyselectURL()를 통해 누출될 수 있으므로, user agent는 이러한 누출을 제한하기 위해 예산을 유지해야 한다.

selectURL() 호출 시 이러한 예산 중 하나라도 소진되면, 어떤 URL을 선택할지 결정하기 위해 기본 selectURL index가 사용된다.

기본 selectURL index 가져오기를 하려면, sequence<USVString> urls가 주어졌을 때, 다음 단계를 실행한다:
  1. 0을 반환한다.

    Note: 반환된 index가 등록된 operation class의 "run" 메서드와 독립적인 한, 0부터 urlssize까지의 range(끝값 제외)에서 임의의 unsigned long을 반환하도록 선택할 수도 있었다.

기본 selectURL indexsequence<USVString> urls가 주어졌을 때, 기본 selectURL index 가져오기를 실행하여 얻은 index이다.

사용자가 selectURL()에 의해 생성된 fenced frame config instance를 가진 node documentbrowsing context에 속한 fenced frameactivates하고, 그로 인해 top-level traversable navigation이 시작되면, 이는 landing page에 자신의 URL이 선택되었음을 드러내며, 이는 selectURL() 호출에 대한 입력 URLs 개수의 밑이 2인 로그까지 entropy bits가 누출되는 것이다. 이를 완화하기 위해, user agentsitenavigation entropy allowance를 설정한다.

navigation entropy allowance는 주어진 호출 site에 대해 주어진 navigation budget epoch 동안, fenced framestop-level traversable navigations를 시작함으로써 누출이 허용되는 entropy bits의 최대 허용량이다. 이 allowanceuser agent에 의해 정의되며 site와 무관하다.

user agent는 고정된 미리 정해진 durationnavigation budget lifetime을 정의한다.

navigation budget epoch는 그 durationnavigation budget lifetime인 임의의 시간 간격이다.

navigation entropy allowance가 어떻게 사용되는지 추적하기 위해, user agentshared storage navigation budget table을 사용하며, 이는 sitesnavigation entropy ledgers에 매핑하는 map이다.

navigation entropy ledgerbit debitslist이다.

bit debit는 다음 items를 가진 struct이다:

bits

double

timestamp

DOMHighResTimeStamp (Unix Epoch 기준)

Bit debits 중 그 timestamps가 현재 navigation budget epoch의 시작보다 앞서는 것은 expired되었다고 한다.

누출이 발생하면, 그 값은 entropy bits로 계산되어 해당 site에 대해 저장되고, 현재 시간이 timestamp로 함께 저장되어, 이 둘이 합쳐진 bit debitshared storage navigation budget table에 저장된다.

site는 연결된 double remaining navigation budget를 가지며, 그 값은 navigation entropy allowance에서 현재 navigation budget epoch 안에 있는 timestamps를 가진 모든 bit debits를 뺀 값이다.

siteremaining navigation budget이 부족하면, selectURL()기본 selectURL index에 있는 SharedStorageUrlWithMetadataurl에 대한 SharedStorageResponse (즉 FencedFrameConfig 또는 urn uuid)를 반환한다.

남은 navigation budget 결정을 하려면, environment settings object environmentsite site가 주어졌을 때, 다음 단계를 실행한다:
  1. Assert: siteopaque origin이 아니다.

  2. maxBitsuser agentnavigation entropy allowance로 둔다.

  3. user agentshared storage navigation budget tablesitecontain하지 않으면 maxBits를 반환한다.

  4. 그렇지 않으면, ledgeruser agentshared storage navigation budget table[site]로 둔다.

  5. debitSum을 0으로 둔다.

  6. ledger의 각 item bitDebit에 대해 For each, 다음 단계를 수행한다:

    1. debitbitDebitbits로 둔다.

    2. environmentbitDebit와 함께 bit debit이 expired되었는지 확인을 실행한 결과가 false이면, debitSumdebit만큼 증가시킨다.

  7. maxBitsdebitSum을 반환한다.

bit debit이 expired되었는지 확인을 하려면, environment settings object environmentbit debit bitDebit가 주어졌을 때, 다음 단계를 실행한다:
  1. epochLengthuser agentnavigation budget lifetime으로 둔다.

  2. currentTimeenvironmentcurrent wall time으로 둔다.

  3. thresholdcurrentTimeepochLength로 둔다.

  4. bitDebittimestampthreshold보다 작으면 true를 반환한다.

  5. 그렇지 않으면 false를 반환한다.

selectURL()를 통해 생성된 fenced frame config instance를 가진 node documentbrowsing context에 속한 fenced frame에 의해 시작된 각 top-level traversable navigation마다 bit debitshared storage navigation budget tablecharged해야 한다. 이는 cross-site data를 누출할 수 있기 때문이다. 부과할 bitsselectURL() 호출 중에 계산되지만, 결과 fenced frame이 top-level traversable navigation을 시작하는 경우 그리고 그 시점에만 실제로 shared storage navigation budget table에 기록되므로, bits는 이 시점까지 대응하는 fenced frame의 node documentbrowsing contextfenced frame config instance 안에 pending shared storage budget debit로 저장되어야 한다.

pending shared storage budget debit의 정의를 fenced frame config instance[Fenced-Frame] 초안 명세에서 이동한다. [Issue #148]

beginning navigationending navigation 사이에, user agentshared storage navigation budget 부과 알고리즘을 수행한다.

navigation budget charging의 타이밍을 명시할 더 나은 방법을 찾아야 한다. [Issue #138]

shared storage navigation budget 부과를 하려면, navigationnavigable navigableDocument sourceDocument가 주어졌을 때, 다음 단계를 실행한다:
  1. navigabletop-level traversable이 아니면 반환한다.

  2. currentNavigablesourceDocumentnode navigable로 둔다.

  3. currentNavigable이 null이 아닌 동안:

    1. sitecurrentNavigableactive documentorigin으로 obtain a site를 실행한 결과로 둔다.

    2. instancecurrentNavigablenode documentbrowsing contextfenced frame config instance로 둔다.

    3. currentNavigablecurrentNavigableparent로 설정한다.

    4. instance가 null이거나 siteopaque origin이면 continue한다.

    5. pendingBitsinstancepending shared storage budget debit로 둔다.

    6. pendingBits가 0보다 크지 않으면 continue한다.

    7. ledgeruser agentshared storage navigation budget table[site]로 둔다.

    8. bitDebit를 새 bit debit로 둔다.

    9. bitDebitbitspendingBits로 설정한다.

    10. currentTimecurrent wall time으로 둔다.

    11. bitDebittimestampcurrentTime으로 설정한다.

    12. bitDebitledgerAppend한다.

    13. pendingBits를 0으로 설정한다.

user agentexpiredbit debits가 더 이상 필요하지 않으므로, 모든 navigation entropy ledger에서 expired된 bit debits 제거를 주기적으로 수행하도록 timer를 설정하고 싶을 수 있다.

모든 navigation entropy ledger에서 expired된 bit debits 제거를 하려면, 다음 단계를 실행한다:
  1. user agentshared storage navigation budget table의 각 originledger에 대해 For each:

    1. ledger 안의 각 bitDebit에 대해 For each, bitDebit와 함께 bit debit이 expired되었는지 확인을 실행한 결과가 true이면, bitDebitledger에서 remove한다.

2.5.2. Top-Level Traversable 엔트로피 예산

단기적으로는, 더 제한이 적은 fenced frames가 있는 동안, 다음과 같은 추가 제한을 부과할 필요가 있다.

user agent는 최대 overall page entropy allowance와 최대 site page entropy allowance를 지정하며, 전자는 top-level traversable별로 selectURL()에 대해 누출이 허용되는 총 비트 수이고, 후자는 site별, top-level traversable별로 selectURL()에 대해 누출이 허용되는 총 비트 수이다

shared storage page budget은 다음 items를 가진 struct이다:

overall budget

double

site budget map

map of site to double

saved query map

map of tuples (origin data origin, URL worklet script URL, string operation name, string query name) to saved query data

saved query data는 다음 items를 가진 struct이다:

index

long

callbacks

queue of tasks

2.5.2.1. Traversable Navigables에 대한 Monkey patch

[HTML]Traversable navigables 절에 다음을 추가한다:

navigable의 속성에 더해, traversable navigable은 다음을 가진다:

2.5.2.2. Navigables에 대한 Monkey patch

navigable 초기화 알고리즘의 끝에 다음 단계를 추가하여 수정한다:

  1. parent가 null이고 navigabletraversable navigable이면:

    1. newPageBudget를 비어 있는 site budget map을 가진 shared storage page budget으로 둔다.

    2. newPageBudgetoverall budgetoverall page entropy allowance로 설정한다.

    3. navigablepage budgetnewPageBudget로 설정한다.

2.5.2.3. 저장된 질의
저장된 질의에 대한 인덱스 가져오기를 하려면, navigable navigable, origin origin, URL moduleURLRecord, string operationName, string savedQueryName, 그리고 task callbackTask가 주어졌을 때:
  1. topLevelTraversablenavigable에 대해 top-level traversable 가져오기를 실행한 결과로 둔다.

  2. Assert: topLevelTraversablepage budget은 null이 아니다.

  3. topLevelTraversablepage budgetsaved query map이 (origin, moduleURLRecord, operationName, savedQueryName)을 contain하지 않으면:

    1. topLevelTraversablepage budgetsaved query map[(origin, moduleURLRecord, operationName, savedQueryName)]을 새 saved query data struct queryDataSet한다.

    2. queryDataindex 값을 -1로 설정한다.

    3. "pending current operation"을 반환한다.

  4. savedIndextopLevelTraversablepage budgetsaved query map[(origin, moduleURLRecord, operationName, savedQueryName)]의 index로 둔다.

  5. savedIndex가 -1이면:

    1. callbackTaskqueryDatacallbacksEnqueue한다.

    2. "pending callback"을 반환한다.

  6. savedIndex를 반환한다.

Note: 저장된 질의에 대한 인덱스 가져오기 알고리즘은 index 값이 SharedStorageWorkletGlobalScopeworklet event looptask를 queue하여 registered operation을 수행한 결과를 기다리고 있음을 나타내기 위해 "pending current operation"을 반환한다.

Note: 저장된 질의에 대한 인덱스 가져오기 알고리즘은 index의 결과를 결정할 task가 이전에 SharedStorageWorkletGlobalScopeworklet event loopqueued되었으며, 이제 원래 task가 완료되었을 때 실행될 추가 callbackTask를 queue하고 있음을 나타내기 위해 "pending callback"을 반환한다.

저장된 질의에 대한 인덱스 저장을 하려면, Window window, navigable navigable, origin origin, URL moduleURLRecord, string operationName, string savedQueryName, 그리고 unsigned long index가 주어졌을 때:
  1. topLevelTraversablenavigable에 대해 top-level traversable 가져오기를 실행한 결과로 둔다.

  2. Assert: topLevelTraversablepage budget은 null이 아니다.

  3. queryDatatopLevelTraversablepage budgetsaved query map[(origin, moduleURLRecord, operationName, savedQueryName)]로 둔다.

  4. queryDataindexindexSet한다.

  5. queryDatacallbacks가 비어 있지 않은 동안 While:

    1. 다음 task callbackTaskqueryDatacallbacks에서 Dequeue하고, window가 주어졌을 때 DOM manipulation task sourceglobal task를 queue하여 index가 주어졌을 때 callbackTask의 단계를 실행한다.

저장된 인덱스 결과를 처리할 callback 얻기를 하려면, Window window, SharedStorageUrlWithMetadata들의 list urlList, promise promise가 주어졌을 때, 다음 단계를 수행한다. 이 단계들은 알고리즘을 반환한다.
  1. processIndexTaskunsigned long index가 주어졌을 때 다음 단계를 수행하는 알고리즘으로 둔다:

    1. indexurlListsize보다 크면, window가 주어졌을 때 DOM manipulation task sourceglobal task를 queue하여 promiseTypeErrorreject한다.

      Note: 결과 index가 입력 urls의 size를 벗어난다. 이는 selectURL() 프로토콜을 위반하며, 어떤 url이 선택되어야 하는지 알 수 없다.

    2. 그렇지 않으면, window가 주어졌을 때 DOM manipulation task sourceglobal task를 queue하여 promiseindexresolve한다.

  2. processIndexTask를 반환한다.

2.5.2.4. Top-Level Traversable 엔트로피 예산 부과
shared storage top-level traversable budgets 부과를 하려면, navigable navigable, site site, 그리고 double pendingBits가 주어졌을 때, 다음 단계를 실행한다:
  1. topLevelTraversablenavigable에 대해 top-level traversable 가져오기를 실행한 결과로 둔다.

  2. Assert: topLevelTraversablepage budget은 null이 아니다.

  3. pendingBitstopLevelTraversablepage budgetoverall budget보다 크면, false를 반환하고 이 단계를 중단한다.

  4. topLevelTraversablepage budgetsite budget mapsitecontain하지 않으면, topLevelTraversablepage budgetsite budget map [site]을 site page entropy allowanceset한다.

  5. pendingBitstopLevelTraversablepage budgetsite budget map [site]보다 크면, false를 반환하고 이 단계를 중단한다.

  6. topLevelTraversablepage budgetsite budget map [site]을 pendingBits만큼 감소시킨다.

  7. topLevelTraversablepage budgetoverall budgetpendingBits만큼 감소시킨다.

  8. true를 반환한다.

3. Shared Storage의 백엔드

Shared Storage API는 아래와 같이, 새 storage endpointregistering함으로써 Storage API에 통합된다.

3.1. Storage Model에 대한 Monkey Patch

이 표준은 Storage Model에 새 storage type "shared"를 추가한다.

user agenttype "shared"인 storage endpoints에 대해 shared storage shed를 보유한다.

또한 이 표준은 type "shared", storage identifier "sharedStorage", 그리고 quota 54 * 216 bytes(즉 39.0625 mebibytes)를 가진 storage endpointregister한다.

quota는 현재 구현에서 계산된 것이다. 현재 구현을 storage endpoints "localStorage" 및 "sessionStorage"에 대한 명세, 즉 5 * 220 bytes에 맞추는 것을 고려한다. 예를 들어, origin별 entry 제한을 10,000에서 1,280으로 줄이면 이를 달성할 수 있다.

shared storage shedoriginsstorage shelves에 매핑하는 map이다. 처음에는 비어 있다.

Note: key가 storage keysstorage sheds와 달리, shared storage shedsorigins를 직접 key로 사용한다. Shared storage는 의도적으로 client-side storage partitioning에서 제외된다.

shared storage shed 안의 각 storage shelf에 대해, 그 storage shelfbucket map은 현재 "default"라는 단일 key만 가진다.

user agentshared storage shed는 모든 shared storage 데이터를 보유한다.

shared storage shelf 얻기를 하려면, shared storage shed shed, environment settings object environment, 그리고 origin origin이 주어졌을 때, 다음 단계를 실행한다:
  1. allowedInOpaqueOriginContext를 false로 둔다.

  2. environment, origin, 그리고 allowedInOpaqueOriginContext가 주어졌을 때 context에 의해 shared storage가 허용되는지 결정을 실행한 결과가 false이면, failure를 반환한다.

  3. environmentorigin이 주어졌을 때 사용자 환경설정이 shared storage에 대한 접근을 허용하는지 확인을 실행한 결과가 false이면, failure를 반환한다.

  4. shed[origin]이 존재하지 않으면, shed[origin]을 type "shared"와 함께 shared storage shelf 생성을 실행한 결과로 설정한다.

  5. shed[origin]을 반환한다.

shared storage shelf 생성을 하려면, 다음 단계를 실행한다:
  1. shelf를 새 storage shelf로 둔다.

  2. shelfbucket map["default"]을 shared storage bucket 생성을 실행한 결과로 설정한다.

  3. shelf를 반환한다.

shared storage bucketshared storage shedshelves 중 하나에 있는 storage bucket이다.

shared storage bucket 생성을 하려면, 다음 단계를 실행한다:
  1. endpointstorage identifier "sharedStorage"를 가진 storage endpoint로 둔다.

  2. bucket을 새 shared storage bucket으로 둔다.

  3. bucketbottle map["sharedStorage"]을 새 storage bottle로 설정하며, 그 quotaendpointquota이다.

  4. bucket을 반환한다.

Note: 현재 shared storage bucketbottle mapsize 1을 가진다. 이는 type "shared"로 registeredstorage endpoint가 하나뿐이기 때문이다.

shared storage bottle map 얻기를 하려면, environment settings object environmentorigin origin이 주어졌을 때, 다음 단계를 실행한다:
  1. sheduser agentshared storage shed로 둔다.

  2. shelfshed, environment, 그리고 origin과 함께 shared storage shelf 얻기를 실행한 결과로 둔다.

  3. shelf가 failure이면 failure를 반환한다.

  4. bucketshelfbucket map["default"]으로 둔다.

  5. bottlebucketbottle map["sharedStorage"]로 둔다.

  6. proxyMap을 새 storage proxy map으로 두며, 그 backing mapbottlemap이다.

  7. proxyMapbottleproxy map reference setAppend한다.

  8. proxyMap을 반환한다.

3.2. Shared Storage Database

browsing context는 연결된 shared storage database를 가지며, 이는 데이터를 store, retrieve, delete, clear, 그리고 purge expired할 수 있는 메서드와 아래와 같은 추가 메서드를 제공한다. database 안의 데이터는 entries 형태를 취한다.

shared storage databaseshared storage database queue를 가지며, 이는 새 parallel queue 시작의 결과이다. 이 queue는 해당 browsing context에서 호출이 시작될 때 각 shared storage database의 메서드를 실행하는 데 사용된다.

entrykeyvalue struct로 구성된다.

entrykeystring이다.

User agentskeymaximum length를 지정할 수 있다.

keysentries를 구성하고 효율적으로 검색하는 데 사용되므로, keys는 주어진 shared storage database 안에서 최대 한 번만 나타나야 한다.

entryvalue structstring valueDOMHighResTimeStamp last updated(Unix Epoch 기준)로 구성된 struct이다.

User agentsvaluemaximum length를 지정할 수 있다.

User agentsdefault entry lifetime, 즉 entrystored된 시점부터 만료되는 시점까지의 기본 duration을 지정할 수 있다. user agentdefault entry lifetime을 지정하는 경우, database에서 expired entries를 purge하는 timer를 주기적으로 가져야 한다.

3.3. 핵심 Database 알고리즘

database에 entry 저장을 하려면, shared storage database queue queue, storage proxy map databaseMap, environment settings object environment, key key, 그리고 value value가 주어졌을 때, queue에서 다음 단계를 실행한다:
  1. valueStruct를 새 value struct로 둔다.

  2. valueStructvaluevalue로 설정한다.

  3. currentTimeenvironmentcurrent wall time으로 둔다.

  4. valueStructlast updatedcurrentTime으로 설정한다.

  5. databaseMap[key]를 valueStructSet한다.

  6. exception이 throw되었으면 false를 반환한다.

    Note: 구현에 따라 storage proxy map databaseMap의 메서드에서 오류가 발생할 수 있다.

  7. 그렇지 않으면 true를 반환한다.

database에서 entry 가져오기를 하려면, shared storage database queue queue, storage proxy map databaseMap, environment settings object environment, 그리고 key key가 주어졌을 때, queue에서 다음 단계를 실행한다:
  1. databaseMapkeycontain하지 않으면 undefined를 반환한다.

  2. valueStructdatabaseMap에 대해 key와 함께 Get을 실행한 결과로 둔다.

  3. exception이 throw되었으면 failure를 반환한다.

    Note: 구현에 따라 storage proxy map databaseMap의 메서드에서 오류가 발생할 수 있다.

  4. environmentvalueStruct와 함께 entry가 expired되었는지 결정을 실행한 결과가 true이면 undefined를 반환한다.

  5. valueStructvalue를 반환한다.

database에서 entry 삭제를 하려면, shared storage database queue queue, storage proxy map databaseMap, 그리고 key key가 주어졌을 때, queue에서 다음 단계를 실행한다:
  1. databaseMap[key]를 Remove한다.

  2. exception이 throw되었으면 false를 반환한다.

    Note: 구현에 따라 storage proxy map databaseMap의 메서드에서 오류가 발생할 수 있다.

  3. true를 반환한다.

database의 모든 entry 지우기를 하려면, shared storage database queue queuestorage proxy map databaseMap가 주어졌을 때, queue에서 다음 단계를 실행한다:
  1. databaseMap에서 Clear를 실행한다.

  2. exception이 throw되었으면 false를 반환한다.

    Note: 구현에 따라 storage proxy map databaseMap의 메서드에서 오류가 발생할 수 있다.

  3. true를 반환한다.

database에서 모든 entry 가져오기를 하려면, shared storage database queue queuestorage proxy map databaseMap가 주어졌을 때, queue에서 다음 단계를 실행한다:
  1. valuesdatabaseMap에서 값 가져오기를 실행한 결과로 둔다.

  2. exception이 throw되었으면 failure를 반환한다.

    Note: 구현에 따라 storage proxy map databaseMap의 메서드에서 오류가 발생할 수 있다.

  3. values를 반환한다.

database의 entry 개수 세기를 하려면, shared storage database queue queuestorage proxy map databaseMap가 주어졌을 때, queue에서 다음 단계를 실행한다:
  1. sizedatabaseMapsize로 둔다.

  2. exception이 throw되었으면 failure를 반환한다.

    Note: 구현에 따라 storage proxy map databaseMap의 members에서 오류가 발생할 수 있다.

  3. size를 반환한다.

database에서 expired entries 제거를 하려면, shared storage database queue queue, storage proxy map databaseMap, 그리고 environment settings object environment가 주어졌을 때, queue에서 다음 단계를 실행한다:
  1. databaseMap 안의 각 key key에 대해 For each:

    1. valueStructdatabaseMap에 대해 key와 함께 Get을 실행한 결과로 둔다.

    2. exception이 throw되었으면 false를 반환한다.

    3. environmentvalueStruct와 함께 entry가 expired되었는지 결정을 실행한 결과가 true이면, databaseMap[key]를 Remove한다.

    4. exception이 throw되었으면 false를 반환한다.

  2. true를 반환한다.

entry가 expired되었는지 결정하려면, environment settings object environmentvalue struct valueStruct가 주어졌을 때, 다음 단계를 실행한다:

  1. lastUpdatedvalueStructlast updated로 둔다.

  2. lifetimeuser agentdefault entry lifetime으로 둔다.

  3. expirationlastUpdatedlifetime의 합으로 둔다.

  4. currentTimeenvironmentcurrent wall time으로 둔다.

  5. expirationcurrentTime보다 작거나 같으면 true를 반환한다.

  6. 그렇지 않으면 false를 반환한다.

3.4. 특수화된 Database 알고리즘

이 알고리즘들은 § 3.3 핵심 Database 알고리즘의 핵심 알고리즘과 달리, 더 특수화된 휴리스틱을 가진 매개변수를 받거나, 다단계 프로세스를 사용하거나, 또는 둘 다를 사용하여 더 복잡한 database operation을 처리한다.

database에 entry 설정을 하려면, shared storage database queue queue, storage proxy map databaseMap, environment settings object environment, key key, value value, 그리고 boolean ignoreIfPresent가 주어졌을 때, queue에서 다음 단계를 실행한다:

  1. ignoreIfPresent이면:

    1. currentValuequeue, databaseMap, environment, 그리고 key와 함께 database에서 entry 가져오기를 실행한 결과로 둔다.

    2. currentValue가 failure이면 false를 반환한다.

    3. currentValue가 undefined가 아니면 true를 반환한다.

  2. queue, databaseMap, environment, key, 그리고 value와 함께 database에 entry 저장을 실행한 결과를 반환한다.

database에 entry 추가를 하려면, shared storage database queue queue, storage proxy map databaseMap, environment settings object environment, key key, 그리고 value value가 주어졌을 때, queue에서 다음 단계를 실행한다:

  1. currentValuequeue, databaseMap, environment, 그리고 key와 함께 database에서 entry 가져오기를 실행한 결과로 둔다.

  2. currentValue가 failure이면 false를 반환한다.

  3. currentValue가 undefined가 아니면:

    1. list를 새 list로 둔다.

    2. currentValuelistAppend한다.

    3. valuelistAppend한다.

    4. valuelist에 대해 concatenate를 실행한 결과로 설정한다.

  4. queue, databaseMap, environment, key, 그리고 value와 함께 database에 entry 저장을 실행한 결과를 반환한다.

database의 entries 일괄 갱신을 하려면, shared storage database queue queue, storage proxy map databaseMap, environment settings object environment, 그리고 SharedStorageModifierMethod들의 list methods가 주어졌을 때, queue에서 다음 단계를 실행한다:

  1. originalDatabaseMapdatabaseMap으로 둔다.

  2. innerMethodFailed를 false로 둔다.

  3. methods 안의 각 method에 대해:

    1. methodSharedStorageSetMethod이면:

      1. keymethodkey로 둔다.

      2. valuemethodvalue로 둔다.

      3. ignoreIfPresentmethodignore if present로 둔다.

      4. resultqueue, databaseMap, environment, key, value, 그리고 ignoreIfPresent와 함께 database에 entry 설정을 실행한 결과로 둔다.

      5. result가 false이면:

        1. innerMethodFailed를 true로 설정한다.

        2. Break.

    2. 그렇지 않고 methodSharedStorageAppendMethod이면:

      1. keymethodkey로 둔다.

      2. valuemethodvalue로 둔다.

      3. resultqueue, databaseMap, environment, key, 그리고 value와 함께 database에 entry 추가를 실행한 결과로 둔다.

      4. result가 false이면:

        1. innerMethodFailed를 true로 설정한다.

        2. Break.

    3. 그렇지 않고 methodSharedStorageDeleteMethod이면:

      1. keymethodkey로 둔다.

      2. resultqueue, databaseMap, environment, 그리고 key와 함께 database에서 entry 삭제를 실행한 결과로 둔다.

      3. result가 false이면:

        1. innerMethodFailed를 true로 설정한다.

        2. Break.

    4. 그렇지 않으면:

      1. Assert: methodSharedStorageClearMethod이다.

      2. resultqueue, databaseMap, 그리고 environment와 함께 database의 모든 entry 지우기를 실행한 결과로 둔다.

      3. result가 false이면:

        1. innerMethodFailed를 true로 설정한다.

        2. Break.

  4. innerMethodFailed이면:

    1. databaseMaporiginalDatabaseMap으로 설정한다.

    2. false를 반환한다.

  5. true를 반환한다.

이 알고리즘은 단순한 rollback 메커니즘을 사용한다. production 환경에서는 전체 database 복사를 피하는 더 효율적인 기법을 고려한다.

4. Window 인터페이스에 대한 확장

Window 객체는 연결된 SharedStorage 인스턴스 sharedStorage를 가지며, 이는 Shared Storage가 활성화된 경우 Window와 함께 생성되고, 아래의 getter를 가진다.
partial interface Window {
  [SecureContext] readonly attribute SharedStorage? sharedStorage;
};
sharedStorage getter 단계는 다음과 같다:
  1. thisfully active이면, thissharedStorage를 반환한다.

  2. 그렇지 않으면 null을 반환한다.

5. SharedStorageModifierMethod Interface Group

SharedStorageSetMethod, SharedStorageAppendMethod, SharedStorageDeleteMethod, SharedStorageClearMethod 인터페이스는 set(), append(), delete(), clear() modifier 메서드에 대응한다. 이들 모두는 기본 SharedStorageModifierMethod 인터페이스를 상속한다.
[Exposed=(Window,SharedStorageWorklet)]
interface SharedStorageModifierMethod {};

[Exposed=(Window, SharedStorageWorklet)]
interface SharedStorageSetMethod : SharedStorageModifierMethod {
  constructor(DOMString key, DOMString value, optional SharedStorageSetMethodOptions options = {});
};

[Exposed=(Window, SharedStorageWorklet)]
interface SharedStorageAppendMethod : SharedStorageModifierMethod {
  constructor(DOMString key, DOMString value, optional SharedStorageModifierMethodOptions options = {});
};

[Exposed=(Window, SharedStorageWorklet)]
interface SharedStorageDeleteMethod : SharedStorageModifierMethod {
  constructor(DOMString key, optional SharedStorageModifierMethodOptions options = {});
};

[Exposed=(Window, SharedStorageWorklet)]
interface SharedStorageClearMethod : SharedStorageModifierMethod {
  constructor(optional SharedStorageModifierMethodOptions options = {});
};

dictionary SharedStorageModifierMethodOptions {
  DOMString withLock;
};

dictionary SharedStorageSetMethodOptions : SharedStorageModifierMethodOptions {
  boolean ignoreIfPresent;
};

SharedStorageModifierMethod는 다음 연결된 fields를 가진다:

with lock

Null 또는 string. 처음에는 null이다.

SharedStorageSetMethod는 다음 연결된 fields를 가진다:

key

string. 처음에는 비어 있다.

value

string. 처음에는 비어 있다.

ignore if present

boolean. 처음에는 false이다.

SharedStorageAppendMethod는 다음 연결된 fields를 가진다:

key

string. 처음에는 비어 있다.

value

string. 처음에는 비어 있다.

SharedStorageDeleteMethod는 다음 연결된 fields를 가진다:

key

string. 처음에는 비어 있다.

new SharedStorageSetMethod(key, value, options) constructor 단계는 다음과 같다:

  1. globalObjectcurrent realmglobal object로 둔다.

  2. context를 null로 둔다.

  3. globalObjectWindow이면:

    1. contextglobalObjectbrowsing context로 설정한다.

  4. 그렇지 않으면:

    1. contextglobalObjectoutside settingstarget browsing context로 설정한다.

    2. SharedStorage의 연결된 SharedStorageWorkletGlobalScope에 대해 addModule이 완료되었는지 확인을 실행한 결과가 false이면, TypeError를 throw한다.

  5. context가 null이면, TypeError를 throw한다.

  6. contextactive windowassociated documentfully active가 아니면, TypeError를 throw한다.

  7. keylengthmaximum length를 초과하면, TypeError를 throw한다.

  8. valuelengthmaximum length를 초과하면, TypeError를 throw한다.

  9. environmentcontextactive windowrelevant settings object로 둔다.

  10. databaseMapenvironmentenvironmentorigin이 주어졌을 때 shared storage bottle map 얻기를 실행한 결과로 둔다.

  11. databaseMap가 failure이면, TypeError를 throw한다.

  12. thiskeykey로 설정한다.

  13. thisvaluevalue로 설정한다.

  14. thisignore if presentoptions["ignoreIfPresent"]로 설정한다.

  15. options["withLock"]가 exists하면:

    1. options["withLock"]가 U+002D HYPHEN-MINUS (-)로 시작하면, TypeError를 throw한다.

    2. thiswith lockoptions["withLock"]로 설정한다.

new SharedStorageAppendMethod(key, value, options) constructor 단계는 다음과 같다:

  1. globalObjectcurrent realmglobal object로 둔다.

  2. context를 null로 둔다.

  3. globalObjectWindow이면:

    1. contextglobalObjectbrowsing context로 설정한다.

  4. 그렇지 않으면:

    1. contextglobalObjectoutside settingstarget browsing context로 설정한다.

    2. SharedStorage의 연결된 SharedStorageWorkletGlobalScope에 대해 addModule이 완료되었는지 확인을 실행한 결과가 false이면, TypeError를 throw한다.

  5. context가 null이면, TypeError를 throw한다.

  6. contextactive windowassociated documentfully active가 아니면, TypeError를 throw한다.

  7. keylengthmaximum length를 초과하면, TypeError를 throw한다.

  8. valuelengthmaximum length를 초과하면, TypeError를 throw한다.

  9. environmentcontextactive windowrelevant settings object로 둔다.

  10. databaseMapenvironmentenvironmentorigin이 주어졌을 때 shared storage bottle map 얻기를 실행한 결과로 둔다.

  11. databaseMap가 failure이면, TypeError를 throw한다.

  12. thiskeykey로 설정한다.

  13. thisvaluevalue로 설정한다.

  14. options["withLock"]가 exists하면:

    1. options["withLock"]가 U+002D HYPHEN-MINUS (-)로 시작하면, TypeError를 throw한다.

    2. thiswith lockoptions["withLock"]로 설정한다.

new SharedStorageAppendMethod(key, options) constructor 단계는 다음과 같다:

  1. globalObjectcurrent realmglobal object로 둔다.

  2. context를 null로 둔다.

  3. globalObjectWindow이면:

    1. contextglobalObjectbrowsing context로 설정한다.

  4. 그렇지 않으면:

    1. contextglobalObjectoutside settingstarget browsing context로 설정한다.

    2. SharedStorage의 연결된 SharedStorageWorkletGlobalScope에 대해 addModule이 완료되었는지 확인을 실행한 결과가 false이면, TypeError를 throw한다.

  5. context가 null이면, TypeError를 throw한다.

  6. contextactive windowassociated documentfully active가 아니면, TypeError를 throw한다.

  7. keylengthmaximum length를 초과하면, TypeError를 throw한다.

  8. environmentcontextactive windowrelevant settings object로 둔다.

  9. databaseMapenvironmentenvironmentorigin이 주어졌을 때 shared storage bottle map 얻기를 실행한 결과로 둔다.

  10. databaseMap가 failure이면, TypeError를 throw한다.

  11. thiskeykey로 설정한다.

  12. options["withLock"]가 exists하면:

    1. options["withLock"]가 U+002D HYPHEN-MINUS (-)로 시작하면, TypeError를 throw한다.

    2. thiswith lockoptions["withLock"]로 설정한다.

new SharedStorageClearMethod(options) constructor 단계는 다음과 같다:

  1. globalObjectcurrent realmglobal object로 둔다.

  2. context를 null로 둔다.

  3. globalObjectWindow이면:

    1. contextglobalObjectbrowsing context로 설정한다.

  4. 그렇지 않으면:

    1. contextglobalObjectoutside settingstarget browsing context로 설정한다.

    2. SharedStorage의 연결된 SharedStorageWorkletGlobalScope에 대해 addModule이 완료되었는지 확인을 실행한 결과가 false이면, TypeError를 throw한다.

  5. context가 null이면, TypeError를 throw한다.

  6. contextactive windowassociated documentfully active가 아니면, TypeError를 throw한다.

  7. environmentcontextactive windowrelevant settings object로 둔다.

  8. databaseMapenvironmentenvironmentorigin이 주어졌을 때 shared storage bottle map 얻기를 실행한 결과로 둔다.

  9. databaseMap가 failure이면, TypeError를 throw한다.

  10. options["withLock"]가 exists하면:

    1. options["withLock"]가 U+002D HYPHEN-MINUS (-)로 시작하면, TypeError를 throw한다.

    2. thiswith lockoptions["withLock"]로 설정한다.

6. SharedStorage 인터페이스

SharedStorage 인터페이스는 WindowSharedStorageWorklet에 노출된다.

데이터를 설정 및/또는 삭제할 수 있게 하는 메서드들은 WindowSharedStorageWorklet 양쪽에 모두 노출되지만, 그 구현은 해당 environment에 따라 달라질 수 있다. 이를 통해 여러 context에서 Shared Storage의 데이터를 수정할 수 있다.

한편, SharedStorageWorkletGlobalScope 안에서 실행될 operation을 게시하기 위한 메서드들(즉 selectURL()run())과, addModule()을 호출하는 데 사용되는 worklet attribute는 Window에만 노출된다. 이는 이들이 WindowSharedStorageWorklet과 상호작용하는 수단이기 때문이다.

반면, shared storage database에서 데이터를 가져오는 메서드들은 database에서 읽은 데이터의 흐름을 신중하게 제어하기 위해 SharedStorageWorklet에만 노출된다. 유일한 예외는 get()Window에 노출되지만, navigable이 network를 완전히 revoked했는지 결정 알고리즘의 결과가 true인 경우에만 성공한다는 점이다.

Note: navigable이 network를 완전히 revoked했는지 결정 알고리즘은 get()disableUntrustedNetwork() 호출을 성공적으로 resolve한 fenced frames에서만 성공하도록 보장한다.

[Exposed=(Window,SharedStorageWorklet)]
interface SharedStorage {
  Promise<DOMString> get(DOMString key);
  Promise<any> set(DOMString key,
                   DOMString value,
                   optional SharedStorageSetMethodOptions options = {});
  Promise<any> append(DOMString key,
                      DOMString value,
                      optional SharedStorageModifierMethodOptions options = {});
  Promise<any> delete(DOMString key, optional SharedStorageModifierMethodOptions options = {});
  Promise<any> clear(optional SharedStorageModifierMethodOptions options = {});
  Promise<any> batchUpdate(sequence<SharedStorageModifierMethod> methods,
                           optional SharedStorageModifierMethodOptions options = {});

  [Exposed=Window]
  Promise<SharedStorageResponse> selectURL(DOMString name,
                               sequence<SharedStorageUrlWithMetadata> urls,
                               optional SharedStorageRunOperationMethodOptions options = {});

  [Exposed=Window]
  Promise<any> run(DOMString name,
                   optional SharedStorageRunOperationMethodOptions options = {});

  [Exposed=Window]
  Promise<SharedStorageWorklet> createWorklet(USVString moduleURL, optional SharedStorageWorkletOptions options = {});

  [Exposed=Window]
  readonly attribute SharedStorageWorklet worklet;

  [Exposed=SharedStorageWorklet]
  Promise<unsigned long> length();

  [Exposed=SharedStorageWorklet]
  Promise<double> remainingBudget();

  [Exposed=SharedStorageWorklet]
  async iterable<DOMString, DOMString>;
};

dictionary SharedStoragePrivateAggregationConfig {
  USVString aggregationCoordinatorOrigin;
  USVString contextId;
  [EnforceRange] unsigned long long filteringIdMaxBytes;
  [EnforceRange] unsigned long long maxContributions;
};

dictionary SharedStorageRunOperationMethodOptions {
  object data;
  boolean resolveToConfig = false;
  boolean keepAlive = false;
  SharedStoragePrivateAggregationConfig privateAggregationConfig;
  DOMString savedQuery;
};

dictionary SharedStorageWorkletOptions : WorkletOptions {
  USVString dataOrigin = "context-origin";
};

6.1. SharedStorage에서 Operation 메서드 실행

selectURL(name, urls, options) 메서드 단계는 다음과 같다:
  1. sharedStoragethis로 둔다.

  2. sharedStorage.worklet.selectURL(name, urls, options)를 반환한다.

run(name, options) 메서드 단계는 다음과 같다:
  1. sharedStoragethis로 둔다.

  2. sharedStorage.worklet.run(name, options)를 반환한다.

6.2. SharedStorage를 통해 새 worklet 생성

createWorklet(moduleURL, options) 메서드 단계는 다음과 같다:
  1. sharedStorageWorklet를 새 SharedStorageWorklet로 둔다.

  2. options가 "dataOrigin"을 contains하면, sharedStorageWorkletdata originoptions["dataOrigin"]로 설정한다.

  3. addModulePromise를 sharedStorageWorklet.addModule(moduleURL, options)를 호출한 결과로 둔다.

  4. resultPromise를 새 promise로 둔다.

  5. addModulePromisefulfillment 시, resultPromisesharedStorageWorkletresolve한다.

  6. addModulePromiserejection 시, resultPromiseTypeErrorreject한다.

  7. resultPromise를 반환한다.

6.3. BatchUpdate 메서드

batchUpdate(methods, options) 메서드 단계는 다음과 같다:
  1. promise를 새 promise로 둔다.

  2. globalObjectcurrent realmglobal object로 둔다.

  3. context를 null로 둔다.

  4. globalObjectWindow이면:

    1. contextglobalObjectbrowsing context로 설정한다.

  5. 그렇지 않으면:

    1. contextglobalObjectoutside settingstarget browsing context로 설정한다.

    2. SharedStorage의 연결된 SharedStorageWorkletGlobalScope에 대해 addModule이 완료되었는지 확인을 실행한 결과가 false이면, TypeErrorrejected된 promise를 반환한다.

  6. context가 null이면, TypeErrorrejected된 promise를 반환한다.

  7. contextactive windowassociated documentfully active가 아니면, TypeErrorrejected된 promise를 반환한다.

  8. methods 안의 각 method에 대해:

    1. method["withLock"]가 exists하면:

      1. TypeErrorrejected된 promise를 반환한다.

      Note: batchUpdate()는 transactional operation으로 실행된다. 더 세분화된 locking으로 인해 발생할 수 있는 deadlock을 피하기 위해, batchUpdate() 내부의 inner methods는 withLock option을 사용할 수 없다. 이 option을 무시하는 대신, restriction을 강제하고 오용을 방지하기 위해 오류가 throw된다.

  9. environmentcontextactive windowrelevant settings object로 둔다.

  10. databaseMapenvironmentenvironmentorigin이 주어졌을 때 shared storage bottle map 얻기를 실행한 결과로 둔다.

  11. databaseMap가 failure이면, TypeErrorrejected된 promise를 반환한다.

  12. onLockGrantedCallback을 다음 단계를 수행하는 알고리즘으로 둔다:

    1. queue다음 단계를 enqueue한다:

      1. resultqueue, databaseMap, environment, 그리고 methods와 함께 database의 entries 일괄 갱신을 실행한 결과로 둔다.

      2. result가 false이고 globalObjectSharedStorageWorkletGlobalScope이면:

        1. realmglobal object가 주어졌을 때, DOM manipulation task sourceglobal task를 queue하여 promiseTypeErrorreject한다.

        2. 이 단계를 중단한다.

      3. realmglobal object가 주어졌을 때, DOM manipulation task sourceglobal task를 queue하여 promise를 undefined로 resolve한다.

  13. options["withLock"]가 exists하면, environmentorigin, options["withLock"], onLockGrantedCallback이 주어졌을 때 shared storage lock 안에서 callback 처리를 실행한다.

  14. 그렇지 않으면, onLockGrantedCallback을 실행한다.

  15. promise를 반환한다.

6.4. Setter/Deleter 메서드

set(key, value, options) 메서드 단계는 다음과 같다:
  1. promise를 새 promise로 둔다.

  2. globalObjectcurrent realmglobal object로 둔다.

  3. context를 null로 둔다.

  4. globalObjectWindow이면:

    1. contextglobalObjectbrowsing context로 설정한다.

  5. 그렇지 않으면:

    1. contextglobalObjectoutside settingstarget browsing context로 설정한다.

    2. SharedStorage의 연결된 SharedStorageWorkletGlobalScope에 대해 addModule이 완료되었는지 확인을 실행한 결과가 false이면, TypeErrorrejected된 promise를 반환한다.

  6. context가 null이면, TypeErrorrejected된 promise를 반환한다.

  7. contextactive windowassociated documentfully active가 아니면, TypeErrorrejected된 promise를 반환한다.

  8. keylengthmaximum length를 초과하면, TypeErrorrejected된 promise를 반환한다.

  9. valuelengthmaximum length를 초과하면, TypeErrorrejected된 promise를 반환한다.

  10. environmentcontextactive windowrelevant settings object로 둔다.

  11. databaseMapenvironmentenvironmentorigin이 주어졌을 때 shared storage bottle map 얻기를 실행한 결과로 둔다.

  12. databaseMap가 failure이면, TypeErrorrejected된 promise를 반환한다.

  13. queuecontext의 연결된 databaseshared storage database queue로 둔다.

  14. realmcurrent realm으로 둔다.

  15. onLockGrantedCallback을 다음 단계를 수행하는 알고리즘으로 둔다:

    1. queue다음 단계를 enqueue한다:

      1. resultqueue, databaseMap, environment, key, value, 그리고 options["ignoreIfPresent"]와 함께 database에 entry 설정을 실행한 결과로 둔다.

      2. result가 false이고 globalObjectSharedStorageWorkletGlobalScope이면:

        1. realmglobal object가 주어졌을 때 DOM manipulation task sourceglobal task를 queue하여 promiseTypeErrorreject한다.

        2. 이 단계를 중단한다.

      3. realmglobal object가 주어졌을 때 DOM manipulation task sourceglobal task를 queue하여 promise를 undefined로 resolve한다.

  16. options["withLock"]가 exists하면:

    1. options["withLock"]가 U+002D HYPHEN-MINUS (-)로 시작하면, TypeErrorrejected된 promise를 반환한다.

    2. environmentorigin, options["withLock"], 그리고 onLockGrantedCallback이 주어졌을 때 shared storage lock 안에서 callback 처리를 실행한다.

  17. 그렇지 않으면, onLockGrantedCallback을 실행한다.

  18. promise를 반환한다.

append(key, value, options) 메서드 단계는 다음과 같다:
  1. promise를 새 promise로 둔다.

  2. globalObjectcurrent realmglobal object로 둔다.

  3. context를 null로 둔다.

  4. globalObjectWindow이면:

    1. contextglobalObjectbrowsing context로 설정한다.

  5. 그렇지 않으면:

    1. contextglobalObjectoutside settingstarget browsing context로 설정한다.

    2. SharedStorage의 연결된 SharedStorageWorkletGlobalScope에 대해 addModule이 완료되었는지 확인을 실행한 결과가 false이면, TypeErrorrejected된 promise를 반환한다.

  6. context가 null이면, TypeErrorrejected된 promise를 반환한다.

  7. contextactive windowassociated documentfully active가 아니면, TypeErrorrejected된 promise를 반환한다.

  8. keylengthmaximum length를 초과하면, TypeErrorrejected된 promise를 반환한다.

  9. valuelengthmaximum length를 초과하면, TypeErrorrejected된 promise를 반환한다.

  10. environmentcontextactive windowrelevant settings object로 둔다.

  11. databaseMapenvironmentenvironmentorigin이 주어졌을 때 shared storage bottle map 얻기를 실행한 결과로 둔다.

  12. databaseMap가 failure이면, TypeErrorrejected된 promise를 반환한다.

  13. queuecontext의 연결된 databaseshared storage database queue로 둔다.

  14. realmcurrent realm으로 둔다.

  15. onLockGrantedCallback을 다음 단계를 수행하는 알고리즘으로 둔다:

    1. queue다음 단계를 enqueue한다:

      1. resultqueue, databaseMap, environment, key, 그리고 value와 함께 database에 entry 추가를 실행한 결과로 둔다.

      2. result가 false이고 globalObjectSharedStorageWorkletGlobalScope이면:

        1. realmglobal object가 주어졌을 때 DOM manipulation task sourceglobal task를 queue하여 promiseTypeErrorreject한다.

        2. 이 단계를 중단한다.

      3. realmglobal object가 주어졌을 때 DOM manipulation task sourceglobal task를 queue하여 promise를 undefined로 resolve한다.

  16. options["withLock"]가 exists하면:

    1. options["withLock"]가 U+002D HYPHEN-MINUS (-)로 시작하면, TypeErrorrejected된 promise를 반환한다.

    2. environmentorigin, options["withLock"], 그리고 onLockGrantedCallback이 주어졌을 때 shared storage lock 안에서 callback 처리를 실행한다.

  17. 그렇지 않으면, onLockGrantedCallback을 실행한다.

  18. promise를 반환한다.

delete(key, options) 메서드 단계는 다음과 같다:
  1. promise를 새 promise로 둔다.

  2. globalObjectcurrent realmglobal object로 둔다.

  3. context를 null로 둔다.

  4. globalObjectWindow이면:

    1. contextglobalObjectbrowsing context로 설정한다.

  5. 그렇지 않으면:

    1. contextglobalObjectoutside settingstarget browsing context로 설정한다.

    2. SharedStorage의 연결된 SharedStorageWorkletGlobalScope에 대해 addModule이 완료되었는지 확인을 실행한 결과가 false이면, TypeErrorrejected된 promise를 반환한다.

  6. context가 null이면, TypeErrorrejected된 promise를 반환한다.

  7. contextactive windowassociated documentfully active가 아니면, TypeErrorrejected된 promise를 반환한다.

  8. keylengthmaximum length를 초과하면, TypeErrorrejected된 promise를 반환한다.

  9. environmentcontextactive windowrelevant settings object로 둔다.

  10. databaseMapenvironmentenvironmentorigin이 주어졌을 때 shared storage bottle map 얻기를 실행한 결과로 둔다.

  11. databaseMap가 failure이면, TypeErrorrejected된 promise를 반환한다.

  12. queuecontext의 연결된 databaseshared storage database queue로 둔다.

  13. realmcurrent realm으로 둔다.

  14. onLockGrantedCallback을 다음 단계를 수행하는 알고리즘으로 둔다:

    1. queue다음 단계를 enqueue한다:

      1. resultqueue, databaseMap, 그리고 key와 함께 database에서 entry 삭제를 실행한 결과로 둔다.

      2. result가 false이고 globalObjectSharedStorageWorkletGlobalScope이면:

        1. realmglobal object가 주어졌을 때 DOM manipulation task sourceglobal task를 queue하여 promiseTypeErrorreject한다.

        2. 이 단계를 중단한다.

      3. realmglobal object가 주어졌을 때 DOM manipulation task sourceglobal task를 queue하여 promise를 undefined로 resolve한다.

  15. options["withLock"]가 exists하면:

    1. options["withLock"]가 U+002D HYPHEN-MINUS (-)로 시작하면, TypeErrorrejected된 promise를 반환한다.

    2. environmentorigin, options["withLock"], 그리고 onLockGrantedCallback이 주어졌을 때 shared storage lock 안에서 callback 처리를 실행한다.

  16. 그렇지 않으면, onLockGrantedCallback을 실행한다.

  17. promise를 반환한다.

clear(options) 메서드 단계는 다음과 같다:
  1. promise를 새 promise로 둔다.

  2. globalObjectcurrent realmglobal object로 둔다.

  3. context를 null로 둔다.

  4. globalObjectWindow이면:

    1. contextglobalObjectbrowsing context로 설정한다.

  5. 그렇지 않으면:

    1. contextglobalObjectoutside settingstarget browsing context로 설정한다.

    2. SharedStorage의 연결된 SharedStorageWorkletGlobalScope에 대해 addModule이 완료되었는지 확인을 실행한 결과가 false이면, TypeErrorrejected된 promise를 반환한다.

  6. context가 null이면, TypeErrorrejected된 promise를 반환한다.

  7. contextactive windowassociated documentfully active가 아니면, TypeErrorrejected된 promise를 반환한다.

  8. environmentcontextactive windowrelevant settings object로 둔다.

  9. databaseMapenvironmentenvironmentorigin이 주어졌을 때 shared storage bottle map 얻기를 실행한 결과로 둔다.

  10. databaseMap가 failure이면, TypeErrorrejected된 promise를 반환한다.

  11. queuecontext의 연결된 databaseshared storage database queue로 둔다.

  12. realmcurrent realm으로 둔다.

  13. onLockGrantedCallback을 다음 단계를 수행하는 알고리즘으로 둔다:

    1. queue다음 단계를 enqueue한다:

      1. resultqueuedatabaseMap와 함께 database의 모든 entry 지우기를 실행한 결과로 둔다.

      2. result가 false이고 globalObjectSharedStorageWorkletGlobalScope이면:

        1. realmglobal object가 주어졌을 때 DOM manipulation task sourceglobal task를 queue하여 promiseTypeErrorreject한다.

        2. 이 단계를 중단한다.

      3. realmglobal object가 주어졌을 때 DOM manipulation task sourceglobal task를 queue하여 promise를 undefined로 resolve한다.

  14. options["withLock"]가 exists하면:

    1. options["withLock"]가 U+002D HYPHEN-MINUS (-)로 시작하면, TypeErrorrejected된 promise를 반환한다.

    2. environmentorigin, options["withLock"], 그리고 onLockGrantedCallback이 주어졌을 때 shared storage lock 안에서 callback 처리를 실행한다.

  15. 그렇지 않으면, onLockGrantedCallback을 실행한다.

  16. promise를 반환한다.

6.5. Getter 메서드

get(key) 메서드 단계는 다음과 같다:
  1. promise를 새 promise로 둔다.

  2. globalObjectcurrent realmglobal object로 둔다.

  3. context를 null로 둔다.

  4. environment를 null로 둔다.

  5. globalObjectWindow이면:

    1. contextglobalObjectbrowsing context로 설정한다.

    2. context가 null이면, TypeErrorrejected된 promise를 반환한다.

    3. environmentcontextactive windowrelevant settings object로 설정한다.

    4. allowedInOpaqueOriginContext를 false로 둔다.

    5. environment, environmentorigin, 그리고 allowedInOpaqueOriginContext가 주어졌을 때 context에 의해 shared storage가 허용되는지 결정을 실행한 결과가 false이면, TypeErrorrejected된 promise를 반환한다.

    6. environmentenvironmentorigin이 주어졌을 때 사용자 환경설정이 shared storage에 대한 접근을 허용하는지 확인을 실행한 결과가 false이면, OperationErrorrejected된 promise를 반환한다.

    7. documentcontextactive document로 둔다.

    8. "fenced-unpartitioned-storage-read", document, 그리고 environmentorigin에 대해 Is feature enabled in document for origin?을 실행한 결과가 false이면, OperationErrorrejected된 promise를 반환한다.

    9. navigabledocumentnode navigable로 둔다.

    10. navigable이 주어졌을 때 navigable이 network를 완전히 revoked했는지 결정을 실행한 결과가 false이면, OperationErrorrejected된 promise를 반환한다.

  6. 그렇지 않으면: 1 SharedStorage의 연결된 SharedStorageWorkletGlobalScope에 대해 addModule이 완료되었는지 확인을 실행한 결과가 false이면, TypeErrorrejected된 promise를 반환한다.

    1. contextSharedStorageSharedStorageWorkletGlobalScopeoutside settingstarget browsing context로 설정한다.

    2. context가 null이면, TypeErrorrejected된 promise를 반환한다.

    3. environmentcontextactive windowrelevant settings object로 설정한다.

  7. keylengthmaximum length를 초과하면, TypeErrorrejected된 promise를 반환한다.

  8. contextactive windowassociated documentfully active가 아니면, TypeErrorrejected된 promise를 반환한다.

  9. realmcurrent realm으로 둔다.

  10. databaseMapenvironmentrealmsettings objectorigin이 주어졌을 때 shared storage bottle map 얻기를 실행한 결과로 둔다.

  11. databaseMap가 failure이면, TypeErrorrejected된 promise를 반환한다.

  12. queuecontext의 연결된 databaseshared storage database queue로 둔다.

  13. queue다음 단계를 enqueue한다:

    1. valuequeue, databaseMap, environment, 그리고 key와 함께 database에서 entry 가져오기를 실행한 결과로 둔다.

    2. value가 failure이면, realmglobal object가 주어졌을 때 DOM manipulation task sourceglobal task를 queue하여 promiseTypeErrorreject한다.

    3. 그렇지 않고 value가 undefined이면, realmglobal object가 주어졌을 때 DOM manipulation task sourceglobal task를 queue하여 promise를 undefined로 resolve한다.

    4. 그렇지 않으면, realmglobal object가 주어졌을 때 DOM manipulation task sourceglobal task를 queue하여 promisevalueresolve한다.

  14. promise를 반환한다.

length() 메서드 단계는 다음과 같다:
  1. promise를 새 promise로 둔다.

  2. SharedStorage의 연결된 SharedStorageWorkletGlobalScope에 대해 addModule이 완료되었는지 확인을 실행한 결과가 false이면, TypeErrorrejected된 promise를 반환한다.

  3. contextSharedStorageSharedStorageWorkletGlobalScopeoutside settingstarget browsing context로 둔다.

  4. context가 null이면, TypeErrorrejected된 promise를 반환한다.

  5. contextactive windowassociated documentfully active가 아니면, TypeErrorrejected된 promise를 반환한다.

  6. environmentcontextactive windowrelevant settings object로 둔다.

  7. realmcurrent realm으로 둔다.

  8. databaseMapenvironmentrealmsettings objectorigin이 주어졌을 때 shared storage bottle map 얻기를 실행한 결과로 둔다.

  9. databaseMap가 failure이면, TypeErrorrejected된 promise를 반환한다.

  10. queuecontext의 연결된 databaseshared storage database queue로 둔다.

  11. queue다음 단계를 enqueue한다:

    1. numEntriesqueueenvironment와 함께 database의 entry 개수 세기를 실행한 결과로 둔다.

    2. numEntries가 failure이면, realmglobal object가 주어졌을 때 DOM manipulation task sourceglobal task를 queue하여 promiseTypeErrorreject한다.

    3. 그렇지 않으면, realmglobal object가 주어졌을 때 DOM manipulation task sourceglobal task를 queue하여 promisenumEntriesresolve한다.

  12. promise를 반환한다.

remainingBudget() 메서드 단계는 다음과 같다:
  1. promise를 새 promise로 둔다.

  2. SharedStorage의 연결된 SharedStorageWorkletGlobalScope에 대해 addModule이 완료되었는지 확인을 실행한 결과가 false이면, TypeErrorrejected된 promise를 반환한다.

  3. contextSharedStorageSharedStorageWorkletGlobalScopeoutside settingstarget browsing context로 둔다.

  4. context가 null이면, TypeErrorrejected된 promise를 반환한다.

  5. contextactive windowassociated documentfully active가 아니면, TypeErrorrejected된 promise를 반환한다.

  6. environmentcontextactive windowrelevant settings object로 둔다.

  7. realmcurrent realm으로 둔다.

  8. allowedInOpaqueOriginContext를 false로 둔다.

  9. environment, realmsettings objectorigin, 그리고 allowedInOpaqueOriginContext가 주어졌을 때 context에 의해 shared storage가 허용되는지 결정을 실행한 결과가 false이면, TypeErrorrejected된 promise를 반환한다.

  10. environmentrealmsettings objectorigin이 주어졌을 때 사용자 환경설정이 shared storage에 대한 접근을 허용하는지 확인을 실행한 결과가 false이면, TypeErrorrejected된 promise를 반환한다.

  11. siterealmsettings objectorigin과 함께 site 얻기를 실행한 결과로 둔다.

  12. Assert: siteopaque origin이 아니다.

  13. queuecontext의 연결된 databaseshared storage database queue로 둔다.

  14. queue다음 단계를 enqueue한다:

    1. remainingBudgetsite와 함께 남은 navigation budget 결정을 실행한 결과로 둔다.

    2. realmglobal object가 주어졌을 때 DOM manipulation task sourceglobal task를 queue하여 promiseremainingBudget으로 resolve하도록 Resolve한다.

  15. promise를 반환한다.

6.6. Iteration

SharedStorage async iterator 인스턴스는 entriesqueuepending entries를 가지며, 처음에는 empty이다.

SharedStorage async iterator 인스턴스는 또한 boolean error를 가지며, 처음에는 false이다.

아래에 정의된 asynchronous iterator initialization stepsget the next iteration result 알고리즘은 Web IDL Standard에서 asynchronous iterator initialization stepsget the next iteration result 알고리즘이라고 부르는 것에 대응한다.

SharedStorage async iterator iterator에 대한 asynchronous iterator initialization steps는 다음과 같다:
  1. promise를 새 promise로 둔다.

  2. SharedStorage의 연결된 SharedStorageWorkletGlobalScope에 대해 addModule이 완료되었는지 확인을 실행한 결과가 false이면, TypeErrorrejected된 promise를 반환한다.

  3. contextSharedStorageSharedStorageWorkletGlobalScopeoutside settingstarget browsing context로 둔다.

  4. context가 null이면, TypeErrorrejected된 promise를 반환한다.

  5. contextactive windowassociated documentfully active가 아니면, TypeErrorrejected된 promise를 반환한다.

  6. environmentcontextactive windowrelevant settings object로 둔다.

  7. realmcurrent realm으로 둔다.

  8. databaseMapenvironmentrealmsettings objectorigin이 주어졌을 때 shared storage bottle map 얻기를 실행한 결과로 둔다.

  9. databaseMap가 failure이면, TypeErrorrejected된 promise를 반환한다.

  10. queuecontext의 연결된 databaseshared storage database queue로 둔다.

  11. queue다음 단계를 enqueue한다:

    1. entriesqueueenvironment와 함께 database에서 모든 entry 가져오기를 실행한 결과로 둔다.

    2. entries가 failure이면, realmglobal object가 주어졌을 때 DOM manipulation task sourceglobal task를 queue하여 promiseTypeErrorreject한다.

    3. 그렇지 않으면, realmglobal object가 주어졌을 때 DOM manipulation task sourceglobal task를 queue하여 promiseentriesresolve한다.

  12. promisefulfillment 시, 다음을 실행한다:

    1. promiseEntriespromise의 값으로 둔다.

    2. promiseEntries 안의 각 entry entry에 대해 For each, entryiteratorpending entriesenqueue한다.

  13. promiserejection 시, iteratorerror를 true로 설정한다.

SharedStorageasync iterator iterator가 주어졌을 때 다음 iteration 결과 가져오기를 하려면, 다음 단계를 실행한다:
  1. promise를 새 promise로 둔다.

  2. 다음 단계를 enqueue한다:

    1. iteratorerror가 true이면, TypeErrorrejected된 promise를 반환한다.

    2. iteratorpending entriesempty이면:

      1. 객체 doneObject를 생성한다.

      2. realmglobal object가 주어졌을 때 DOM manipulation task sourceglobal task를 queue하여 promisedoneObjectresolve한다.

      3. 이 단계를 중단한다.

    3. 그렇지 않으면, entryiteratorpending entries에서 dequeueing한 결과로 둔다.

    4. realmglobal object가 주어졌을 때 DOM manipulation task sourceglobal task를 queue하여 promiseentryresolve한다.

  3. promise를 반환한다.

7. HTTP Response Header를 통한 Operation 트리거

setter 및 deleter operation(예: set(), append(), delete(), clear())은 Window 또는 SharedStorageWorkletGlobalScope에 대한 위 API들을 통해 시작할 수 있지만, setter/deleter operation은 대안적으로 HTTP response header를 통해 트리거될 수 있다.

이를 위해 HTML 및 Fetch 명세에 monkey patch가 필요하다.

8. HTML Monkey Patch

8.1. sharedStorageWritablesharedstoragewritable Attribute

다음 interface mixin을 정의하고, 이를 HTMLIFrameElementHTMLImageElement에 대한 IDL interfaces에 포함한다:

interface mixin HTMLSharedStorageWritableElementUtils {
  [CEReactions, SecureContext] attribute boolean sharedStorageWritable;
};

HTMLIFrameElement includes HTMLSharedStorageWritableElementUtils;
HTMLImageElement includes HTMLSharedStorageWritableElementUtils;

다음 boolean content attributes를 추가한다:

iframe

sharedstoragewritable

img

sharedstoragewritable

IDL attribute sharedStorageWritable은 같은 이름의 해당 content attributereflect해야 한다.

8.2. HTML Algorithm 수정

8.2.1. Update the image data Algorithm에 대한 수정

update the image data를 다음과 같이 수정한다:

다음 단계 뒤에

requestpriority를 현재 상태로 설정한다...

다음 단계를 추가한다

  1. element에 sharedstoragewritable attribute가 있으면, requestshared storage writable을 true로 설정한다.

8.2.2. Create navigation params by fetching Algorithm에 대한 수정

create navigation params by fetching을 다음과 같이 수정한다:

다음 단계 뒤에

request를 ...를 가진 새 request로 둔다

다음 단계를 추가한다

  1. navigablecontaineriframe element이고, 그것이 sharedstoragewritable content attribute를 가지면, requestshared storage writable을 true로 설정한다.

9. Fetch Monkey Patch

9.1. sharedStorageWritable Key

request는 연결된 boolean shared storage writable을 가진다. 달리 명시되지 않는 한 false이다.

RequestInit dictionary는 sharedStorageWritable key를 포함한다:

partial dictionary RequestInit {
  boolean sharedStorageWritable;
};

9.2. Fetch Algorithm 수정

9.2.1. Request Constructor Algorithm에 대한 수정

new Request(input, init) constructor를 다음과 같이 수정한다:

다음 단계 앞에

this의 requestrequest로 설정한다.

다음 단계를 추가한다

  1. init["sharedStorageWritable"]가 exists하면, requestshared storage writable을 그것으로 설정한다.

9.2.2. HTTP network or cache fetch Algorithm에 대한 수정

HTTP network or cache fetch 알고리즘을 다음과 같이 수정한다:

다음 단계 앞에

HTTP에 따라 httpRequestheader list를 수정한다. ...

다음 단계를 추가한다

  1. httpRequest에 대해 Sec-Shared-Storage-Writable request header를 append하거나 수정한다.

9.2.3. HTTP fetch Algorithm에 대한 수정

HTTP fetch 알고리즘을 다음과 같이 수정한다:

다음 단계 앞에

internalResponsestatusredirect status이면: ...

다음 단계들을 추가한다

  1. requestdestination이 "sharedstorageworklet"이면:

    1. dataOriginValuerequestheader list에서 `Sec-Shared-Storage-Data-Origin`을 getting한 결과로 둔다.

    2. dataOriginValue가 null이 아니면:

      1. dataOriginUrldataOriginValueURL parser를 실행한 결과로 둔다.

      2. Assert: dataOriginUrl은 failure가 아니다.

      3. Assert: requestorigin은 "client"가 아니다.

      4. Assert: requestoriginrequestURLoriginsame origin이 아니다.

      5. allowed를 true로 둔다.

      6. dataOriginUrloriginrequestURLoriginsame origin이면:

        1. responseHeadersinternalResponseheader list로 둔다.

        2. allowed를 `Shared-Storage-Cross-Origin-Worklet-Allowed`, "item", 그리고 responseHeaders가 input으로 주어졌을 때 structured field value 가져오기 알고리즘을 실행한 결과로 둔다.

      7. allowed가 false이면, network error를 반환한다.

  2. Shared-Storage-Write response 처리response internalResponserequest request가 input으로 주어졌을 때 실행한다.

9.3. Shared Storage HTTP Header

9.3.1. `Sec-Shared-Storage-Data-Origin` Request Header

이 명세는 Sec-Shared-Storage-Data-Origin HTTP request header를 정의한다.

`Sec-Shared-Storage-Data-Origin` request header는 그 valuestring이다.

`Sec-Shared-Storage-Data-Origin`이 fetch a worklet/module worker script graph 알고리즘 동안 전송될 때, 그 value는 worklet의 shared storage data를 소유하는 직렬화된 origin으로 설정된다.

9.3.2. `Shared-Storage-Cross-Origin-Worklet-Allowed` Response Header

이 명세는 Shared-Storage-Cross-Origin-Worklet-Allowed HTTP response header를 정의한다.

`Shared-Storage-Cross-Origin-Worklet-Allowed` response header는 그 value가 Boolean이어야 하는 Structured Header이다.

response가 `Shared-Storage-Cross-Origin-Worklet-Allowed`를 true value로 가질 때, worklet script의 server는 cross-origin site가 worklet script의 origin의 shared storage data를 사용하여 worklet을 생성하도록 허가한 것이다.

9.3.3. `Sec-Shared-Storage-Writable` Request Header

이 명세는 Sec-Shared-Storage-Writable HTTP request header를 정의한다.

`Sec-Shared-Storage-Writable` request header는 그 value가 Boolean이어야 하는 Structured Header이다.

request가 `Sec-Shared-Storage-Writable`을 true로 설정하면 그 responseshared storage에 쓸 수 있다.

9.3.4. `Shared-Storage-Write` Response Header

이 명세는 Shared-Storage-Write HTTP response header를 정의한다.

`Shared-Storage-Write` response header는 그 value가 List여야 하는 Structured Header이다. 다음 list member들이 정의된다. 동일한 문자 sequence를 보유하는 TokensStrings는 동등한 것으로 간주된다. HTTP header를 통해 non-ASCII Unicode key 및 value를 쓰고 삭제하는 기능을 제공하기 위해, UTF-8 encoded byte를 나타내는 Byte Sequences도 허용된다.

알 수 없는 list member들, 즉 string도 아니고 Byte Sequences도 아닌 type들을 포함한 member들은 건너뛰며, 나머지 list는 그것들이 없는 것처럼 처리된다. 필요한 parameters가 없거나 그 parameters가 예상하지 못한 type을 가지는 경우에도 member들은 건너뛴다.

Note: Unicode key 및 value를 수용하기 위해 Byte Sequences를 허용한다. 모든 Byte SequenceUTF-8 encoded된 것으로 간주되며, 그렇지 않으면 parse에 실패한다.

예제를 추가한다.

9.4. Shared Storage Fetch 관련 알고리즘

request request가 주어졌을 때, request가 현재 shared storage를 사용할 수 있는지 결정하려면, 다음 단계를 수행한다:
  1. windowrequestwindow로 둔다.

  2. window가 그 global objectWindowenvironment settings object가 아니면, false를 반환한다.

  3. allowedInOpaqueOriginContext를 true로 둔다.

  4. window, requestcurrent URLorigin, 그리고 allowedInOpaqueOriginContext가 주어졌을 때 context에 의해 shared storage가 허용되는지 결정을 실행한 결과가 false이면, false를 반환한다.

  5. windowrequestcurrent URLorigin이 주어졌을 때 사용자 환경설정이 shared storage에 대한 접근을 허용하는지 확인을 실행한 결과가 false이면, false를 반환한다.

request가 현재 shared storage를 사용할 수 있는지 결정 알고리즘은 https://github.com/w3c/webappsec-permissions-policy/pull/499에 설명된 대로 "opt-in features"를 고려해야 한다.

request request가 주어졌을 때, Sec-Shared-Storage-Writable request header를 append하거나 수정하려면, 다음 단계를 수행한다:
  1. requestshared storage writable이 true가 아니면 반환한다.

    Note: redirect에서는 requestshared storage writable이 true일 수 있지만, redirect에는 shared storage를 사용할 권한이 없어 request에 대해 request가 현재 shared storage를 사용할 수 있는지 결정을 실행한 결과가 false가 될 수 있다.

  2. request에 대해 request가 현재 shared storage를 사용할 수 있는지 결정을 실행한 결과가 false이면, requestheader list에서 `Sec-Shared-Storage-Writable`를 delete한다.

  3. 그렇지 않으면, requestheader list에서 (`Sec-Shared-Storage-Writable`, true)를 structured field value 설정한다.

response responserequest request가 주어졌을 때, Shared-Storage-Write response 처리를 하려면, 다음 단계를 수행한다:
  1. sharedStorageWritable을 `Sec-Shared-Storage-Writable`, "item", 그리고 requestheader list가 input으로 주어졌을 때 structured field value 가져오기 알고리즘을 실행한 결과로 둔다.

  2. sharedStorageWritable이 null이거나, sharedStorageWritableBoolean이 아니거나, sharedStorageWritable의 value가 false이면, 반환한다.

  3. windowrequestwindow로 둔다.

  4. Assert: window는 그 global objectWindowenvironment settings object이다.

  5. sharedStoragewindowglobal objectsharedStorage로 둔다.

  6. sharedStorage가 null이면 반환한다.

  7. listresponseheader list로 둔다.

  8. operationsToParse를 `Shared-Storage-Write`, "list", 그리고 list가 input으로 주어졌을 때 structured field value 가져오기 알고리즘을 실행한 결과로 둔다.

  9. operationsToParse가 null 또는 empty이면 반환한다.

  10. methods를 빈 list로 둔다.

  11. batchWithLock을 null로 둔다.

  12. operationsToParse 안의 각 tuple (item, parameters)에 대해, 다음 단계를 수행한다:

    1. itemInner List이면, continue한다.

    2. Assert: itemBare Item이다.

    3. methodOrOptionsStringitem에 대해 string value 가져오기를 실행한 결과로 둔다.

    4. methodOrOptionsString이 failure이면, continue한다.

    5. methodOrOptionsString에 대해 switch한다:

      methodOrOptionsString이 "clear"이면:
      다음 단계를 수행한다:
      1. options를 새 SharedStorageModifierMethodOptions로 둔다.

      2. withLockparameters 및 "with_lock"과 함께 string-like parameter value 얻기를 실행한 결과로 둔다.

      3. withLock이 null이 아니고 U+002D HYPHEN-MINUS (-)로 시작하지 않으면, options["withLock"]를 withLock으로 set한다.

      4. method를 new SharedStorageClearMethod(options)로 둔다.

      5. exception이 throw되었으면, continue한다.

      6. methodmethodsAppend한다.

      7. Continue한다.

      methodOrOptionsString이 "delete"이면:
      다음 단계를 수행한다:
      1. keyparameters 및 "key"와 함께 string-like parameter value 얻기를 실행한 결과로 둔다.

      2. key가 null이면, continue한다.

      3. options를 새 SharedStorageModifierMethodOptions로 둔다.

      4. withLockparameters 및 "with_lock"와 함께 string-like parameter value 얻기를 실행한 결과로 둔다.

      5. withLock이 null이 아니고 U+002D HYPHEN-MINUS (-)로 시작하지 않으면, options["withLock"]를 withLock으로 set한다.

      6. method를 new SharedStorageDeleteMethod(key, options)로 둔다.

      7. exception이 throw되었으면, continue한다.

      8. methodmethodsAppend한다.

      9. Continue한다.

      methodOrOptionsString이 "append"이면:
      다음 단계를 수행한다:
      1. keyparameters 및 "key"와 함께 string-like parameter value 얻기를 실행한 결과로 둔다.

      2. key가 null이면, continue한다.

      3. valueparameters 및 "value"와 함께 string-like parameter value 얻기를 실행한 결과로 둔다.

      4. value가 null이면, continue한다.

      5. options를 새 SharedStorageModifierMethodOptions로 둔다.

      6. withLockparameters 및 "with_lock"와 함께 string-like parameter value 얻기를 실행한 결과로 둔다.

      7. withLock이 null이 아니고 U+002D HYPHEN-MINUS (-)로 시작하지 않으면, options["withLock"]를 withLock으로 set한다.

      8. method를 new SharedStorageAppendMethod(key, value, options)로 둔다.

      9. exception이 throw되었으면, continue한다.

      10. methodmethodsAppend한다.

      11. Continue한다.

      methodOrOptionsString이 "set"이면:
      다음 단계를 수행한다:
      1. keyparameters 및 "key"와 함께 string-like parameter value 얻기를 실행한 결과로 둔다.

      2. key가 null이면, continue한다.

      3. valueparameters 및 "value"와 함께 string-like parameter value 얻기를 실행한 결과로 둔다.

      4. value가 null이면, continue한다.

      5. options를 새 SharedStorageSetMethodOptions로 둔다.

      6. parameters 및 "ignore_if_present"와 함께 boolean parameter value 얻기를 실행한 결과가 true이면, options["ignoreIfPresent"]를 true로 set한다.

      7. withLockparameters 및 "with_lock"와 함께 string-like parameter value 얻기를 실행한 결과로 둔다.

      8. withLock이 null이 아니고 U+002D HYPHEN-MINUS (-)로 시작하지 않으면, options["withLock"]를 withLock으로 set한다.

      9. method를 new SharedStorageSetMethod(key, value, options)로 둔다.

      10. exception이 throw되었으면, continue한다.

      11. methodmethodsAppend한다.

      12. Continue한다.

      methodOrOptionsString이 "options"이면:
      다음 단계를 수행한다:
      1. batchWithLockparameters 및 "with_lock"와 함께 string-like parameter value 얻기를 실행한 결과로 설정한다.

      2. Continue한다.

      methodOrOptionsString이 그 밖의 것이면:
      Continue한다.
  13. batchOptions를 새 SharedStorageModifierMethodOptions로 둔다.

  14. batchWithLock이 null이 아니고 batchWithLock이 U+002D HYPHEN-MINUS (-)로 시작하지 않으면, batchOptions["withLock"]를 batchWithLock으로 설정한다.

  15. sharedStorage.batchUpdate(methods, batchOptions)를 실행한다.

Bare Item item에 대해 string-like인지 확인하려면, 다음을 수행한다:
  1. itemString, Token, 또는 Byte Sequence이면, true를 반환한다.

  2. 그렇지 않으면 false를 반환한다.

Bare Item item에 대해 string value 가져오기를 하려면, 다음을 수행한다:
  1. item에 대해 string-like인지 확인을 실행한 결과가 false이면, failure를 반환한다.

  2. item의 type에 대해 switch한다:

    itemToken이면:
    itemString이면:
    다음 단계를 수행한다:
    1. Assert: itemASCII string이다.

    2. item을 반환한다.

    itemByte Sequence이면:
    다음 단계를 수행한다:
    1. fromUTF8item에 대해 UTF-8 decode를 실행한 결과로 둔다.

    2. fromUTF8이 error이면, null을 반환한다.

    3. fromUTF8을 반환한다.

parameters map parametersToken paramKey가 주어졌을 때, string-like parameter value 얻기를 하려면, 다음 단계를 수행한다:
  1. parametersparamKeycontain하지 않으면 null을 반환한다.

  2. parameters[paramKey]에 대해 string-like인지 확인의 결과가 false이면, null을 반환한다.

  3. parameters[paramKey]에 대해 string value 가져오기를 실행한 결과를 반환한다.

parameters map parametersToken paramKey가 주어졌을 때, boolean parameter value 얻기를 하려면, 다음 단계를 수행한다:
  1. parametersparamKeycontain하지 않으면 null을 반환한다.

  2. parameters[paramKey]가 Boolean이 아니면, null을 반환한다.

  3. parameters[paramKey]를 반환한다.

10. Web Locks 통합

10.1. User Agent 연결 상태

shared storage lock managers maporigins에서 lock managers로의 map이다. 처음에는 비어 있다.

user agent는 연결된 shared storage lock managers map을 가진다.

Note: data partitioning과 유사하게, shared storage는 Storage Buckets API와 독립적인 자체 lock management scope를 가진다. 이러한 web locks는 기존 legacy Web Locks API를 통해 Window 또는 Worker에서 생성된 web locks와 상호작용하지 않는다.

10.2. SharedStorageWorkletNavigator interface

[
  Exposed=SharedStorageWorklet
] interface SharedStorageWorkletNavigator {};

10.3. Web Locks IDLs Monkey Patch

NavigatorLocks mixin을 SharedStorageWorkletNavigator에 포함한다(즉, SharedStorageWorkletNavigatorLockManager 인스턴스를 포함하게 한다):

SharedStorageWorkletNavigator includes NavigatorLocks;

LockManagerLock은 SharedStorageWorklet에도 추가로 노출된다:

[SecureContext, Exposed=(Window,Worker,SharedStorageWorklet)]
interface LockManager {};
[SecureContext, Exposed=(Window,Worker,SharedStorageWorklet)]
interface Lock {};

10.4. lock manager의 description에 대한 Monkey Patch

lock manager를 정의하는 paragraph 끝에 다음 문장을 추가한다: "Additionally, each user agent includes one shared storage lock managers map for Web Locks API’s integration with the Shared Storage API."

10.5. locks getter steps에 대한 Monkey Patch

locks getter steps는 다음 단계 집합으로 갱신되어야 한다:

  1. globalObjectcurrent realmglobal object로 둔다.

  2. globalObjectSharedStorageWorkletGlobalScope이면:

    1. globalObjectaddModule success가 false이면, TypeError를 throw한다.

  3. thisrelevant settings objectLockManager object를 반환한다

10.6. "obtain a lock manager" algorithm에 대한 Monkey Patch

obtain a lock manager 알고리즘 앞에 다음 단계를 prepend해야 한다:

  1. current realmglobal objectSharedStorageWorkletGlobalScope이면:

    1. workletDataOriginenvironmentorigin으로 둔다.

    2. shared storage lock managers map[workletDataOrigin]를 반환한다.

10.7. "Handle callback within a shared storage lock" algorithm

origin workletDataOrigin, string name, task callback이 주어졌을 때, shared storage lock 안에서 callback 처리를 하려면, 다음 단계를 수행한다:
  1. environmentthisrelevant settings object로 둔다.

  2. lockManagershared storage lock managers map[workletDataOrigin]로 둔다.

  3. promisenew promise로 둔다.

  4. defaultOptions를 새 LockOptions로 둔다.

  5. promise, current agent, environmentid, lockManager, callback, name, defaultOptions["mode"], defaultOptions["ifAvailable"], defaultOptions["steal"], defaultOptions["signal"]와 함께 lock 요청을 실행한다.

Note: 기본 LockOptions에서는, lock이 granted될 때 결국 callback이 호출된다(즉, lock request는 실패하지 않는다).

11. Permissions Policy 통합

이 명세는 다음 문자열로 식별되는 세 개의 policy-controlled features를 정의한다:

shared-storage"는 일반적인 Shared Storage 접근을 gate한다.

"shared-storage-select-url"은 selectURL()에 추가 permission layer를 더한다.

"fenced-unpartitioned-storage-read"는 get()에 추가 permission layer를 더하여, Window에서 호출된 경우 disableUntrustedNetwork()에서 반환된 Promiseresolved된 경우에만 성공적으로 호출될 수 있도록 보장한다.

이들 각각에 대해 default allowlist는 *이다.

12. Clear Site Data 통합

Clear Site Data 통합에 대한 세부 사항을 추가한다.

13. Privacy 고려사항

Shared Storage API는 third-party cookies를 사용하는 것보다 사용자 privacy를 더 잘 보호하는 방식으로, 다양한 use case에서 cross-site data를 사용할 수 있는 능력을 제공하려고 한다. Shared Storage의 주요 privacy safeguard는 그 storage에 저장된 data에 대한 read access가 embedder의 SharedStorageWorklet 안에서만 발생할 수 있다는 점이다. 잘 정의된 limit는 SharedStorageWorklet에서 data의 output을 최소한으로 제한한다.

특히, embedder는 자신의 shared storage 안의 data를 기반으로 짧은 URL 목록에서 URL을 선택한 다음, 그 결과를 fenced frame에 표시할 수 있다. embedder는 더 장기적으로 더 잘 완화될 특정 메커니즘을 통하지 않고는 어떤 URL이 선택되었는지 알 수 없다. 현재는 사용자가 fenced frame을 클릭하여 top-level traversable navigation을 시작하거나, fenced framereportEvent() API를 호출할 때마다 몇 bit의 entropy가 leak될 수 있다.

embedder는 또한 Private Aggregation API를 통해 aggregatable report를 보낼 수 있다. 이 API는 differential privacy를 달성하기 위해 noise를 추가하고, report 전송에 시간 지연을 사용하며, 전송되는 report 수에 limit를 부과하고, individual privacy가 보호되도록 report를 aggregate data로 처리한다.

준수

문서 관례

준수 요구사항은 설명적 assertion과 RFC 2119 용어의 조합으로 표현된다. 이 문서의 normative 부분에서 key words “MUST”, “MUST NOT”, “REQUIRED”, “SHALL”, “SHALL NOT”, “SHOULD”, “SHOULD NOT”, “RECOMMENDED”, “MAY”, 그리고 “OPTIONAL”은 RFC 2119에 설명된 대로 해석되어야 한다. 다만 가독성을 위해, 이 명세에서는 이러한 단어들이 모두 대문자로 나타나지는 않는다.

이 명세의 모든 텍스트는 normative이다. 단, 명시적으로 non-normative로 표시된 section, example, note는 제외한다. [RFC2119]

이 명세의 example은 “for example”이라는 말로 도입되거나, normative text와 분리되어 class="example"으로 표시된다. 예를 들면 다음과 같다:

이것은 informative example의 예이다.

Informative note는 “Note”라는 말로 시작하며, normative text와 분리되어 class="note"로 표시된다. 예를 들면 다음과 같다:

Note, 이것은 informative note이다.

색인

이 명세가 정의하는 용어

참조에서 정의된 용어

참고문헌

Normative References

[BEACON]
Ilya Grigorik; Alois Reitbauer. Beacon. URL: https://w3c.github.io/beacon/
[DOM]
Anne van Kesteren. DOM Standard. Living Standard. URL: https://dom.spec.whatwg.org/
[ECMASCRIPT]
ECMAScript Language Specification. URL: https://tc39.es/ecma262/multipage/
[ENCODING]
Anne van Kesteren. Encoding Standard. Living Standard. URL: https://encoding.spec.whatwg.org/
[Fenced-Frame]
Fenced Frame. Draft Community Group Report. URL: https://wicg.github.io/fenced-frame/
[FETCH]
Anne van Kesteren. Fetch Standard. Living Standard. URL: https://fetch.spec.whatwg.org/
[HR-TIME-3]
Yoav Weiss. High Resolution Time. URL: https://w3c.github.io/hr-time/
[HTML]
Anne van Kesteren; et al. HTML Standard. Living Standard. URL: https://html.spec.whatwg.org/multipage/
[I18N-GLOSSARY]
Richard Ishida; Addison Phillips. Internationalization Glossary. URL: https://w3c.github.io/i18n-glossary/
[INFRA]
Anne van Kesteren; Domenic Denicola. Infra Standard. Living Standard. URL: https://infra.spec.whatwg.org/
[MEDIA-SOURCE-2]
Jean-Yves Avenard; Mark Watson. Media Source Extensions™. URL: https://w3c.github.io/media-source/
[MIMESNIFF]
Gordon P. Hemsley. MIME Sniffing Standard. Living Standard. URL: https://mimesniff.spec.whatwg.org/
[PERMISSIONS-POLICY-1]
Ian Clelland. Permissions Policy. URL: https://w3c.github.io/webappsec-permissions-policy/
[PRIVATE-AGGREGATION-API]
Private Aggregation API. Unofficial Proposal Draft. URL: https://patcg-individual-drafts.github.io/private-aggregation-api/
[RFC2119]
S. Bradner. Key words for use in RFCs to Indicate Requirement Levels. March 1997. Best Current Practice. URL: https://datatracker.ietf.org/doc/html/rfc2119
[RFC8941]
M. Nottingham; P-H. Kamp. Structured Field Values for HTTP. February 2021. Proposed Standard. URL: https://httpwg.org/specs/rfc8941.html
[STORAGE]
Anne van Kesteren. Storage Standard. Living Standard. URL: https://storage.spec.whatwg.org/
[URL]
Anne van Kesteren. URL Standard. Living Standard. URL: https://url.spec.whatwg.org/
[WEB-LOCKS]
Joshua Bell; Kagami Rosylight. Web Locks API. URL: https://w3c.github.io/web-locks/
[WEBIDL]
Edgar Chen; Timothy Gu. Web IDL Standard. Living Standard. URL: https://webidl.spec.whatwg.org/

Informative References

[SERVICE-WORKERS]
Yoshisato Yanagisawa; Monica CHINTALA. Service Workers. URL: https://w3c.github.io/ServiceWorker/

IDL 색인

typedef (USVString or FencedFrameConfig) SharedStorageResponse;

[Exposed=(Window)]
interface SharedStorageWorklet : Worklet {
  Promise<SharedStorageResponse> selectURL(DOMString name,
                               sequence<SharedStorageUrlWithMetadata> urls,
                               optional SharedStorageRunOperationMethodOptions options = {});
  Promise<any> run(DOMString name,
                   optional SharedStorageRunOperationMethodOptions options = {});
};

callback RunFunctionForSharedStorageSelectURLOperation = Promise<unsigned long>(sequence<USVString> urls, optional any data);

[Exposed=SharedStorageWorklet, Global=SharedStorageWorklet]
interface SharedStorageWorkletGlobalScope : WorkletGlobalScope {
  undefined register(DOMString name,
                     Function operationCtor);

  readonly attribute SharedStorage sharedStorage;
  readonly attribute PrivateAggregation privateAggregation;

  Promise<sequence<StorageInterestGroup>> interestGroups();

  readonly attribute SharedStorageWorkletNavigator navigator;
};

dictionary SharedStorageUrlWithMetadata {
  required USVString url;
  object reportingMetadata;
};

partial interface Window {
  [SecureContext] readonly attribute SharedStorage? sharedStorage;
};

[Exposed=(Window,SharedStorageWorklet)]
interface SharedStorageModifierMethod {};

[Exposed=(Window, SharedStorageWorklet)]
interface SharedStorageSetMethod : SharedStorageModifierMethod {
  constructor(DOMString key, DOMString value, optional SharedStorageSetMethodOptions options = {});
};

[Exposed=(Window, SharedStorageWorklet)]
interface SharedStorageAppendMethod : SharedStorageModifierMethod {
  constructor(DOMString key, DOMString value, optional SharedStorageModifierMethodOptions options = {});
};

[Exposed=(Window, SharedStorageWorklet)]
interface SharedStorageDeleteMethod : SharedStorageModifierMethod {
  constructor(DOMString key, optional SharedStorageModifierMethodOptions options = {});
};

[Exposed=(Window, SharedStorageWorklet)]
interface SharedStorageClearMethod : SharedStorageModifierMethod {
  constructor(optional SharedStorageModifierMethodOptions options = {});
};

dictionary SharedStorageModifierMethodOptions {
  DOMString withLock;
};

dictionary SharedStorageSetMethodOptions : SharedStorageModifierMethodOptions {
  boolean ignoreIfPresent;
};

[Exposed=(Window,SharedStorageWorklet)]
interface SharedStorage {
  Promise<DOMString> get(DOMString key);
  Promise<any> set(DOMString key,
                   DOMString value,
                   optional SharedStorageSetMethodOptions options = {});
  Promise<any> append(DOMString key,
                      DOMString value,
                      optional SharedStorageModifierMethodOptions options = {});
  Promise<any> delete(DOMString key, optional SharedStorageModifierMethodOptions options = {});
  Promise<any> clear(optional SharedStorageModifierMethodOptions options = {});
  Promise<any> batchUpdate(sequence<SharedStorageModifierMethod> methods,
                           optional SharedStorageModifierMethodOptions options = {});

  [Exposed=Window]
  Promise<SharedStorageResponse> selectURL(DOMString name,
                               sequence<SharedStorageUrlWithMetadata> urls,
                               optional SharedStorageRunOperationMethodOptions options = {});

  [Exposed=Window]
  Promise<any> run(DOMString name,
                   optional SharedStorageRunOperationMethodOptions options = {});

  [Exposed=Window]
  Promise<SharedStorageWorklet> createWorklet(USVString moduleURL, optional SharedStorageWorkletOptions options = {});

  [Exposed=Window]
  readonly attribute SharedStorageWorklet worklet;

  [Exposed=SharedStorageWorklet]
  Promise<unsigned long> length();

  [Exposed=SharedStorageWorklet]
  Promise<double> remainingBudget();

  [Exposed=SharedStorageWorklet]
  async iterable<DOMString, DOMString>;
};

dictionary SharedStoragePrivateAggregationConfig {
  USVString aggregationCoordinatorOrigin;
  USVString contextId;
  [EnforceRange] unsigned long long filteringIdMaxBytes;
  [EnforceRange] unsigned long long maxContributions;
};

dictionary SharedStorageRunOperationMethodOptions {
  object data;
  boolean resolveToConfig = false;
  boolean keepAlive = false;
  SharedStoragePrivateAggregationConfig privateAggregationConfig;
  DOMString savedQuery;
};

dictionary SharedStorageWorkletOptions : WorkletOptions {
  USVString dataOrigin = "context-origin";
};

interface mixin HTMLSharedStorageWritableElementUtils {
  [CEReactions, SecureContext] attribute boolean sharedStorageWritable;
};

HTMLIFrameElement includes HTMLSharedStorageWritableElementUtils;
HTMLImageElement includes HTMLSharedStorageWritableElementUtils;

partial dictionary RequestInit {
  boolean sharedStorageWritable;
};

[
  Exposed=SharedStorageWorklet
] interface SharedStorageWorkletNavigator {};

SharedStorageWorkletNavigator includes NavigatorLocks;

[SecureContext, Exposed=(Window,Worker,SharedStorageWorklet)]
interface LockManager {};

[SecureContext, Exposed=(Window,Worker,SharedStorageWorklet)]
interface Lock {};

이슈 색인

permissions policy 확인이 먼저 수행된다면 여기서 early return을 추가하는 것을 고려한다.
WebIDL에 의해 여기서 "name"과 "operationCtor"는 누락될 수 없다. default/empty 값만 확인해야 한다. [Issue #151]
reportingMetadatadictionary여야 한다. [Issue #141]
reportingUrlMapfencedFrameConfigStruct와 연결된 fenced frame reporter class 안에 저장한다. 이 둘 모두 draft [Fenced-Frame]에 아직 추가되어야 한다. [Issue #144]
pending shared storage budget debit의 정의를 draft fenced frame config instance [Fenced-Frame] specification으로 이동한다. [Issue #148]
navigation budget charging의 timing을 지정하는 더 나은 방법을 찾아야 한다. [Issue #138]
request가 현재 shared storage를 사용할 수 있는지 결정 알고리즘은 https://github.com/w3c/webappsec-permissions-policy/pull/499에 설명된 대로 "opt-in features"를 고려해야 한다.