rfc9404.original | rfc9404.txt | |||
---|---|---|---|---|
JMAP B. Gondwana, Ed. | Internet Engineering Task Force (IETF) B. Gondwana, Ed. | |||
Internet-Draft Fastmail | Request for Comments: 9404 Fastmail | |||
Updates: 8620 (if approved) 4 January 2023 | Updates: 8620 August 2023 | |||
Intended status: Standards Track | Category: Standards Track | |||
Expires: 8 July 2023 | ISSN: 2070-1721 | |||
JMAP Blob management extension | JSON Meta Application Protocol (JMAP) Blob Management Extension | |||
draft-ietf-jmap-blob-18 | ||||
Abstract | Abstract | |||
The JMAP base protocol (RFC8620) provides the ability to upload and | The JSON Meta Application Protocol (JMAP) base protocol (RFC 8620) | |||
download arbitrary binary data via HTTP POST and GET on defined | provides the ability to upload and download arbitrary binary data via | |||
endpoint. This binary data is called a "blob". | HTTP POST and GET on a defined endpoint. This binary data is called | |||
a "blob". | ||||
This extension adds additional ways to create and access blobs, by | This extension adds additional ways to create and access blobs by | |||
making inline method calls within a standard JMAP request. | making inline method calls within a standard JMAP request. | |||
This extension also adds a reverse lookup mechanism to discover where | This extension also adds a reverse lookup mechanism to discover where | |||
blobs are referenced within other data types. | blobs are referenced within other data types. | |||
Status of This Memo | Status of This Memo | |||
This Internet-Draft is submitted in full conformance with the | This is an Internet Standards Track document. | |||
provisions of BCP 78 and BCP 79. | ||||
Internet-Drafts are working documents of the Internet Engineering | ||||
Task Force (IETF). Note that other groups may also distribute | ||||
working documents as Internet-Drafts. The list of current Internet- | ||||
Drafts is at https://datatracker.ietf.org/drafts/current/. | ||||
Internet-Drafts are draft documents valid for a maximum of six months | This document is a product of the Internet Engineering Task Force | |||
and may be updated, replaced, or obsoleted by other documents at any | (IETF). It represents the consensus of the IETF community. It has | |||
time. It is inappropriate to use Internet-Drafts as reference | received public review and has been approved for publication by the | |||
material or to cite them other than as "work in progress." | Internet Engineering Steering Group (IESG). Further information on | |||
Internet Standards is available in Section 2 of RFC 7841. | ||||
This Internet-Draft will expire on 8 July 2023. | Information about the current status of this document, any errata, | |||
and how to provide feedback on it may be obtained at | ||||
https://www.rfc-editor.org/info/rfc9404. | ||||
Copyright Notice | Copyright Notice | |||
Copyright (c) 2023 IETF Trust and the persons identified as the | Copyright (c) 2023 IETF Trust and the persons identified as the | |||
document authors. All rights reserved. | document authors. All rights reserved. | |||
This document is subject to BCP 78 and the IETF Trust's Legal | This document is subject to BCP 78 and the IETF Trust's Legal | |||
Provisions Relating to IETF Documents (https://trustee.ietf.org/ | Provisions Relating to IETF Documents | |||
license-info) in effect on the date of publication of this document. | (https://trustee.ietf.org/license-info) in effect on the date of | |||
Please review these documents carefully, as they describe your rights | publication of this document. Please review these documents | |||
and restrictions with respect to this document. Code Components | carefully, as they describe your rights and restrictions with respect | |||
extracted from this document must include Revised BSD License text as | to this document. Code Components extracted from this document must | |||
described in Section 4.e of the Trust Legal Provisions and are | include Revised BSD License text as described in Section 4.e of the | |||
provided without warranty as described in the Revised BSD License. | Trust Legal Provisions and are provided without warranty as described | |||
in the Revised BSD License. | ||||
Table of Contents | Table of Contents | |||
1. Introduction . . . . . . . . . . . . . . . . . . . . . . . . 2 | 1. Introduction | |||
2. Conventions Used In This Document . . . . . . . . . . . . . . 3 | 2. Conventions Used in This Document | |||
3. Addition to the Capabilities Object . . . . . . . . . . . . . 3 | 3. Addition to the Capabilities Object | |||
3.1. urn:ietf:params:jmap:blob . . . . . . . . . . . . . . . . 3 | 3.1. urn:ietf:params:jmap:blob | |||
3.1.1. Capability Example . . . . . . . . . . . . . . . . . 4 | 3.1.1. Capability Example | |||
4. Blob Methods . . . . . . . . . . . . . . . . . . . . . . . . 5 | 4. Blob Methods | |||
4.1. Blob/upload . . . . . . . . . . . . . . . . . . . . . . . 5 | 4.1. Blob/upload | |||
4.1.1. Blob/upload simple example . . . . . . . . . . . . . 8 | 4.1.1. Blob/upload Simple Example | |||
4.1.2. Blob/upload complex example . . . . . . . . . . . . . 9 | 4.1.2. Blob/upload Complex Example | |||
4.2. Blob/get . . . . . . . . . . . . . . . . . . . . . . . . 11 | 4.2. Blob/get | |||
4.2.1. Blob/get simple example . . . . . . . . . . . . . . . 13 | 4.2.1. Blob/get Simple Example | |||
4.2.2. Blob/get example with range and encoding errors . . . 15 | 4.2.2. Blob/get Example with Range and Encoding Errors | |||
4.3. Blob/lookup . . . . . . . . . . . . . . . . . . . . . . . 20 | 4.3. Blob/lookup | |||
4.3.1. Blob/lookup example . . . . . . . . . . . . . . . . . 21 | 4.3.1. Blob/lookup Example | |||
5. Security considerations . . . . . . . . . . . . . . . . . . . 23 | 5. Security Considerations | |||
6. IANA considerations . . . . . . . . . . . . . . . . . . . . . 23 | 6. IANA Considerations | |||
6.1. JMAP Capability registration for "blob" . . . . . . . . . 23 | 6.1. JMAP Capability Registration for "blob" | |||
6.2. JMAP Error Codes Registration for "unknownDataType" . . . 24 | 6.2. JMAP Error Codes Registration for "unknownDataType" | |||
6.3. Creation of "JMAP Data Types" Registry . . . . . . . . . 24 | 6.3. Creation of "JMAP Data Types" Registry | |||
7. Changes . . . . . . . . . . . . . . . . . . . . . . . . . . . 25 | 7. References | |||
8. Acknowledgements . . . . . . . . . . . . . . . . . . . . . . 29 | 7.1. Normative References | |||
9. Normative References . . . . . . . . . . . . . . . . . . . . 29 | 7.2. Informative References | |||
10. Informative References . . . . . . . . . . . . . . . . . . . 29 | Acknowledgements | |||
Author's Address . . . . . . . . . . . . . . . . . . . . . . . . 30 | Author's Address | |||
1. Introduction | 1. Introduction | |||
Sometimes JMAP ([RFC8620]) interactions require creating a blob and | Sometimes JMAP [RFC8620] interactions require creating a blob and | |||
then referencing it. In the same way that IMAP Literals were | then referencing it. In the same way that IMAP literals were | |||
extended by [RFC7888], embedding small blobs directly into the JMAP | extended by [RFC7888], embedding small blobs directly into the JMAP | |||
method calls array can be an option for reducing roundtrips. | method calls array can be an option for reducing round trips. | |||
Likewise, when fetching an object, it can be useful to also fetch the | Likewise, when fetching an object, it can be useful to also fetch the | |||
raw content of that object without a separate roundtrip. | raw content of that object without a separate round trip. | |||
Since raw blobs may contain arbitrary binary data, this document | Since raw blobs may contain arbitrary binary data, this document | |||
defines a use of the base64 coding specified in [RFC4648] for both | defines a use of the base64 coding specified in [RFC4648] for both | |||
creating and fetching blob data. | creating and fetching blob data. | |||
Where JMAP is being proxied through a system which applies additional | When JMAP is proxied through a system that applies additional access | |||
access restrictions, it can be useful to know which objects reference | restrictions, it can be useful to know which objects reference any | |||
any particular blob, and this document defines a way to discover | particular blob; this document defines a way to discover those | |||
those references. | references. | |||
2. Conventions Used In This Document | 2. Conventions Used in This Document | |||
The key words "MUST", "MUST NOT", "REQUIRED", "SHALL", "SHALL NOT", | The key words "MUST", "MUST NOT", "REQUIRED", "SHALL", "SHALL NOT", | |||
"SHOULD", "SHOULD NOT", "RECOMMENDED", "NOT RECOMMENDED", "MAY", and | "SHOULD", "SHOULD NOT", "RECOMMENDED", "NOT RECOMMENDED", "MAY", and | |||
"OPTIONAL" in this document are to be interpreted as described in BCP | "OPTIONAL" in this document are to be interpreted as described in | |||
14 [RFC2119] [RFC8174] when, and only when, they appear in all | BCP 14 [RFC2119] [RFC8174] when, and only when, they appear in all | |||
capitals, as shown here. | capitals, as shown here. | |||
The definitions of JSON keys and datatypes in the document follow the | The definitions of JSON keys and datatypes in the document follow the | |||
conventions described in the core JMAP specification [RFC8620]. | conventions described in [RFC8620]. | |||
3. Addition to the Capabilities Object | 3. Addition to the Capabilities Object | |||
The capabilities object is returned as part of the JMAP Session | The capabilities object is returned as part of the JMAP Session | |||
object; see [RFC8620], Section 2. | object; see [RFC8620], Section 2. | |||
This document defines an additional capability URI. | This document defines an additional capability URI. | |||
3.1. urn:ietf:params:jmap:blob | 3.1. urn:ietf:params:jmap:blob | |||
The capability urn:ietf:params:jmap:blob being present in the | The presence of the capability urn:ietf:params:jmap:blob in the | |||
"accountCapabilities" property of an account represents support for | accountCapabilities property of an account represents support for | |||
additional API methods on the Blob datatype. Servers that include | additional API methods on the Blob datatype. Servers that include | |||
the capability in one or more "accountCapabilities" properties MUST | the capability in one or more accountCapabilities properties MUST | |||
also include the property in the "capabilities" property. | also include the property in the capabilities property. | |||
The value of this property in the JMAP session "capabilities" | The value of this property in the JMAP Session capabilities property | |||
property MUST be an empty object. | MUST be an empty object. | |||
The value of this property in an account's "accountCapabilities" | The value of this property in an account's accountCapabilities | |||
property is an object that MUST contain the following information on | property is an object that MUST contain the following information on | |||
server capabilities and permissions for that account: | server capabilities and permissions for that account: | |||
* maxSizeBlobSet: UnsignedInt|null | * maxSizeBlobSet: "UnsignedInt|null" | |||
This is the maximum size of blob (in octets) that the server will | The maximum size of the blob (in octets) that the server will | |||
allow to be created (including blobs created by concatenating | allow to be created (including blobs created by concatenating | |||
multiple data sources together). | multiple data sources together). | |||
Clients MUST NOT attempt to create blobs larger than this size. | Clients MUST NOT attempt to create blobs larger than this size. | |||
If this value is null, then clients are not required to limit the | If this value is null, then clients are not required to limit the | |||
size of blob they try to create, though servers can always reject | size of the blob they try to create, though servers can always | |||
creation of blobs regardless of size; e.g. due to lack of disk | reject creation of blobs regardless of size, e.g., due to lack of | |||
space, or per-user rate limits. | disk space or per-user rate limits. | |||
* maxDataSources: UnsignedInt | * maxDataSources: "UnsignedInt" | |||
The maximum number of DataSourceObjects allowed per creation in a | The maximum number of DataSourceObjects allowed per creation in a | |||
Blob/upload. | Blob/upload. | |||
Servers MUST allow at least 64 DataSourceObjects per creation. | Servers MUST allow at least 64 DataSourceObjects per creation. | |||
* supportedTypeNames: String[] | * supportedTypeNames: "String[]" | |||
An array of data type names that are supported for Blob/lookup. | An array of data type names that are supported for Blob/lookup. | |||
If the server does not support lookups then this will be the empty | If the server does not support lookups, then this will be the | |||
list. | empty list. | |||
NOTE, the supportedTypeNames list may include private types which | Note that the supportedTypeNames list may include private types | |||
are not in the JMAP Types Registry defined by this document. | that are not in the "JMAP Data Types" registry defined by this | |||
Clients MUST ignore type names they do not recognise. | document. Clients MUST ignore type names they do not recognise. | |||
* supportedDigestAlgorithms: String[] | * supportedDigestAlgorithms: "String[]" | |||
An array of supported digest algorithms that are supported for | An array of supported digest algorithms that are supported for | |||
Blob/get. If the server does not support calculating blob | Blob/get. If the server does not support calculating blob | |||
digests, then this will be the empty list. Algorithms in this | digests, then this will be the empty list. Algorithms in this | |||
list MUST be present in the HTTP Digest Algorithms registry | list MUST be present in the "HTTP Digest Algorithm Values" | |||
defined by [RFC3230], and are always lowercased. | registry defined by [RFC3230]; however, in JMAP, they must be | |||
lowercased, e.g., "md5" rather than "MD5". | ||||
Clients SHOULD prefer algorithms listed earlier in this list. | Clients SHOULD prefer algorithms listed earlier in this list. | |||
3.1.1. Capability Example | 3.1.1. Capability Example | |||
{ | { | |||
"capabilities": { | "capabilities": { | |||
..., | ..., | |||
"urn:ietf:params:jmap:blob": {} | "urn:ietf:params:jmap:blob": {} | |||
}, | }, | |||
"accounts": { | "accounts": { | |||
"A13842": { | "A13842": { | |||
... | ... | |||
"accountCapabilities": { | "accountCapabilities": { | |||
"urn:ietf:params:jmap:blob": { | "urn:ietf:params:jmap:blob": { | |||
skipping to change at page 5, line 35 ¶ | skipping to change at line 205 ¶ | |||
} | } | |||
} | } | |||
} | } | |||
} | } | |||
} | } | |||
4. Blob Methods | 4. Blob Methods | |||
A blob is a sequence of zero or more octets. | A blob is a sequence of zero or more octets. | |||
The JMAP base spec [RFC8620] defines the Blob/copy method, which is | JMAP [RFC8620] defines the Blob/copy method, which is unchanged by | |||
unchanged by this specification, and is selected by the | this specification and is selected by the urn:ietf:params:jmap:core | |||
urn:ietf:params:jmap:core capability. | capability. | |||
The following JMAP Methods are selected by the | The following JMAP methods are selected by the | |||
urn:ietf:params:jmap:blob capability. | urn:ietf:params:jmap:blob capability. | |||
4.1. Blob/upload | 4.1. Blob/upload | |||
This is similar to a Foo/set from [RFC8620] in some ways, however | This is similar to a Foo/set in [RFC8620] in some ways. However, | |||
blobs can not be updated or deleted, so only create is allowed in the | blobs cannot be updated or deleted, so only create is allowed in the | |||
method call, and blobs do not have state, so there is no state field | method call. Also, blobs do not have state, so there is no state | |||
present in the method response. | field present in the method response. | |||
*Parameters* | *Parameters* | |||
* accountId: Id | * accountId: "Id" | |||
The id of the account in which the blobs will be created. | The id of the account in which the blobs will be created. | |||
* create: Id[UploadObject] | * create: "Id[UploadObject]" | |||
A map of creation id to UploadObjects. | A map of creation id to UploadObjects. | |||
*Result* | *Result* | |||
The result is the same as for Foo/set in RFC8620, with created and | The result is the same as for Foo/set in [RFC8620], with created and | |||
notCreated objects mapping from the creationId. | notCreated objects mapping from the creation id. | |||
The created objects contain: | The created objects contain: | |||
* id: Id | * id: "Id" | |||
the blobId which was created | The blobId that was created. | |||
* type: String|null | * type: "String|null" | |||
the media type as given in the creation (if any); or detected from | The media type as given in the creation (if any). If not | |||
content by the server; or null | provided, the server MAY perform content analysis and return one | |||
of the following: the calculated value, "application/octet- | ||||
string", or null. | ||||
* size: UnsignedInt | * size: "UnsignedInt" | |||
as per RFC8620 - the size of the created blob in octets | As per [RFC8620], the size of the created blob in octets. | |||
It will also contain any other properties identical to those that | The created objects will also contain any other properties identical | |||
would be returned in the JSON response of the RFC8620 upload endpoint | to those that would be returned in the JSON response of the upload | |||
(which may be extended in the future - this document anticipates that | endpoint described in [RFC8620]. This may be extended in the future; | |||
implementations will extend both the upload endpoint and the Blob/ | in this document, it is anticipated that implementations will extend | |||
upload responses in the same way) | both the upload endpoint and the Blob/upload responses in the same | |||
way. | ||||
Or if there is a problem with a creation, then the server will return | If there is a problem with a creation, then the server will return a | |||
a notCreated response with a map from the failed creationId to a | notCreated response with a map from the failed creation id to a | |||
SetError object. | SetError object. | |||
For each successful upload, servers MUST add an entry to the | For each successful upload, servers MUST add an entry to the | |||
creationIds map for the request. This allows the blob id to be used | createdIds map ([RFC8620], Section 3.3) for the request; even if the | |||
via back-reference in subsequent method calls. | caller did not explicitly pass a createdIds, the value must be | |||
available to later methods defined in the same Request Object. This | ||||
allows the blobId to be used via back-reference in subsequent method | ||||
calls. | ||||
The created blob will have the same lifetime and same expiry | The created blob will have the same lifetime and same expiry | |||
semantics as any other binary object created via the mechanism | semantics as any other binary object created via the mechanism | |||
specified in [!@RFC8620] section 6. | specified in [RFC8620], Section 6. | |||
Uploads using with this mechanism will be restricted by the | Uploads using this mechanism will be restricted by the maxUploadSize | |||
maxUploadSize limit for JMAP requests specified by the server, and | limit for JMAP requests specified by the server, and clients SHOULD | |||
clients SHOULD consider using the upload mechanism defined by | consider using the upload mechanism defined by [RFC8620] for blobs | |||
[!@RFC8620] for blobs larger than a megabyte. | larger than a megabyte. | |||
*UploadObject* | *UploadObject* | |||
* data: DataSourceObject[] | * data: "DataSourceObject[]" | |||
an array of zero or more octet sources in order (zero to create an | An array of zero or more octet sources in order (zero to create an | |||
empty blob). The result of each of these sources is concatenated | empty blob). The result of each of these sources is concatenated | |||
together in order to create the blob. | in order to create the blob. | |||
* type: String|null (default: null) | * type: "String|null" (default: null) | |||
hint for media type of the data | A hint for media type of the data. | |||
*DataSourceObject* | *DataSourceObject* | |||
Exactly one of: | Exactly one of: | |||
* data:asText: String|null (raw octets, must be UTF-8) | * data:asText: "String|null" (raw octets, must be UTF-8) | |||
* data:asBase64: String|null (base64 representation of octets) | * data:asBase64: "String|null" (base64 representation of octets) | |||
or a blobId source: | or a blobId source: | |||
* blobId: Id | * blobId: "Id" | |||
* offset: UnsignedInt|null (MAY be zero) | * offset: "UnsignedInt|null" (MAY be zero) | |||
* length: UnsignedInt|null (MAY be zero) | * length: "UnsignedInt|null" (MAY be zero) | |||
If null then offset is assumed to be zero. | If null, then offset is assumed to be zero. | |||
If null then length is the remaining octets in the blob. | If null, then length is the remaining octets in the blob. | |||
If the range can not be fully satisfied (i.e. begins or extends past | If the range cannot be fully satisfied (i.e., it begins or extends | |||
the end of the data in the blob) then the DataSourceObject is invalid | past the end of the data in the blob), then the DataSourceObject is | |||
and results in a notCreated response for this creation id. | invalid and results in a notCreated response for this creation id. | |||
If the data properties have any invalid references or invalid data | If the data properties have any invalid references or invalid data | |||
contained in them, the server MUST NOT guess as to the user's intent, | contained in them, the server MUST NOT guess the user's intent and | |||
and MUST reject the creation and return a notCreated response for | MUST reject the creation and return a notCreated response for that | |||
that creation id. | creation id. | |||
Likewise, invalid characters in the base64 of data:asBase64, or | Likewise, invalid characters in the base64 of data:asBase64 or | |||
invalid UTF-8 in data:asText MUST result in a nonCreated response. | invalid UTF-8 in data:asText MUST result in a notCreated response. | |||
It is envisaged that the definition for DataSourceObject might be | It is envisaged that the definition for DataSourceObject might be | |||
extended in the future, for example to fetch external content. | extended in the future, for example, to fetch external content. | |||
A server MUST accept at least 64 DataSourceObjects per create, as | A server MUST accept at least 64 DataSourceObjects per create, as | |||
described in Section 3.1 of this document. | described in Section 3.1 of this document. | |||
4.1.1. Blob/upload simple example | 4.1.1. Blob/upload Simple Example | |||
The data:asBase64 field is set over multiple lines for ease of | The data:asBase64 field is set over multiple lines for ease of | |||
publication here, however all data:asBase64 would be sent as a | publication here; however, the entire data:asBase64 field would be | |||
continuous string with no whitespace on the wire. | sent as a continuous string with no wrapping on the wire. | |||
Method Call: | Method Call: | |||
[ | [ | |||
"Blob/upload", | "Blob/upload", | |||
{ | { | |||
"accountId": "account1", | "accountId": "account1", | |||
"create": { | "create": { | |||
"1": { | "1": { | |||
"data" : [ | "data" : [ | |||
{ | { | |||
"data:asBase64": "iVBORw0KGgoAAAANSUhEUgAAAAEAAAABAQMAAAAl21bKA | "data:asBase64": "iVBORw0KGgoAAAANSUhEUgAAAAEAAAABAQMAAAAl21bKA | |||
AAAA1BMVEX/AAAZ4gk3AAAAAXRSTlN/gFy0ywAAAApJRE | AAAA1BMVEX/AAAZ4gk3AAAAAXRSTlN/gFy0ywAAAApJRE | |||
FUeJxjYgAAAAYAAzY3fKgAAAAASUVORK5CYII=", | FUeJxjYgAAAAYAAzY3fKgAAAAASUVORK5CYII=" | |||
} | } | |||
], | ], | |||
"type": "image/png" | "type": "image/png" | |||
}, | } | |||
} | ||||
}, | }, | |||
}, | "R1" | |||
"R1" | ] | |||
] | ||||
Response: | Response: | |||
[ | [ | |||
"Blob/upload", | "Blob/upload", | |||
{ | { | |||
"accountId" : "account1", | "accountId" : "account1", | |||
"created" : { | "created" : { | |||
"1": { | "1": { | |||
"id" : "G4c6751edf9dd6903ff54b792e432fba781271beb", | "id" : "G4c6751edf9dd6903ff54b792e432fba781271beb", | |||
"type" : "image/png", | "type" : "image/png", | |||
"size" : 95 | "size" : 95 | |||
}, | } | |||
}, | } | |||
}, | }, | |||
"R1" | "R1" | |||
] | ] | |||
4.1.2. Blob/upload complex example | ||||
Method Calls: | 4.1.2. Blob/upload Complex Example | |||
[ | Method Calls: | |||
[ | ||||
"Blob/upload", | [ | |||
{ | [ | |||
"Blob/upload", | ||||
{ | ||||
"create": { | "create": { | |||
"b4": { | "b4": { | |||
"data": [ | "data": [ | |||
{ | { | |||
"data:asText": "The quick brown fox jumped over the lazy dog." | "data:asText": "The quick brown fox jumped over the lazy dog." | |||
} | } | |||
] | ] | |||
} | ||||
} | } | |||
} | ||||
}, | }, | |||
"S4" | "S4" | |||
], | ], | |||
[ | [ | |||
"Blob/upload", | "Blob/upload", | |||
{ | { | |||
"create": { | "create": { | |||
"cat": { | "cat": { | |||
"data": [ | "data": [ | |||
{ | { | |||
"data:asText": "How" | "data:asText": "How" | |||
}, | }, | |||
{ | { | |||
"blobId": "#b4", | "blobId": "#b4", | |||
"length": 7, | "length": 7, | |||
"offset": 3 | "offset": 3 | |||
skipping to change at page 10, line 4 ¶ | skipping to change at line 421 ¶ | |||
"blobId": "#b4", | "blobId": "#b4", | |||
"length": 1, | "length": 1, | |||
"offset": 1 | "offset": 1 | |||
}, | }, | |||
{ | { | |||
"data:asBase64": "YXQ/" | "data:asBase64": "YXQ/" | |||
} | } | |||
] | ] | |||
} | } | |||
} | } | |||
}, | ||||
}, | "CAT" | |||
"CAT" | ], | |||
], | [ | |||
[ | "Blob/get", | |||
"Blob/get", | { | |||
{ | ||||
"properties": [ | "properties": [ | |||
"data:asText", | "data:asText", | |||
"size" | "size" | |||
], | ], | |||
"ids": [ | "ids": [ | |||
"#cat" | "#cat" | |||
] | ] | |||
}, | }, | |||
"G4" | "G4" | |||
] | ] | |||
] | ] | |||
Responses: | Responses: | |||
[ | [ | |||
[ | [ | |||
"Blob/upload", | "Blob/upload", | |||
{ | { | |||
"oldState": null, | "oldState": null, | |||
"created": { | "created": { | |||
"b4": { | "b4": { | |||
"id": "Gc0854fb9fb03c41cce3802cb0d220529e6eef94e", | "id": "Gc0854fb9fb03c41cce3802cb0d220529e6eef94e", | |||
"size": 45, | "size": 45, | |||
"type": "application/octet-stream" | "type": "application/octet-stream" | |||
} | } | |||
}, | }, | |||
"notCreated": null, | "notCreated": null, | |||
"accountId": "account1" | "accountId": "account1" | |||
}, | }, | |||
"S4" | "S4" | |||
], | ], | |||
[ | [ | |||
"Blob/upload", | "Blob/upload", | |||
{ | { | |||
"oldState": null, | "oldState": null, | |||
"created": { | "created": { | |||
"cat": { | "cat": { | |||
"id": "Gcc60576f036321ae6e8037ffc56bdee589bd3e23", | "id": "Gcc60576f036321ae6e8037ffc56bdee589bd3e23", | |||
"size": 19, | "size": 19, | |||
"type": "application/octet-stream" | "type": "application/octet-stream" | |||
} | } | |||
}, | }, | |||
"notCreated": null, | "notCreated": null, | |||
"accountId": "account1" | "accountId": "account1" | |||
}, | }, | |||
"CAT" | "CAT" | |||
], | ], | |||
[ | [ | |||
"Blob/get", | "Blob/get", | |||
{ | { | |||
"list": [ | "list": [ | |||
{ | { | |||
"id": "Gcc60576f036321ae6e8037ffc56bdee589bd3e23", | "id": "Gcc60576f036321ae6e8037ffc56bdee589bd3e23", | |||
"data:asText": "How quick was that?", | "data:asText": "How quick was that?", | |||
"size": 19 | "size": 19 | |||
} | } | |||
], | ], | |||
"notFound": [], | "notFound": [], | |||
"accountId": "account1" | "accountId": "account1" | |||
}, | }, | |||
"G4" | "G4" | |||
] | ] | |||
] | ] | |||
4.2. Blob/get | 4.2. Blob/get | |||
A standard JMAP get, with two additional optional parameters: | A standard JMAP get, with two additional optional parameters: | |||
* offset: UnsignedInt|null | * offset: "UnsignedInt|null" | |||
start this many octets into the blob data. If null or | Start this many octets into the blob data. If null or | |||
unspecified, this defaults to zero. | unspecified, this defaults to zero. | |||
* length: UnsignedInt|null | * length: "UnsignedInt|null" | |||
return at most this many octets of the blob data. If null or | Return at most this many octets of the blob data. If null or | |||
unspecified, then all remaining octets in the blob are returned. | unspecified, then all remaining octets in the blob are returned. | |||
This can be considered equivalent to an infinitely large length | This can be considered equivalent to an infinitely large length | |||
value, except that the isTruncated warning is not given unless the | value, except that the isTruncated warning is not given unless the | |||
start offset is past the end of the blob. | start offset is past the end of the blob. | |||
*Request Properties:* | *Request Properties:* | |||
Any of | Any of: | |||
* data:asText | * data:asText | |||
* data:asBase64 | * data:asBase64 | |||
* data (returns data:asText if the selected octets are valid UTF-8, | ||||
* data (returns data:asText if the selected octets are valid UTF-8 | ||||
or data:asBase64) | or data:asBase64) | |||
* digest:<algorithm> (where <algorithm> is one of the named | * digest:<algorithm> (where <algorithm> is one of the named | |||
algorithms in the supportedDigestAlgorithms capability) | algorithms in the supportedDigestAlgorithms capability) | |||
* size | * size | |||
If not given, properties defaults to data and size. | If not given, the properties default to data and size. | |||
*Result Properties:* | *Result Properties:* | |||
* data:asText: String|null | * data:asText: "String|null" | |||
the raw octets of the selected range if they are valid UTF-8, | The raw octets of the selected range if they are valid UTF-8; | |||
otherwise null | otherwise, null. | |||
* data:asBase64: String | * data:asBase64: "String" | |||
the base64 encoding of the octets in the selected range | The base64 encoding of the octets in the selected range. | |||
* digest:<algorithm> String | * digest:<algorithm>: "String" | |||
the base64 encoding of the digest of the octets in the selected | The base64 encoding of the digest of the octets in the selected | |||
range, calculated using the named algorithm | range, calculated using the named algorithm. | |||
* isEncodingProblem: Boolean (default: false) | * isEncodingProblem: "Boolean" (default: false) | |||
* isTruncated: Boolean (default: false) | * isTruncated: "Boolean" (default: false) | |||
* size: UnsignedInt | * size: "UnsignedInt" | |||
the number of octets in the entire blob | The number of octets in the entire blob. | |||
The size value MUST always be the number of octets in the underlying | The size value MUST always be the number of octets in the underlying | |||
blob, regardless of offset and length. | blob, regardless of offset and length. | |||
The data fields contain a representation of the octets within the | The data fields contain a representation of the octets within the | |||
selected range that are present in the blob. If the octets selected | selected range that are present in the blob. If the octets selected | |||
are not valid UTF-8 (including truncating in the middle of a multi- | are not valid UTF-8 (including truncating in the middle of a multi- | |||
octet sequence) and data or data:asText was requested, then the key | octet sequence) and data or data:asText was requested, then the key | |||
isEncodingProblem MUST be set to true and the data:asText response | isEncodingProblem MUST be set to true, and the data:asText response | |||
value MUST be null. In the case where data was requested and the | value MUST be null. In the case where data was requested and the | |||
data is not valid UTF-8, then data:asBase64 MUST be returned. | data is not valid UTF-8, then data:asBase64 MUST be returned. | |||
If the selected range requests data outside the blob (i.e. the | If the selected range requests data outside the blob (i.e., the | |||
offset+length is larger than the blob) then the result is either just | offset+length is larger than the blob), then the result is either | |||
the octets from the offset to the end of the blob, or an empty string | just the octets from the offset to the end of the blob or an empty | |||
if the offset is past the end of the blob. Either way, the | string if the offset is past the end of the blob. Either way, the | |||
isTruncated property in the result MUST be set to true to tell the | isTruncated property in the result MUST be set to true to tell the | |||
client that the requested range could not be fully satisfied. If | client that the requested range could not be fully satisfied. If | |||
digest was requested, any digest is calculated on the octets that | digest was requested, any digest is calculated on the octets that | |||
would be returned for a data field. | would be returned for a data field. | |||
Servers SHOULD store the size for blobs in a format which is | Servers SHOULD store the size for blobs in a format that is efficient | |||
efficient to read, and clients SHOULD limit their request to just the | to read, and clients SHOULD limit their request to just the size | |||
size parameter if that is all they need, as fetching blob content | parameter if that is all they need, as fetching blob content could be | |||
could be significantly more expensive and slower for the server. | significantly more expensive and slower for the server. | |||
4.2.1. Blob/get simple example | 4.2.1. Blob/get Simple Example | |||
Where a blob containing the string "The quick brown fox jumped over | In this example, a blob containing the string "The quick brown fox | |||
the lazy dog." has blobId Gc0854fb9fb03c41cce3802cb0d220529e6eef94e. | jumped over the lazy dog." has blobId | |||
Gc0854fb9fb03c41cce3802cb0d220529e6eef94e. | ||||
The first method call requests just the size for multiple blobs, and | The first method call requests just the size for multiple blobs, and | |||
the second requests both size and a short range of the data for one | the second requests both the size and a short range of the data for | |||
of the blobs. | one of the blobs. | |||
Method Calls: | ||||
[ | Method Calls: | |||
[ | ||||
"Blob/get", | ||||
{ | ||||
"accountId" : "account1", | ||||
"ids" : [ | ||||
"Gc0854fb9fb03c41cce3802cb0d220529e6eef94e", | ||||
"not-a-blob" | ||||
], | ||||
"properties" : [ | ||||
"data:asText", | ||||
"digest:sha", | ||||
"size" | ||||
] | ||||
}, | ||||
"R1" | ||||
], | ||||
[ | ||||
"Blob/get", | ||||
{ | ||||
"accountId" : "account1", | ||||
"ids" : [ | ||||
"Gc0854fb9fb03c41cce3802cb0d220529e6eef94e" | ||||
], | [ | |||
"properties" : [ | [ | |||
"data:asText", | "Blob/get", | |||
"digest:sha", | { | |||
"digest:sha-256", | "accountId" : "account1", | |||
"size" | "ids" : [ | |||
], | "Gc0854fb9fb03c41cce3802cb0d220529e6eef94e", | |||
"offset" : 4, | "not-a-blob" | |||
"length" : 9 | ], | |||
}, | "properties" : [ | |||
"R2" | "data:asText", | |||
] | "digest:sha", | |||
] | "size" | |||
] | ||||
}, | ||||
"R1" | ||||
], | ||||
[ | ||||
"Blob/get", | ||||
{ | ||||
"accountId" : "account1", | ||||
"ids" : [ | ||||
"Gc0854fb9fb03c41cce3802cb0d220529e6eef94e" | ||||
], | ||||
"properties" : [ | ||||
"data:asText", | ||||
"digest:sha", | ||||
"digest:sha-256", | ||||
"size" | ||||
], | ||||
"offset" : 4, | ||||
"length" : 9 | ||||
}, | ||||
"R2" | ||||
] | ||||
] | ||||
Responses: | Responses: | |||
[ | [ | |||
[ | [ | |||
"Blob/get", | "Blob/get", | |||
{ | { | |||
"accountId": "account1", | "accountId": "account1", | |||
"list": [ | "list": [ | |||
{ | { | |||
"id": "Gc0854fb9fb03c41cce3802cb0d220529e6eef94e", | "id": "Gc0854fb9fb03c41cce3802cb0d220529e6eef94e", | |||
"data:asText": "The quick brown fox jumped over the lazy dog.", | "data:asText": "The quick brown fox jumped over the lazy dog.", | |||
"digest:sha": "wIVPufsDxBzOOALLDSIFKebu+U4=", | "digest:sha": "wIVPufsDxBzOOALLDSIFKebu+U4=", | |||
"size": 45 | "size": 45 | |||
} | } | |||
], | ], | |||
"notFound": [ | "notFound": [ | |||
"not-a-blob" | "not-a-blob" | |||
] | ] | |||
}, | }, | |||
"R1" | "R1" | |||
], | ], | |||
[ | [ | |||
"Blob/get", | "Blob/get", | |||
{ | { | |||
"accountId": "account1", | "accountId": "account1", | |||
"list": [ | "list": [ | |||
{ | { | |||
"id": "Gc0854fb9fb03c41cce3802cb0d220529e6eef94e", | "id": "Gc0854fb9fb03c41cce3802cb0d220529e6eef94e", | |||
"data:asText": "quick bro", | "data:asText": "quick bro", | |||
"digest:sha": "QiRAPtfyX8K6tm1iOAtZ87Xj3Ww=", | "digest:sha": "QiRAPtfyX8K6tm1iOAtZ87Xj3Ww=", | |||
"digest:sha-256": "gdg9INW7lwHK6OQ9u0dwDz2ZY/gubi0En0xlFpKt0OA=", | "digest:sha-256": "gdg9INW7lwHK6OQ9u0dwDz2ZY/gubi0En0xlFpKt0OA=", | |||
"size": 45 | "size": 45 | |||
} | } | |||
] | ] | |||
}, | ||||
"R2" | ||||
] | ||||
] | ||||
}, | 4.2.2. Blob/get Example with Range and Encoding Errors | |||
"R2" | ||||
] | ||||
] | ||||
4.2.2. Blob/get example with range and encoding errors | ||||
The b1 value is the text: "The quick brown fox jumped over the | The b1 value is the text "The quick brown fox jumped over the | |||
\x81\x81 fox" which contains an invalid utf8 sequence. | \x81\x81 dog.", which contains an invalid UTF-8 sequence. | |||
The results have the following interesting properties: | The results have the following properties: | |||
* G1: defaults to data and size - so b1 returns isEncodingProblem | * G1: Defaults to data and size, so b1 returns isEncodingProblem and | |||
and a base64 value. | a base64 value. | |||
* G2: since data:asText was explicitly selected, does not attempt to | * G2: Since data:asText was explicitly selected, does not attempt to | |||
return a value for the data, just isEncodingProblem for b1. | return a value for the data, just isEncodingProblem for b1. | |||
* G3: since only data:asBase64 was requested, there is no encoding | * G3: Since only data:asBase64 was requested, there is no encoding | |||
problem and both values are returned. | problem, and both values are returned. | |||
* G4: since the requested range could be satisfied as text, both | * G4: Since the requested range could be satisfied as text, both | |||
blobs are returned as data:asText and there is no encoding | blobs are returned as data:asText, and there is no encoding | |||
problem. | problem. | |||
* G5: both blobs cannot satisfy the requested range, so isTruncated | * G5: Both blobs cannot satisfy the requested range, so isTruncated | |||
is true for both. | is true for both. | |||
Note: some values have been wrapped for line length - there would be | | Note: Some values have been wrapped for line length. There | |||
no whitespace in the data:asBase64 values on the wire | | would be no wrapping in the data:asBase64 values on the wire. | |||
Method calls: | Method Calls: | |||
[ | [ | |||
[ | [ | |||
"Blob/upload", | "Blob/upload", | |||
{ | { | |||
"create": { | "create": { | |||
"b1": { | "b1": { | |||
"data": [ | "data": [ | |||
{ | { | |||
"data:asBase64": "VGhlIHF1aWNrIGJyb3duIGZveCBqdW1wZW | "data:asBase64": "VGhlIHF1aWNrIGJyb3duIGZveCBqdW1wZW | |||
skipping to change at page 20, line 26 ¶ | skipping to change at line 920 ¶ | |||
"accountId": "account1" | "accountId": "account1" | |||
}, | }, | |||
"G5" | "G5" | |||
] | ] | |||
] | ] | |||
4.3. Blob/lookup | 4.3. Blob/lookup | |||
Given a list of blobIds, this method does a reverse lookup in each of | Given a list of blobIds, this method does a reverse lookup in each of | |||
the provided type names to find the list of Ids within that data type | the provided type names to find the list of Ids within that data type | |||
which reference the provided blob. | that reference the provided blob. | |||
Since different datatypes will have different semantics of | Since different datatypes will have different semantics of | |||
"contains", the definition of reference is somewhat loosely defined, | "contains", the definition of "reference" is somewhat loose but | |||
but roughly means "you could discover this blobId by looking at this | roughly means "you could discover this blobId by looking at this | |||
object or at other objects recursively contained within this object". | object or at other objects recursively contained within this object". | |||
For example with an [RFC8621] server, if checking whether a Mailbox | For example, with a server that supports [RFC8621], if a Mailbox | |||
references a blob, then if any Emails within that Mailbox reference | references a blob and if any Emails within that Mailbox reference the | |||
the blobId, then the Mailbox references that blobId. For any Thread | blobId, then the Mailbox references that blobId. For any Thread that | |||
which references an Email that references a blobId, it can be said | references an Email that references a blobId, it can be said that the | |||
that the Thread references the blobId. | Thread references the blobId. | |||
But this does not mean that if an Email references a Mailbox in its | However, this does not mean that if an Email references a Mailbox in | |||
mailboxIds property, then any blobId referenced by other Emails in | its mailboxIds property, then any blobId referenced by other Emails | |||
that Mailbox are also referenced by the initial Email. | in that Mailbox are also referenced by the initial Email. | |||
*Parameters* | *Parameters* | |||
* accountId: Id | * accountId: "Id" | |||
The id of the account used for the call. | The id of the account used for the call. | |||
* typeNames: String[] | * typeNames: "String[]" | |||
A list of names from the "JMAP Data Types" registry, or defined by | ||||
private extensions which the client has requested. Only names for | A list of names from the "JMAP Data Types" registry or defined by | |||
private extensions that the client has requested. Only names for | ||||
which "Can reference blobs" is true may be specified, and the | which "Can reference blobs" is true may be specified, and the | |||
capability which defines each type must also be used by the | capability that defines each type must also be used by the overall | |||
overall JMAP request in which this method is called. | JMAP request in which this method is called. | |||
If a type name is not known by the server, or the associated | If a type name is not known by the server, or the associated | |||
capability has not been requested, then the server returns an | capability has not been requested, then the server returns an | |||
"unknownDataType" error. | "unknownDataType" error. | |||
* ids: Id[] | * ids: "Id[]" | |||
A list of blobId values to be looked for. | A list of blobId values to be looked for. | |||
*Response* | *Response* | |||
* list: BlobInfo[] | * list: "BlobInfo[]" | |||
A list of BlobInfo objects. | A list of BlobInfo objects. | |||
*BlobInfo Object* | *BlobInfo Object* | |||
* id: Id | * id: "Id" | |||
The Blob Identifier. | The blobId. | |||
* matchedIds: String[Id[]] | * matchedIds: "String[Id[]]" | |||
A map from type name to list of Ids of that data type (e.g. the | A map from type name to a list of Ids of that data type (e.g., the | |||
name "Email" maps to a list of emailIds) | name "Email" maps to a list of emailIds). | |||
If a blob is not visible to a user, or does not exist on the server | If a blob is not visible to a user or does not exist on the server at | |||
at all, then the server MUST still return an empty array for each | all, then the server MUST still return an empty array for each type | |||
type as this doesn't leak any information about whether the blob is | as this doesn't leak any information about whether the blob is on the | |||
on the server but not visible to the requesting user. | server but not visible to the requesting user. | |||
4.3.1. Blob/lookup example | 4.3.1. Blob/lookup Example | |||
Method call: | ||||
Method Call: | ||||
[ | [ | |||
"Blob/lookup", | "Blob/lookup", | |||
{ | { | |||
"typeNames": [ | "typeNames": [ | |||
"Mailbox", | "Mailbox", | |||
"Thread", | "Thread", | |||
"Email" | "Email" | |||
], | ], | |||
"ids": [ | "ids": [ | |||
skipping to change at page 23, line 5 ¶ | skipping to change at line 1031 ¶ | |||
} | } | |||
} | } | |||
], | ], | |||
"notFound": [ | "notFound": [ | |||
"not-a-blob" | "not-a-blob" | |||
] | ] | |||
}, | }, | |||
"R1" | "R1" | |||
] | ] | |||
5. Security considerations | 5. Security Considerations | |||
All security considerations of JMAP [RFC8620] apply to this | All security considerations for JMAP [RFC8620] apply to this | |||
specification. Additional considerations specific to the data types | specification. Additional considerations specific to the data types | |||
and functionality introduced by this document are described here. | and functionality introduced by this document are described here. | |||
JSON parsers are not all consistent in handling non-UTF-8 data. JMAP | JSON parsers are not all consistent in handling non-UTF-8 data. JMAP | |||
requires that all JSON data be UTF-8 encoded, so servers MUST only | requires that all JSON data be UTF-8 encoded, so servers MUST only | |||
return a null value if data:asText is requested for a range of octets | return a null value if data:asText is requested for a range of octets | |||
which is not valid UTF-8, and set isEncodingProblem: true. | that is not valid UTF-8 and set isEncodingProblem: true. | |||
Servers MUST apply any access controls, such that if the | Servers MUST apply any access controls, such that if the | |||
authenticated user would be unable to discover the blobId by making | authenticated user would be unable to discover the blobId by making | |||
queries, then this fact can not be discovered via a Blob/lookup. For | queries, then this fact cannot be discovered via a Blob/lookup. For | |||
example, if an Email exists in a Mailbox which the authenticated user | example, if an Email exists in a Mailbox that the authenticated user | |||
does not have access to see, then that emailId MUST NOT be returned | does not have access to see, then that emailId MUST NOT be returned | |||
in a lookup for a blob which is referenced by that email. | in a lookup for a blob that is referenced by that email. | |||
The server MUST NOT trust that the data given to a Blob/upload is a | The server MUST NOT trust that the data given to a Blob/upload is a | |||
well formed instance of the specified media type, and if the server | well-formed instance of the specified media type. Also, if the | |||
attempts to parse the given blob, only hardened parsers designed to | server attempts to parse the given blob, only hardened parsers | |||
deal with arbitrary untrusted data should be used. The server SHOULD | designed to deal with arbitrary untrusted data should be used. The | |||
NOT reject data on the grounds that it is not a valid specimen of the | server SHOULD NOT reject data on the grounds that it is not a valid | |||
stated type. | specimen of the stated type. | |||
Blob/upload with carefully chosen data sources can be used to | With carefully chosen data sources, Blob/upload can be used to | |||
recreate dangerous content on the far side of security scanners | recreate dangerous content on the far side of security scanners | |||
(anti-virus or exfiltration scanners for example) which may be | (anti-virus or exfiltration scanners, for example) that may be | |||
watching the upload endpoint. Server implementations SHOULD provide | watching the upload endpoint. Server implementations SHOULD provide | |||
a hook to allow security scanners to check the resulting blob after | a hook to allow security scanners to check the resulting blob after | |||
concatenating the data sources in the same way that they do for the | concatenating the data sources in the same way that they do for the | |||
upload endpoint. | upload endpoint. | |||
Digest algorithms can be expensive for servers to calculate. Servers | Digest algorithms can be expensive for servers to calculate. Servers | |||
which share resources between multiple users should track resource | that share resources between multiple users should track resource | |||
usage by clients, and rate-limit expensive operations to avoid | usage by clients and rate-limit expensive operations to avoid | |||
resource starvation. | resource starvation. | |||
6. IANA considerations | 6. IANA Considerations | |||
6.1. JMAP Capability registration for "blob" | ||||
IANA is requested to register the "blob" JMAP Capability as follows: | ||||
Capability Name: urn:ietf:params:jmap:blob | ||||
Specification document: this document | 6.1. JMAP Capability Registration for "blob" | |||
Intended use: common | ||||
Change Controller: IETF | IANA has registered the "blob" JMAP capability as follows: | |||
Security and privacy considerations: this document, Section XXX | Capability Name: urn:ietf:params:jmap:blob | |||
Specification document: RFC 9404 | ||||
Intended use: common | ||||
Change Controller: IETF | ||||
Security and privacy considerations: RFC 9404, Section 5 | ||||
6.2. JMAP Error Codes Registration for "unknownDataType" | 6.2. JMAP Error Codes Registration for "unknownDataType" | |||
IANA is requested to register the "unknownDataType" JMAP Error Code | IANA has registered the "unknownDataType" JMAP error code as follows: | |||
as follows: | ||||
JMAP Error Code: unknownDataType | ||||
Intended use: common | ||||
Change Controller: IETF | ||||
Reference: this document | ||||
Description: The server does not recognise this data type, or the | JMAP Error Code: unknownDataType | |||
capability to enable it was not present. | Intended use: common | |||
Change Controller: IETF | ||||
Reference: RFC 9404 | ||||
Description: The server does not recognise this data type, or the | ||||
capability to enable it is not present in the current Request | ||||
Object. | ||||
6.3. Creation of "JMAP Data Types" Registry | 6.3. Creation of "JMAP Data Types" Registry | |||
IANA is requested to create a new registry "JMAP Data Types" with the | IANA has created a new registry called "JMAP Data Types". Table 1 | |||
initial content: | shows the initial contents of this new registry. | |||
+================+=========+======+=====================================+=========+ | ||||
|Type Name |Can |Can |Capability |Reference| | ||||
| |reference|use | | | | ||||
| |blobs |for | | | | ||||
| | |state | | | | ||||
| | |change| | | | ||||
+================+=========+======+=====================================+=========+ | ||||
|Core |No |No |urn:ietf:params:jmap:core |[RFC8620]| | ||||
+----------------+---------+------+-------------------------------------+---------+ | ||||
|PushSubscription|No |No |urn:ietf:params:jmap:core |[RFC8620]| | ||||
+----------------+---------+------+-------------------------------------+---------+ | ||||
|Mailbox |Yes |Yes |urn:ietf:params:jmap:mail |[RFC8621]| | ||||
+----------------+---------+------+-------------------------------------+---------+ | ||||
|Thread |Yes |Yes |urn:ietf:params:jmap:mail |[RFC8621]| | ||||
+----------------+---------+------+-------------------------------------+---------+ | ||||
|Email |Yes |Yes |urn:ietf:params:jmap:mail |[RFC8621]| | ||||
+----------------+---------+------+-------------------------------------+---------+ | ||||
|EmailDelivery |No |Yes |urn:ietf:params:jmap:mail |[RFC8621]| | ||||
+----------------+---------+------+-------------------------------------+---------+ | ||||
|SearchSnippet |No |No |urn:ietf:params:jmap:mail |[RFC8621]| | ||||
+----------------+---------+------+-------------------------------------+---------+ | ||||
|Identity |No |Yes |urn:ietf:params:jmap:submission |[RFC8621]| | ||||
+----------------+---------+------+-------------------------------------+---------+ | ||||
|EmailSubmission |No |Yes |urn:ietf:params:jmap:submission |[RFC8621]| | ||||
+----------------+---------+------+-------------------------------------+---------+ | ||||
|VacationResponse|No |Yes |urn:ietf:params:jmap:vacationresponse|[RFC8621]| | ||||
+----------------+---------+------+-------------------------------------+---------+ | ||||
|MDN |No |No |urn:ietf:params:jmap:mdn |[RFC9007]| | ||||
+----------------+---------+------+-------------------------------------+---------+ | ||||
Table 1 | ||||
This policy for this registry is "Specification required", either an | ||||
RFC or a similarly stable reference document which defines a JMAP | ||||
Data Type and associated capability. | ||||
IANA is asked to appoint designated experts to review requests for | ||||
additions to this registry, with guidance to allow any registration | ||||
which provides a stable document describing the capability, and | ||||
control over the URI namespace where the capability URI points. | ||||
7. Changes | ||||
EDITOR: please remove this section before publication. | ||||
The source of this document exists on github at: | ||||
https://github.com/brong/draft-gondwana-jmap-blob/ | ||||
(https://github.com/brong/draft-gondwana-jmap-blob/) | ||||
*draft-ietf-jmap-blob-18* | ||||
* add security considerations for Digest algorithm performance (was | ||||
supposed to be in -13 but I had a commit that never got pushed) | ||||
* artart review: | ||||
- clarify that created blobs behave identically to RFC8620 | ||||
section 6 binary objects. | ||||
- clearer text about "references a blob" | ||||
- remove contractions | ||||
* Roman Danyliw DISCUSS | ||||
- corrected example text - missing comma and extra data:asBase64. | ||||
- simplify Blob/lookup to not have multiple ways of saying "not | ||||
found" for a blob and then need a security considerations | ||||
around it. | ||||
- said that clients SHOULD prefer algorithms earlier in the list. | ||||
- clarified that supportedTypeNames could include private | ||||
extensions. | ||||
- editorial/spelling fixes | ||||
* genart review | ||||
- editorial/spelling fixes | ||||
* Robert Winton review | ||||
- added a suggestion to use the regular upload mechanism for | ||||
blobs over a megabyte in size. | ||||
*draft-ietf-jmap-blob-17* | ||||
* AD review, one more wording nit | ||||
*draft-ietf-jmap-blob-16* | ||||
* secdir last-call review changes - nit fixes and security | ||||
considerations | ||||
*draft-ietf-jmap-blob-15* | ||||
* changed capabilities object to MUST contain all specified keys, to | ||||
align with all other published JMAP extensions. | ||||
*draft-ietf-jmap-blob-14* | ||||
* AD review - fixed MUST usage | ||||
* AD review - added instructions regarding expert review for IANA | ||||
*draft-ietf-jmap-blob-13* | ||||
* added examples of digest responses | ||||
*draft-ietf-jmap-blob-12* | ||||
* updates based on Neil Jenkins' feedback: | ||||
- fixed [] positions for type specs | ||||
- documented delta between /upload and /set better | ||||
- allowed zero-length blobId sources | ||||
- fixed examples with /set leftovers | ||||
- documented datatypes registry policy | ||||
* added optional "digest" support | ||||
*draft-ietf-jmap-blob-11*: | ||||
* updates based on IETF113 feedback: | ||||
- added wording to suggest the a Blob/get of just size might be | ||||
faster | ||||
- added an example with just the size field being selected | ||||
*draft-ietf-jmap-blob-10*: | ||||
* removed remaining references to catenate. | ||||
*draft-ietf-jmap-blob-09*: | ||||
* tidied up introduction text | ||||
* replaced Blob/set with Blob/upload | ||||
* made all upload creates take an array of sources to normalise | ||||
behaviour at the cost of a slightly more complex default case. | ||||
*draft-ietf-jmap-blob-08*: | ||||
* Fixed spelling of Neil's name in acknowledgements | ||||
* Last call review (thanks Jim Fenton) | ||||
- fixed mmark sillyness causing RFC8620 to be non-normative in | ||||
the references | ||||
- clarified the capability object and accountCapability object | ||||
requirements | ||||
- made capability keys much more tightly defined, with mandatory | ||||
minimum catenate limit and default values. | ||||
- increased use of normative language generally | ||||
- lowercased 'blob' anywhere it wasn't explicitly the object | ||||
- lowercased titles of the columns in the registry | ||||
*draft-ietf-jmap-blob-07*: | ||||
* more examples to cover the interactions of offset, length and | ||||
encoding checks. | ||||
*draft-ietf-jmap-blob-06*: | ||||
* removed asHex - we only need base64 and text | ||||
* added reference to where base64 is defined | ||||
* made 'destroy' not be allowed | ||||
* expanded JSON examples for readability | ||||
* removed 'expires' from examples | ||||
*draft-ietf-jmap-blob-05*: | ||||
* discovered I hadn't actually included typeNames and matchedIds | +================+=====+=======+=========================+=========+ | |||
anywhere except the updates section, oops! | |Type Name |Can |Can Use|Capability |Reference| | |||
* added a catenate example | | |Ref |for | | | | |||
* tightened up some text | | |Blobs|State | | | | |||
| | |Change | | | | ||||
+================+=====+=======+=========================+=========+ | ||||
|Core |No |No |urn:ietf:params:jmap:core|[RFC8620]| | ||||
+----------------+-----+-------+-------------------------+---------+ | ||||
|PushSubscription|No |No |urn:ietf:params:jmap:core|[RFC8620]| | ||||
+----------------+-----+-------+-------------------------+---------+ | ||||
|Mailbox |Yes |Yes |urn:ietf:params:jmap:mail|[RFC8621]| | ||||
+----------------+-----+-------+-------------------------+---------+ | ||||
|Thread |Yes |Yes |urn:ietf:params:jmap:mail|[RFC8621]| | ||||
+----------------+-----+-------+-------------------------+---------+ | ||||
|Email |Yes |Yes |urn:ietf:params:jmap:mail|[RFC8621]| | ||||
+----------------+-----+-------+-------------------------+---------+ | ||||
|EmailDelivery |No |Yes |urn:ietf:params:jmap:mail|[RFC8621]| | ||||
+----------------+-----+-------+-------------------------+---------+ | ||||
|SearchSnippet |No |No |urn:ietf:params:jmap:mail|[RFC8621]| | ||||
+----------------+-----+-------+-------------------------+---------+ | ||||
|Identity |No |Yes |urn:ietf:params:jmap: |[RFC8621]| | ||||
| | | |submission | | | ||||
+----------------+-----+-------+-------------------------+---------+ | ||||
|EmailSubmission |No |Yes |urn:ietf:params:jmap: |[RFC8621]| | ||||
| | | |submission | | | ||||
+----------------+-----+-------+-------------------------+---------+ | ||||
|VacationResponse|No |Yes |urn:ietf:params:jmap: |[RFC8621]| | ||||
| | | |vacationresponse | | | ||||
+----------------+-----+-------+-------------------------+---------+ | ||||
|MDN |No |No |urn:ietf:params:jmap:mdn |[RFC9007]| | ||||
+----------------+-----+-------+-------------------------+---------+ | ||||
*draft-ieft-jmap-blob-04*: | Table 1 | |||
* added security considerations for scanning catenate results | The registration policy for this registry is "Specification Required" | |||
[RFC8126]. Either an RFC or a similarly stable reference document | ||||
defines a JMAP Data Type and associated capability. | ||||
*draft-ieft-jmap-blob-03*: | IANA will appoint designated experts to review requests for additions | |||
to this registry, with guidance to allow any registration that | ||||
provides a stable document describing the capability and control over | ||||
the URI namespace to which the capability URI points. | ||||
* added capabilities object | 7. References | |||
* renamed types to typeNames and matchedIds | ||||
* added details of how to handle non-UTF8 data and truncation in | ||||
Blob/get | ||||
* added isTruncated and isEncodingProblem to Blob/get to tell the | ||||
client if the request wasn't entirely satisfied. | ||||
*draft-ieft-jmap-blob-02*: | 7.1. Normative References | |||
* fixed incorrect RFC number in reference and HTTP PUT -> POST, | [RFC2119] Bradner, S., "Key words for use in RFCs to Indicate | |||
thanks Ken. | Requirement Levels", BCP 14, RFC 2119, | |||
* added acknowledgements section | DOI 10.17487/RFC2119, March 1997, | |||
* removed all 'datatype' text and changed to 'data type' or 'type | <https://www.rfc-editor.org/info/rfc2119>. | |||
name' as appropriate (issue #1 proposal) | ||||
* expanded security considerations section and moved optional Blob/ | ||||
lookup empty case into Blob/lookup section | ||||
*draft-ieft-jmap-blob-01*: | [RFC3230] Mogul, J. and A. Van Hoff, "Instance Digests in HTTP", | |||
RFC 3230, DOI 10.17487/RFC3230, January 2002, | ||||
<https://www.rfc-editor.org/info/rfc3230>. | ||||
* renamed 'datatypes' to 'types' to align with PushSubscription from | [RFC4648] Josefsson, S., "The Base16, Base32, and Base64 Data | |||
RFC8620. | Encodings", RFC 4648, DOI 10.17487/RFC4648, October 2006, | |||
* added example for Blob/get | <https://www.rfc-editor.org/info/rfc4648>. | |||
* specified offset and length precisely | ||||
*draft-ieft-jmap-blob-00*: | [RFC8174] Leiba, B., "Ambiguity of Uppercase vs Lowercase in RFC | |||
2119 Key Words", BCP 14, RFC 8174, DOI 10.17487/RFC8174, | ||||
May 2017, <https://www.rfc-editor.org/info/rfc8174>. | ||||
* initial adoption as an IETF document, otherwise identical to | [RFC8620] Jenkins, N. and C. Newman, "The JSON Meta Application | |||
draft-gondwana-jmap-blob-02 | Protocol (JMAP)", RFC 8620, DOI 10.17487/RFC8620, July | |||
2019, <https://www.rfc-editor.org/info/rfc8620>. | ||||
*draft-gondwana-jmap-blob-02* | 7.2. Informative References | |||
* renamed 'objects' to 'datatypes' | ||||
* specified Blob/lookup | ||||
* added IANA registry for datatypes | ||||
*draft-gondwana-jmap-blob-01* | [RFC7888] Melnikov, A., Ed., "IMAP4 Non-synchronizing Literals", | |||
RFC 7888, DOI 10.17487/RFC7888, May 2016, | ||||
<https://www.rfc-editor.org/info/rfc7888>. | ||||
* added an example | [RFC8126] Cotton, M., Leiba, B., and T. Narten, "Guidelines for | |||
Writing an IANA Considerations Section in RFCs", BCP 26, | ||||
RFC 8126, DOI 10.17487/RFC8126, June 2017, | ||||
<https://www.rfc-editor.org/info/rfc8126>. | ||||
*draft-gondwana-jmap-blob-00* | [RFC8621] Jenkins, N. and C. Newman, "The JSON Meta Application | |||
Protocol (JMAP) for Mail", RFC 8621, DOI 10.17487/RFC8621, | ||||
August 2019, <https://www.rfc-editor.org/info/rfc8621>. | ||||
* initial proposal | [RFC9007] Ouazana, R., Ed., "Handling Message Disposition | |||
Notification with the JSON Meta Application Protocol | ||||
(JMAP)", RFC 9007, DOI 10.17487/RFC9007, March 2021, | ||||
<https://www.rfc-editor.org/info/rfc9007>. | ||||
8. Acknowledgements | Acknowledgements | |||
Joris Baum, Jim Fenton, Neil Jenkins, Alexey Melnikov, Ken Murchison, | Joris Baum, Jim Fenton, Neil Jenkins, Alexey Melnikov, Ken Murchison, | |||
Robert Stepanek and the JMAP working group at the IETF. | Robert Stepanek, and the JMAP Working Group in the IETF. | |||
9. Normative References | ||||
[RFC2119] Bradner, S. and RFC Publisher, "Key words for use in RFCs | ||||
to Indicate Requirement Levels", BCP 14, RFC 2119, | ||||
DOI 10.17487/RFC2119, March 1997, | ||||
<https://www.rfc-editor.org/info/rfc2119>. | ||||
[RFC3230] Mogul, J., Van Hoff, A., and RFC Publisher, "Instance | ||||
Digests in HTTP", RFC 3230, DOI 10.17487/RFC3230, January | ||||
2002, <https://www.rfc-editor.org/info/rfc3230>. | ||||
[RFC4648] Josefsson, S. and RFC Publisher, "The Base16, Base32, and | ||||
Base64 Data Encodings", RFC 4648, DOI 10.17487/RFC4648, | ||||
October 2006, <https://www.rfc-editor.org/info/rfc4648>. | ||||
[RFC8174] Leiba, B. and RFC Publisher, "Ambiguity of Uppercase vs | ||||
Lowercase in RFC 2119 Key Words", BCP 14, RFC 8174, | ||||
DOI 10.17487/RFC8174, May 2017, | ||||
<https://www.rfc-editor.org/info/rfc8174>. | ||||
[RFC8620] Jenkins, N., Newman, C., and RFC Publisher, "The JSON Meta | ||||
Application Protocol (JMAP)", RFC 8620, | ||||
DOI 10.17487/RFC8620, July 2019, | ||||
<https://www.rfc-editor.org/info/rfc8620>. | ||||
10. Informative References | ||||
[RFC7888] Melnikov, A., Ed. and RFC Publisher, "IMAP4 Non- | ||||
synchronizing Literals", RFC 7888, DOI 10.17487/RFC7888, | ||||
May 2016, <https://www.rfc-editor.org/info/rfc7888>. | ||||
[RFC8621] Jenkins, N., Newman, C., and RFC Publisher, "The JSON Meta | ||||
Application Protocol (JMAP) for Mail", RFC 8621, | ||||
DOI 10.17487/RFC8621, August 2019, | ||||
<https://www.rfc-editor.org/info/rfc8621>. | ||||
Author's Address | Author's Address | |||
Bron Gondwana (editor) | Bron Gondwana (editor) | |||
Fastmail | Fastmail | |||
Level 2, 114 William St | Level 2, 114 William St | |||
Melbourne VIC 3000 | Melbourne VIC 3000 | |||
Australia | Australia | |||
Email: brong@fastmailteam.com | Email: brong@fastmailteam.com | |||
URI: https://www.fastmail.com | URI: https://www.fastmail.com | |||
End of changes. 173 change blocks. | ||||
670 lines changed or deleted | 522 lines changed or added | |||
This html diff was produced by rfcdiff 1.48. |