rfc-9404

JSON Meta Application Protocol (JMAP) Blob Management Extension

B. Gondwana (Editor)
date2023-08 streamIETF areaart wgjmap statusPROPOSED STANDARD pages24 canonicalhttps://www.rfc-editor.org/rfc/rfc9404 doi10.17487/RFC9404
The JSON Meta Application Protocol (JMAP) base protocol (RFC 8620) provides the ability to upload and download arbitrary binary data via 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 making inline method calls within a standard JMAP request. This extension also adds a reverse lookup mechanism to discover where blobs are referenced within other data types.

updates

Extracted elements (29)

design-rationale §1

Embedding blobs inline in JMAP method calls is analogous to IMAP literals extended by RFC 7888, reducing round trips. Base64 encoding (RFC 4648) is used for both creating and fetching blob data because raw blobs may contain arbitrary binary data that cannot be directly embedded in JSON.

json

design-rationale §4.3

The definition of 'reference' in Blob/lookup is intentionally loose: it means 'you could discover this blobId by looking at this object or at other objects recursively contained within it'. For example, a Thread references a blobId if any Email in that Thread does, but an Email referencing a Mailbox does not inherit all blobs referenced by other Emails in that Mailbox.

json

interoperability-note §4

This document updates RFC 8620. Blob/copy defined in RFC 8620 is unchanged and remains selected by urn:ietf:params:jmap:core; the new Blob/upload, Blob/get, and Blob/lookup methods are selected only by urn:ietf:params:jmap:blob.

json

normative-requirement §3.1 MUST NOT

Clients MUST NOT attempt to create blobs larger than maxSizeBlobSet. If maxSizeBlobSet is null, clients are not required to limit blob size, though servers may still reject any creation.

json

normative-requirement §4.1 SHOULD

Clients SHOULD use the upload mechanism defined by RFC 8620 for blobs larger than one megabyte, since Blob/upload via inline method calls is restricted by the server's maxUploadSize limit for overall JMAP requests.

json, http

normative-requirement §3.1 MUST

Digest algorithm names in supportedDigestAlgorithms MUST be present in the HTTP Digest Algorithm Values registry (RFC 3230) but MUST be lowercased in JMAP (e.g., 'sha-256' not 'SHA-256'). Clients SHOULD prefer algorithms listed earlier in the array.

json, http

normative-requirement §4.3 MUST

If a blob is not visible to a user or does not exist at all, the server MUST still return an empty array for each type in a Blob/lookup response, so as not to leak information about whether the blob exists but is inaccessible to the requester.

json, privacy, security

normative-requirement §4.1 MUST

If a blobId DataSourceObject's range cannot be fully satisfied (begins or extends past the end of the blob), the DataSourceObject is invalid and MUST result in a notCreated response. Servers MUST add a createdIds entry for each successful Blob/upload so the blobId is available via back-reference in subsequent method calls.

json

normative-requirement §4.2 MUST

If requested octets are not valid UTF-8 and data or data:asText was requested, isEncodingProblem MUST be set to true and data:asText MUST be null. When data was requested and data is not valid UTF-8, data:asBase64 MUST be returned instead.

json

normative-requirement §4.1 MUST NOT

If the data properties have any invalid references or invalid data (including invalid base64 in data:asBase64 or invalid UTF-8 in data:asText), the server MUST NOT guess the user's intent and MUST reject the creation, returning a notCreated response for that creation id.

json, security

normative-requirement §4.2 MUST

If the requested offset+length extends beyond the blob, the server returns available octets and MUST set isTruncated to true. If offset is past the end, an empty string is returned with isTruncated true. Any digest is calculated on the octets that would be returned for a data field.

json

normative-requirement §3.1 MUST

Servers MUST allow at least 64 DataSourceObjects per Blob/upload creation. This minimum is stated in both the capability description and the Blob/upload method definition.

json

normative-requirement §4.2 SHOULD

Servers SHOULD store blob sizes in a format efficient to read, and clients SHOULD limit requests to just the size parameter when that is all they need, since fetching blob content may be significantly more expensive and slower.

json

normative-requirement §3.1 MUST

Servers that include urn:ietf:params:jmap:blob in one or more accountCapabilities MUST also include it in the top-level session capabilities property. The session-level value MUST be an empty object.

