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.