json

normative-requirement §4.2 MUST

The size value in a Blob/get response MUST always be the number of octets in the underlying blob, regardless of the offset and length parameters used in the request.

json

protocol-element §4.2

Blob/get is a standard JMAP get extended with two optional parameters: offset (UnsignedInt|null, default 0) to start reading into the blob, and length (UnsignedInt|null) to limit how many octets are returned. Request properties include data:asText, data:asBase64, data, digest:<algorithm>, and size.

json

protocol-element §4.3

Blob/lookup takes accountId, typeNames (String[]), and ids (Id[]) and performs a reverse lookup to find which objects of each named data type reference each blobId. The response contains a list of BlobInfo objects each with id and matchedIds (a map from type name to Id[]).

json

protocol-element §4.1

Blob/upload accepts accountId and a create map of Id to UploadObject. It behaves like Foo/set but permits only creation (no update or delete); the response has no state field. Created objects include id (blobId), type (String|null), and size (UnsignedInt).

json

protocol-element §3.1

The blob capability object in accountCapabilities contains four fields: maxSizeBlobSet (UnsignedInt|null, max blob octets), maxDataSources (UnsignedInt, max DataSourceObjects per create), supportedTypeNames (String[], types available for Blob/lookup), and supportedDigestAlgorithms (String[], algorithms available for Blob/get digest).

json

protocol-element §3.1

The urn:ietf:params:jmap:blob capability, when present in accountCapabilities, signals support for Blob/upload, Blob/get, and Blob/lookup methods. Its value in the session-level capabilities MUST be an empty object; in account capabilities it carries server limits and supported features.

json, registry

registry §6.3

RFC 9404 creates the 'JMAP Data Types' IANA registry with registration policy 'Specification Required'. Initial entries include Core, PushSubscription, Mailbox, Thread, Email, EmailDelivery, SearchSnippet, Identity, EmailSubmission, VacationResponse, and MDN, each with 'Can Ref Blobs', 'Can Use for State Change', and associated capability columns.

registry, json, email

registry §6.1

RFC 9404 registers the JMAP capability urn:ietf:params:jmap:blob with IANA under intended use 'common', with security and privacy considerations in Section 5.

registry, json

registry §6.2

RFC 9404 registers the JMAP error code 'unknownDataType' with IANA. This error is returned when a server does not recognise the data type specified in a Blob/lookup typeNames list, or the capability enabling that type is absent from the current Request Object.

registry, json

security-consideration §5 SHOULD

Blob/upload with carefully chosen data sources can be used to reassemble dangerous content on the far side of security scanners (anti-virus, exfiltration scanners) watching the upload endpoint. Server implementations SHOULD provide a hook for security scanners to inspect the fully concatenated resulting blob.

security, json

security-consideration §5 SHOULD

Digest algorithms can be computationally expensive. Servers that share resources among multiple users should track per-client resource usage and rate-limit expensive digest operations to prevent resource starvation.

security, json

security-consideration §5 MUST

JSON parsers are not consistent in handling non-UTF-8 data. Because JMAP requires all JSON to be UTF-8, servers MUST return null for data:asText and set isEncodingProblem: true rather than attempting to return non-UTF-8 octets directly in a JSON string.

security, json

security-consideration §5 MUST

Servers MUST apply access controls so that a Blob/lookup cannot reveal blobIds from objects (e.g., emails in inaccessible mailboxes) that the authenticated user would not be able to discover through normal queries. Access-controlled IDs MUST NOT appear in lookup responses.

security, json

security-consideration §5 MUST NOT

The server MUST NOT trust that data given to Blob/upload is a well-formed instance of the specified media type. If the server parses the blob, it MUST use only hardened parsers designed for arbitrary untrusted data. The server SHOULD NOT reject data solely because it is not a valid specimen of the stated media type.

security, json

wire-format §4.1

UploadObject has a data field (DataSourceObject[]) and an optional type field (String|null). DataSourceObject contains exactly one of: data:asText (UTF-8 string), data:asBase64 (base64 string), or a blobId source with optional offset (UnsignedInt|null) and length (UnsignedInt|null) fields.

json