idnits 2.17.1 draft-ietf-jmap-core-03.txt: Checking boilerplate required by RFC 5378 and the IETF Trust (see https://trustee.ietf.org/license-info): ---------------------------------------------------------------------------- No issues found here. Checking nits according to https://www.ietf.org/id-info/1id-guidelines.txt: ---------------------------------------------------------------------------- No issues found here. Checking nits according to https://www.ietf.org/id-info/checklist : ---------------------------------------------------------------------------- ** The document seems to lack an IANA Considerations section. (See Section 2.2 of https://www.ietf.org/id-info/checklist for how to handle the case when there are no actions for IANA.) ** There are 2 instances of too long lines in the document, the longest one being 34 characters in excess of 72. Miscellaneous warnings: ---------------------------------------------------------------------------- == The copyright year in the IETF Trust and authors Copyright Line does not match the current year -- The document date (November 29, 2017) is 2333 days in the past. Is this intentional? -- Found something which looks like a code comment -- if you have code sections in the document, please surround them with '' and '' lines. Checking references for intended status: Proposed Standard ---------------------------------------------------------------------------- (See RFCs 3967 and 4897 for information about using normative references to lower-maturity documents in RFCs) -- Looks like a reference, but probably isn't: '1' on line 2002 == Unused Reference: 'RFC2047' is defined on line 1915, but no explicit reference was found in the text == Unused Reference: 'RFC2231' is defined on line 1925, but no explicit reference was found in the text ** Obsolete normative reference: RFC 5246 (Obsoleted by RFC 8446) ** Obsolete normative reference: RFC 5785 (Obsoleted by RFC 8615) ** Obsolete normative reference: RFC 7159 (Obsoleted by RFC 8259) ** Obsolete normative reference: RFC 7230 (Obsoleted by RFC 9110, RFC 9112) ** Obsolete normative reference: RFC 7235 (Obsoleted by RFC 9110) Summary: 7 errors (**), 0 flaws (~~), 3 warnings (==), 3 comments (--). Run idnits with the --verbose option for more detailed information about the items above. -------------------------------------------------------------------------------- 2 JMAP N. Jenkins 3 Internet-Draft FastMail 4 Intended status: Standards Track November 29, 2017 5 Expires: June 2, 2018 7 JSON Meta Application Protocol 8 draft-ietf-jmap-core-03 10 Abstract 12 This document specifies a protocol for synchronising JSON-based data 13 objects efficiently, with support for push and out-of-band binary 14 data upload/download. 16 Status of This Memo 18 This Internet-Draft is submitted in full conformance with the 19 provisions of BCP 78 and BCP 79. 21 Internet-Drafts are working documents of the Internet Engineering 22 Task Force (IETF). Note that other groups may also distribute 23 working documents as Internet-Drafts. The list of current Internet- 24 Drafts is at https://datatracker.ietf.org/drafts/current/. 26 Internet-Drafts are draft documents valid for a maximum of six months 27 and may be updated, replaced, or obsoleted by other documents at any 28 time. It is inappropriate to use Internet-Drafts as reference 29 material or to cite them other than as "work in progress." 31 This Internet-Draft will expire on June 2, 2018. 33 Copyright Notice 35 Copyright (c) 2017 IETF Trust and the persons identified as the 36 document authors. All rights reserved. 38 This document is subject to BCP 78 and the IETF Trust's Legal 39 Provisions Relating to IETF Documents 40 (https://trustee.ietf.org/license-info) in effect on the date of 41 publication of this document. Please review these documents 42 carefully, as they describe your rights and restrictions with respect 43 to this document. Code Components extracted from this document must 44 include Simplified BSD License text as described in Section 4.e of 45 the Trust Legal Provisions and are provided without warranty as 46 described in the Simplified BSD License. 48 Table of Contents 50 1. Introduction . . . . . . . . . . . . . . . . . . . . . . . . 3 51 1.1. Notational conventions . . . . . . . . . . . . . . . . . 3 52 1.2. The Number datatype . . . . . . . . . . . . . . . . . . . 4 53 1.3. The Date datatypes . . . . . . . . . . . . . . . . . . . 4 54 1.4. JSON as the data encoding format . . . . . . . . . . . . 4 55 1.5. Terminology . . . . . . . . . . . . . . . . . . . . . . . 5 56 1.5.1. User . . . . . . . . . . . . . . . . . . . . . . . . 5 57 1.5.2. Accounts . . . . . . . . . . . . . . . . . . . . . . 5 58 1.5.3. Data types and records . . . . . . . . . . . . . . . 5 59 1.6. Ids . . . . . . . . . . . . . . . . . . . . . . . . . . . 5 60 1.7. The JMAP API model . . . . . . . . . . . . . . . . . . . 6 61 2. The JMAP session resource . . . . . . . . . . . . . . . . . . 6 62 2.1. Service Autodiscovery . . . . . . . . . . . . . . . . . . 9 63 3. Structured data exchange . . . . . . . . . . . . . . . . . . 9 64 3.1. Making an API request . . . . . . . . . . . . . . . . . . 10 65 3.2. The Request object . . . . . . . . . . . . . . . . . . . 10 66 3.2.1. Example request . . . . . . . . . . . . . . . . . . . 10 67 3.3. Vendor-specific extensions . . . . . . . . . . . . . . . 11 68 3.4. The Response object . . . . . . . . . . . . . . . . . . . 11 69 3.4.1. Example response: . . . . . . . . . . . . . . . . . . 11 70 3.5. Omitting arguments . . . . . . . . . . . . . . . . . . . 12 71 3.6. Errors . . . . . . . . . . . . . . . . . . . . . . . . . 12 72 3.7. References to previous method results . . . . . . . . . . 13 73 3.8. Security . . . . . . . . . . . . . . . . . . . . . . . . 18 74 3.9. Concurrency . . . . . . . . . . . . . . . . . . . . . . . 18 75 4. Standard methods and naming convention . . . . . . . . . . . 18 76 4.1. getFoos . . . . . . . . . . . . . . . . . . . . . . . . . 19 77 4.2. getFooUpdates . . . . . . . . . . . . . . . . . . . . . . 20 78 4.3. setFoos . . . . . . . . . . . . . . . . . . . . . . . . . 22 79 4.3.1. Example . . . . . . . . . . . . . . . . . . . . . . . 27 80 4.4. getFooList . . . . . . . . . . . . . . . . . . . . . . . 29 81 4.5. getFooListUpdates . . . . . . . . . . . . . . . . . . . . 32 82 5. Binary data . . . . . . . . . . . . . . . . . . . . . . . . . 34 83 5.1. Uploading binary data . . . . . . . . . . . . . . . . . . 35 84 5.2. Downloading binary data . . . . . . . . . . . . . . . . . 36 85 6. Push . . . . . . . . . . . . . . . . . . . . . . . . . . . . 36 86 6.1. The StateChange object . . . . . . . . . . . . . . . . . 37 87 6.2. PushSubscription . . . . . . . . . . . . . . . . . . . . 37 88 6.2.1. setPushSubscription . . . . . . . . . . . . . . . . . 39 89 6.2.2. getPushSubscription . . . . . . . . . . . . . . . . . 39 90 6.3. Event Source . . . . . . . . . . . . . . . . . . . . . . 39 91 7. Security considerations . . . . . . . . . . . . . . . . . . . 41 92 7.1. Transport confidentiality . . . . . . . . . . . . . . . . 41 93 7.2. Authentication scheme . . . . . . . . . . . . . . . . . . 41 94 7.3. Service autodiscovery . . . . . . . . . . . . . . . . . . 41 95 7.4. JSON parsing . . . . . . . . . . . . . . . . . . . . . . 41 96 7.5. Denial of service . . . . . . . . . . . . . . . . . . . . 41 97 7.6. Push encryption . . . . . . . . . . . . . . . . . . . . . 42 98 8. References . . . . . . . . . . . . . . . . . . . . . . . . . 42 99 8.1. Normative References . . . . . . . . . . . . . . . . . . 42 100 8.2. URIs . . . . . . . . . . . . . . . . . . . . . . . . . . 44 101 Author's Address . . . . . . . . . . . . . . . . . . . . . . . . 44 103 1. Introduction 105 JMAP is a generic protocol for synchronising data, such as mail, 106 calendars or contacts, between a client and a server. It is 107 optimised for mobile and web environments, and aims to provide a 108 consistent interface to different data types. 110 This specification is for the generic mechanism of data 111 synchronisation. Further specifications define the data models for 112 different data types that may be synchronised via JMAP. 114 JMAP is designed to make efficient use of limited network resources. 115 Multiple API calls may be batched in a single request to the server, 116 reducing round trips and improving battery life on mobile devices. 117 Push connections remove the need for polling, and an efficient delta 118 update mechanism ensures a minimum of data is transferred. 120 JMAP is designed to be horizontally scalable to a very large number 121 of users. This is facilitated by the separate end points for users 122 after login, the separation of binary and structured data, and a 123 shared data model that does not allow data dependencies between 124 accounts. 126 1.1. Notational conventions 128 The key words "MUST", "MUST NOT", "REQUIRED", "SHALL", "SHALL NOT", 129 "SHOULD", "SHOULD NOT", "RECOMMENDED", "MAY", and "OPTIONAL" in this 130 document are to be interpreted as described in [RFC2119]. 132 The underlying format used for this specification is JSON. 133 Consequently, the terms "object" and "array" as well as the four 134 primitive types (strings, numbers, booleans, and null) are to be 135 interpreted as described in Section 1 of [RFC7159]. Unless otherwise 136 noted, all the property names and values are case sensitive. 138 Some examples in this document contain "partial" JSON documents used 139 for illustrative purposes. In these examples, three periods "..." 140 are used to indicate a portion of the document that has been removed 141 for compactness. 143 Types signatures are given for all JSON objects in this document. 144 The following conventions are used: 146 o "Boolean|String" - The value is either a JSON "Boolean" value, or 147 a JSON "String" value. 149 o "Foo" - Any name that is not a native JSON type means an object 150 for which the properties (and their types) are defined elsewhere 151 within this document. 153 o "Foo[]" - An array of objects of type "Foo". 155 o "String[Foo]" - A JSON "Object" being used as a map (associative 156 array), where all the values are of type "Foo". 158 1.2. The Number datatype 160 The JSON datatypes are limited to those found in JavaScript. A 161 "Number" in JavaScript is represented as a signed double (64-bit 162 floating point). However, except where explicitly specified, all 163 numbers used in this API are unsigned integers <= 2^53 (the maximum 164 integer that may be reliably stored in a double). 166 1.3. The Date datatypes 168 Where "Date" is given as a type, it means a string in [RFC3339] 169 _date-time_ format. To ensure a normalised form, the _time-secfrac_ 170 MUST always be omitted and any letters in the string (e.g. "T" and 171 "Z") MUST be upper-case. For example, ""2014-10-30T14:12:00+08:00"". 173 Where "UTCDate" is given as a type, it means a "Date" where the 174 _time-offset_ component MUST be "Z" (i.e. it must be in UTC time). 175 For example, ""2014-10-30T06:12:00Z"". 177 1.4. JSON as the data encoding format 179 JSON is a text-based data interchange format as specified in 180 [RFC7159]. The I-JSON format defined in [RFC7493] is a strict subset 181 of this, adding restrictions to avoid potentially confusing scenarios 182 (for example, it mandates that an object MUST NOT have two properties 183 with the same key). 185 All data sent from the client to the server or from the server to the 186 client (except binary file upload/download) MUST be valid I-JSON 187 according to the RFC, and is therefore case-sensitive and encoded in 188 UTF-8 ([RFC3629]). 190 1.5. Terminology 192 1.5.1. User 194 A user represents a set of permissions relating to what data can be 195 seen. 197 1.5.2. Accounts 199 An account is a collection of data. 201 All data, other than the Account objects themselves, belong to a 202 single account. A single account may contain an arbitrary set of 203 data, for example a collection of mail, contacts and calendars. Most 204 operations in JMAP are isolated to a single account; there are a few 205 explicit operations to copy data between them. Certain properties 206 are guaranteed for data within the same account, for example 207 uniqueness of ids within a type in that account. 209 An account is not the same as a user, although it is common for the 210 primary account to directly belong to the user. For example, you may 211 have an account that contains data for a group or business, to which 212 multiple users have access. Users may also have access to accounts 213 belonging to another user if that user is sharing some of their data. 215 1.5.3. Data types and records 217 JMAP provides a uniform interface for creating, retrieving, updating 218 and deleting various types of objects. A *data type* is a collection 219 of named, typed properties, just like the schema for a database 220 table. Each instance of a data type is called a *record*. 222 1.6. Ids 224 All object ids are assigned by the server, and are immutable. They 225 MUST be unique among all objects of the *same type* within the *same 226 account*. Ids may clash across accounts, or for two objects of 227 different types within the same account. 229 Ids are always "String"s. An id MUST be a valid UTF-8 string of at 230 least 1 character in length and maximum 256 bytes in size, but MUST 231 NOT start with the "#" character, as this is reserved for doing back 232 references during object creation (see the _setFoos_ description). 234 1.7. The JMAP API model 236 JMAP uses HTTP [RFC7230] to expose API, Push, Upload and Download 237 resources. Implementations MUST support HTTP/1.1, and MAY support 238 later versions. Support for common HTTP mechanisms such as 239 redirection and caching are assumed. 241 All HTTP requests MUST be authenticated. Servers MUST conform with 242 the [RFC7235] HTTP Authentication framework to reject requests that 243 fail authentication and inform the client of available authentication 244 schemes. 246 Clients SHOULD understand and be able to handle standard HTTP status 247 codes appropriately. 249 An authenticated client can fetch the JMAP session object with 250 details about the data and capabilities the server can provide as 251 shown in section 2. The client may then exchange data with the 252 server using four different mechanisms: 254 1. The client may make an API request to the server to get or set 255 structured data. This request consists of an ordered series of 256 method calls. These are processed by the server, which then 257 returns an ordered series of responses. This is described in 258 section 3. 260 2. The client may download binary files from the server. This is 261 detailed in section 4. 263 3. The client may upload binary files to the server. This is 264 specified in section 5. 266 4. The client may connect to a push channel on the server, to be 267 notified when data has changed. This is explained in section 6. 269 2. The JMAP session resource 271 To communicate with a JMAP server you need two things to start: 273 1. The URL for the JMAP session resource. This may be requested 274 directly from the user, or discovered automatically based on a 275 username domain (see Service Autodiscovery section below). 277 2. Credentials to authenticate with. How to obtain credentials is 278 out of scope for this specification. 280 An authenticated GET request to the JMAP session resource MUST return 281 the details about the data and capabilities the server can provide to 282 the client given those credentials. 284 The response to a successful request is a JSON object with the 285 following properties: 287 o *username*: "String" The username associated with the given 288 credentials. 290 o *accounts*: "String[Account]" A map of *account id* to Account 291 object for each account the user has access to. A single set of 292 credentials may provide access to multiple accounts, for example 293 if another user is sharing their mail with the logged in user, or 294 if there is an account that contains data for a group or business. 295 All data belongs to a single account. With the exception of a few 296 explicit operations to copy data between accounts, all JMAP 297 methods take an _accountId_ argument that specifies on which 298 account the operations are to take place. This argument is always 299 optional; if not specified, the primary account is used. All ids 300 (other than Account ids of course) are only unique within their 301 account. In the event of a severe internal error, a server may 302 have to reallocate ids or do something else that violates standard 303 JMAP data constraints. In this situation, the data on the server 304 is no longer compatible with cached data the client may have from 305 before. The server MUST treat this as though the account has been 306 deleted and then recreated with a new account id. Clients will 307 then be forced to throw away any data with the old account id and 308 refetch all data from scratch. An *Account* object has the 309 following properties: 311 * *name*: "String" A user-friendly string to show when presenting 312 content from this account, e.g. the email address representing 313 the owner of the account. 315 * *isPrimary*: "Boolean" This MUST be true for *at most* one of 316 the accounts returned. This is to be considered the user's 317 main or default account by the client. If no account being 318 returned belongs to the user, or in any other way there is no 319 appropriate way to determine a default account, then this MAY 320 be "false" for all accounts. 322 * *isReadOnly*: "Boolean" This is "true" if the entire account is 323 read-only. 325 * *hasDataFor*: "String[]" A list of the data profiles available 326 in this account. Each future JMAP data types specification 327 will define a profile name to encompass that set of types. 329 o *capabilities*: "String[Object]" An object specifying the 330 capabilities of this server. Each key is a URI for a 331 specification supported by the server. The value for each of 332 these keys is an object with further information about the 333 server's capabilities in relation to that specification. The 334 client MUST ignore any properties it does not understand. The 335 capabilities object MUST include a property called "ietf:jmap". 336 The value of this property is an object which MUST contain the 337 following information on server capabilities: 339 * *maxSizeUpload*: "Number" The maximum file size, in bytes, that 340 the server will accept for a single file upload (for any 341 purpose). 343 * *maxConcurrentUpload*: "Number" The maximum number of 344 concurrent requests the server will accept to the upload 345 endpoint. 347 * *maxSizeRequest*: "Number" The maximum size, in bytes, that the 348 server will accept for a single request to the API endpoint. 350 * *maxConcurrentRequests*: "Number" The maximum number of 351 concurrent requests the server will accept to the API endpoint. 353 * *maxCallsInRequest*: "Number" The maximum number of method 354 calls the server will accept in a single request to the API 355 endpoint. 357 * *maxObjectsInGet*: "Number" The maximum number of objects that 358 the client may request in a single "getFoos" type method call. 360 * *maxObjectsInSet*: "Number" The maximum number of objects the 361 client may send to create, update or destroy in a single 362 "setFoos" type method call. 364 Future specifications will define their own properties on the 365 capabilities object. Servers MAY advertise vendor-specific JMAP 366 extensions. To avoid conflict, the identifiers for these MUST be 367 a URI beginning with a domain owned by the vendor. Clients MUST 368 opt in to any specifications it wishes to use (see "Making an API 369 request"). 371 o *apiUrl*: "String" The URL to use for JMAP API requests. 373 o *downloadUrl*: "String" The URL endpoint to use when downloading 374 files (see the Download section of this spec), in [RFC6570] URI 375 Template (level 1) format. The URL MUST contain variables called 376 "blobId", MAY contain a variables called "accountId" and SHOULD 377 contain a variable called "name". 379 o *uploadUrl*: "String" The URL endpoint to use when uploading files 380 (see the Upload section of this spec), in [RFC6570] URI Template 381 (level 1) format. The URL MAY contain a variable called 382 "accountId". 384 o *eventSourceUrl*: "String" The URL to connect to for push events 385 (see the Push section of this spec). 387 To ensure future compatibility, other properties MAY be included on 388 the JMAP session object. Clients MUST ignore any properties they are 389 not expecting. 391 2.1. Service Autodiscovery 393 There are two standardised autodiscovery methods in use for internet 394 protocols: 396 o *DNS srv* ([RFC6186] and [RFC6764]) 398 o *.well-known/servicename* ([RFC5785]) 400 A JMAP-supporting host for the domain "example.com" SHOULD publish a 401 SRV record "_jmaps._tcp.example.com" which gives a _hostname_ and 402 _port_ (usually port "443"). The JMAP Session resource is then 403 "https://${hostname}[:${port}]/.well-known/jmap" (following any 404 redirects). 406 If the client has a username in the form of an email address, it MAY 407 use the domain portion of this to attempt autodiscovery of the JMAP 408 server. 410 To support clients that are unable to do SRV lookups, the server 411 SHOULD make the _hostname_ the same domain as the username if 412 possible. 414 3. Structured data exchange 416 The client may make an API request to the server to get or set 417 structured data. This request consists of an ordered series of 418 method calls. These are processed by the server, which then returns 419 an ordered series of responses. 421 3.1. Making an API request 423 To make an API request, the client makes an authenticated POST 424 request to the API resource, the location of which may be found on 425 the JMAP session object. 427 The request MUST consist of a single *Request* object, encoded in 428 UTF-8. If successful, the response MUST be of type "application/ 429 json" and consist of a single *Response* object. 431 3.2. The Request object 433 A *Request* object has the following properties: 435 o *using*: "String[]" The set of capabilities the client wishes to 436 use. The client MAY include capability identifiers even if the 437 method calls it makes do not utilise those capabilities. The 438 server advertises the set of specifications it supports in the 439 JMAP session resource, as keys on the _capabilities_ property. 441 o *methodCalls*: "Array[]" An array of method calls to process on 442 the server. The method calls MUST be processed sequentially, in 443 order. A *method call* is represented by an array containing 444 three elements: 446 1. A "String" *name* of the method to call. 448 2. An "Object" containing _named_ *arguments* for that method. 450 3. A *client id*: an arbitrary "String" to be echoed back with 451 the responses emitted by that method call (a method may return 452 1 or more responses, as it may make implicit calls to other 453 methods; all responses initiated by this method call get the 454 same client id in the response). 456 Future specifications MAY add further properties to the Request 457 object to extend the semantics. To ensure forwards compatability, a 458 server MUST ignore any other properties it does not understand on the 459 JMAP request object. 461 3.2.1. Example request 462 { 463 "using": [ "ietf.org/rfc/jmap-core", "ietf.org/rfc/jmap-mail" ], 464 "methodCalls": [ 465 ["method1", {"arg1": "arg1data", "arg2": "arg2data"}, "#1"], 466 ["method2", {"arg1": "arg1data"}, "#2"], 467 ["method3", {}, "#3"] 468 ] 469 } 471 3.3. Vendor-specific extensions 473 Individual services will have custom features they wish to expose 474 over JMAP. This may take the form of extra datatypes and/or methods 475 not in the spec, or extra arguments to JMAP methods, or extra 476 properties on existing data types (which may also appear in arguments 477 to methods that take property names). 479 The server can advertise custom extensions it supports by including 480 the identifiers in the capabilities object. Identifiers for vendor 481 extensions MUST be a URL belonging to a domain owned by the vendor, 482 to avoid conflict. The URL SHOULD resolve to documentation for the 483 changes the extension makes. 485 To ensure compatibility with clients that don't know about a specific 486 custom extension, and for compatibility with future versions of JMAP, 487 to use an extension the client MUST opt in by passing the appropriate 488 capability identifier in the _using_ array of the Request object. 489 The server MUST only follow the specifications that are opted-into 490 and behave as though it does not implement anything else when 491 processing a request. 493 3.4. The Response object 495 A *Response* object has the following properties: 497 o *methodResponses*: "Array[]" An array of responses, in the same 498 format as the _methodCalls_ on the request object. The output of 499 the methods MUST be added to the _methodResponses_ array in the 500 same order as the methods are processed. 502 3.4.1. Example response: 504 { 505 "methodResponses": [ 506 ["responseFromMethod1", {"arg1": 3, "arg2": "foo"}, "#1"], 507 ["responseFromMethod2", {"isBlah": true}, "#2"], 508 ["anotherResponseFromMethod2", { 509 "data": 10, 510 "yetmoredata": "Hello" 511 }, "#2"], 512 ["aResponseFromMethod3", {}, "#3"] 513 ] 514 } 516 3.5. Omitting arguments 518 An argument to a method may be specified to have a default value. If 519 omitted by the client, the server MUST treat the method call the same 520 as if the default value had been specified. Similarly, the server 521 MAY omit any argument in a response which has the default value. 523 Unless otherwise specified in a method description, "null" is the 524 default value for any argument in a request or response where this is 525 allowed by the type signature. Other arguments may only be omitted 526 if an explicit default value is defined in the method description. 528 3.6. Errors 530 If the data sent as an API request is not valid JSON or does not 531 match the structure above, a "400 Bad Request" error will be returned 532 at the HTTP level. 534 Possible errors for each method are specified in the method 535 descriptions. If a method encounters an error, the appropriate 536 "error" response MUST be inserted at the current point in the 537 _methodResponses_ array and, unless otherwise specified, further 538 processing MUST NOT happen within that method call. 540 Any further method calls in the request MUST then be processed as 541 normal. 543 An "error" response looks like this: 545 ["error", { 546 type: "unknownMethod" 547 }, "client-id"] 549 The response name is "error", and it has a type property as specified 550 in the method description. Other properties may be present with 551 further information; these are detailed in the method descriptions 552 where appropriate. 554 Any method MAY return an error of type "serverError" if an unexpected 555 or unknown error occurs during the processing of that call. The 556 state of the server after such an error is undefined. 558 If an unknown method is called, an "unknownMethod" error (this is the 559 type shown in the example above) MUST be inserted and then the next 560 method call MUST be processed as normal. 562 If an unknown argument or invalid arguments (wrong type, missing and 563 not optional, or in violation of other specified constraints) are 564 supplied to a method, an "invalidArguments" error MUST be inserted 565 and then the next method call MUST be processed as normal. 567 3.7. References to previous method results 569 To allow clients to make more efficient use of the network and avoid 570 round trips, an argument to one method can be taken from the result 571 of a previous method call. 573 To do this, the client prefixes the argument name with "#". The 574 value is a _ResultReference_ object as described below. When 575 processing a method call, the server MUST first check the arguments 576 object for any names beginning with "#". If found, the back 577 reference should be resolved and the value used as the "real" 578 argument. The method is then processed as normal. If any back 579 reference fails to resolve, the whole method MUST be rejected with a 580 "resultReference" error. If an argument object contains the same 581 argument name in normal and referenced form (e.g. "foo" and "#foo"), 582 the method MUST return an "invalidArguments" error. 584 A *ResultReference* object has the following properties: 586 o *resultOf*: "String" The client id of the method call to get the 587 result from (the string given as the third item in the array for a 588 method call). 590 o *path*: "String" A pointer into the arguments. This is an RFC6901 591 JSON Pointer, except it also allows the use of "*" to map through 592 an array (see description below). 594 To resolve: 596 1. Find the first response with a client id identical to the 597 _resultOf_ property of the _ResultReference_ in the 598 _methodResponses_ array from previously processed method calls in 599 the same request. If none, evaluation fails. 601 2. If the response name is "error", evaluation fails. 603 3. Apply the _path_ to the arguments object of the response (the 604 second item in the response array) following the [RFC6901] JSON 605 pointer algorithm, except with the following addition in 606 Section 4 (Evaluation): 608 If the currently referenced value is a JSON array, the reference 609 token may be exactly the single character "*", making the new 610 referenced value the result of applying the rest of the JSON pointer 611 tokens to every item in the array and returning the results in the 612 same order in a new array. If the result of applying the rest of the 613 pointer tokens to a value was itself an array, its items should be 614 included individually in the output rather than including the array 615 itself (i.e. the result is flattened from an array of arrays to a 616 single array). 618 1. If the type of the result is X, and the expected type of the 619 argument is an array of type X, wrap the result in an array with 620 a single item. 622 As a simple example, suppose we have the following API request 623 _methodCalls_: 625 [[ "getFooUpdates", { 626 "sinceState": "abcdef" 627 }, "t0" ], 628 [ "getFoos", { 629 "#ids": { 630 "resultOf": "t0", 631 "path": "/changed" 632 } 633 }, "t1" ]] 635 After executing the first method call the _methodResponses_ array is: 637 [[ "fooUpdates", { 638 "accountId": "1", 639 "oldState": "abcdef", 640 "newState": "123456", 641 "hasMoreUpdates": false, 642 "changed": [ "f1", "f4" ], 643 "removed": [] 644 }, "t0" ]] 646 So to execute the getFoos call, we look through the arguments and 647 find there is one with a "#" prefix. To resolve this, we apply the 648 algorithm above: 650 1. Find the first response with client id "t0". The "fooUpdates" 651 response fulfils this criterion. 653 2. Check the response name is not "error". It's "fooUpdates", so 654 this is fine. 656 3. Apply the _path_ as a JSON pointer to the arguments object. This 657 simply selects the "changed" property, so the result of 658 evaluating is: "[ "f1", "f4" ]" 660 The JMAP server now continues to process the getFoos call as though 661 the arguments were: 663 { 664 "ids": [ "msg1", "msg4" ] 665 } 667 Now a more complicated example using the JMAP Mail data model: fetch 668 the "from"/"date"/"subject" for every message in the first 10 threads 669 in the Inbox (sorted newest first): 671 [[ "getMessageList", { 672 "filter": { inMailbox: "id_of_inbox" }, 673 "sort": [ "date desc" ], 674 "collapseThreads": true, 675 "position": 0, 676 "limit": 10 677 }, "t0" ], 678 [ "getMessages", { 679 "#ids": { 680 "resultOf": "t0", 681 "path": "/ids" 682 }, 683 "properties": [ "threadId" ] 684 }, "t1" ], 685 [ "getThreads", { 686 "#ids": { 687 "resultOf": "t1", 688 "path": "/list/*/threadId" 689 } 690 }, "t2" ], 691 [ "getMessages", { 692 "#ids": { 693 "resultOf": "t2" 694 "path": "/list/*/messageIds" 695 }, 696 "properties": [ "from", "date", "subject" ] 697 }, "t3" ]] 699 After executing the first 3 method calls the _methodResponses_ array 700 might be: 702 [[ "messageList", { 703 "accountId": "1", 704 "filter": { inMailbox: "id_of_inbox" }, 705 "sort": [ "date desc" ], 706 "collapseThreads": true, 707 "state": "abcdefg", 708 "canCalculateUpdates": true, 709 "position": 0, 710 "total": 101, 711 "ids": [ "msg1023", "msg223", "msg110", "msg93", "msg91", "msg38", "msg36", "msg33", "msg11", "msg1" ] 712 }, "t0" ], 713 [ "messages", { 714 "accountId": "1", 715 "state": "123456", 716 "list": [{ 717 "id": "msg1023", 718 "threadId": "trd194", 719 }, { 720 "id": "msg223", 721 "threadId": "trd114" 722 }, 723 ... etc... 724 ], 725 "notFound": null 726 }, "t1" ], 727 [ "threads", { 728 "accountId": "1", 729 "state": "123456", 730 "list": [{ 731 "id: "trd194", 732 "messageIds": [ "msg1020", "msg1021", "msg1023" ] 733 }, { 734 "id: "trd114", 735 "messageIds": [ "msg201", "msg223" ] 736 }, 737 ... etc... 738 ], 739 "notFound": null 740 }, "t2" ]] 742 So to execute the final getMessages call, we look through the 743 arguments and find there is one with a "#" prefix. To resolve this, 744 we apply the algorithm: 746 1. Find the first response with client id "t2". The "threads" 747 response fulfils this criterion. 749 2. Check the response name is not "error". It's threads", so this 750 is fine. 752 3. Apply the _path_ as a JSON pointer to the arguments object. 753 Token-by-token: a) "list": get the array of thread objects b) 754 "*": for each of the items in the array: i) "messageIds": get the 755 array of message ids ii) Concatenate these into a single array of 756 all the ids in the result. 758 The JMAP server now continues to process the getMessages call as 759 though the arguments were: 761 { 762 "ids": [ "msg1020", "msg1021", "msg1023", "msg201", "msg223", etc... ], 763 "properties": [ "from", "date", "subject" ] 764 } 766 3.8. Security 768 As always, the server must be strict about data received from the 769 client. Arguments need to be checked for validity; a malicious user 770 could attempt to find an exploit through the API. In case of invalid 771 arguments (unknown/insufficient/wrong type for data etc.) the method 772 MUST return an "invalidArguments" error and terminate. 774 3.9. Concurrency 776 Each individual method call within a request MUST be serializable; 777 concurrent execution of methods MUST produce the same effect as 778 running them one at a time in some order. 780 This means that the observable ordering may interleave method calls 781 from different concurrent API requests, such that the data on the 782 server may change between two method calls within a single API 783 request. 785 4. Standard methods and naming convention 787 JMAP provides a uniform interface for creating, retrieving, updating 788 and deleting objects of a particular type. For a "Foo" data type, 789 records of that type would be fetched via a "getFoos" call and 790 modified via a "setFoos" call. Delta updates may be fetched via a 791 "getFooUpdates" call. These methods all follow a standard format as 792 described below. 794 Methods with a name starting with "get" MUST NOT alter state on the 795 server. 797 4.1. getFoos 799 Objects of type *Foo* are fetched via a call to _getFoos_. 801 It takes the following arguments: 803 o *accountId*: "String|null" The id of the Account to use. If 804 "null", the primary account is used. 806 o *ids*: "String[]|null" The ids of the Foo objects to return. If 807 "null" then *all* records of the data type are returned, if this 808 is supported for that data type. 810 o *properties*: "String[]|null" If supplied, only the properties 811 listed in the array are returned for each Foo object. If "null", 812 all properties of the object are returned. The id of the object 813 is *always* returned, even if not explicitly requested. 815 The response to "getFoos" is called "foos". It has the following 816 arguments: 818 o *accountId*: "String" The id of the account used for the call. 820 o *state*: "String" A string representing the state on the server 821 for *all* the data of this type in the account (not just the 822 objects returned in this call). If the data changes, this string 823 MUST change. If the Foo data is unchanged, servers SHOULD return 824 the same state string on subsequent requests for this data type. 825 When a client receives a response with a different state string to 826 a previous call, it MUST either throw away all currently cached 827 objects for the type, or call _getFooUpdates_ to get the exact 828 changes. 830 o *list*: "Foo[]" An array of the Foo objects requested. This is 831 the *empty array* if no objects were found, or if the _ids_ 832 argument passed in was also the empty array. The results MAY be 833 in a different order to the _ids_ in the request arguments. If an 834 identical id is included more than once in the request, the server 835 MUST only include it once in the _list_ or _notFound_ response. 837 o *notFound*: "String[]|null" This array contains the ids passed to 838 the method for records that do not exist. This property is "null" 839 if all requested ids were found, or if the _ids_ argument passed 840 in was either "null" or the empty array. 842 The following error may be returned instead of the "foos" response: 844 "accountNotFound": An _accountId_ was explicitly included with the 845 request, but it does not correspond to a valid account. 847 "accountNotSupportedByMethod": The _accountId_ given corresponds to a 848 valid account, but the account does not support this data type. 850 "requestTooLarge": The number of _ids_ requested by the client 851 exceeds the maximum number the server is willing to process in a 852 single method call. 854 "invalidArguments": One of the arguments is of the wrong type, or 855 otherwise invalid. A "description" property MAY be present on the 856 response object to help debug with an explanation of what the problem 857 was. 859 4.2. getFooUpdates 861 When the state of the set of Foo records changes on the server 862 (whether due to creation, updates or deletion), the _state_ property 863 of the _foos_ response will change. The _getFooUpdates_ call allows 864 a client to efficiently update the state of its Foo cache to match 865 the new state on the server. It takes the following arguments: 867 o *accountId*: "String|null" The id of the Account to use. If 868 "null", the primary account is used. 870 o *sinceState*: "String" The current state of the client. This is 871 the string that was returned as the _state_ argument in the _foos_ 872 response. The server will return the changes made since this 873 state. 875 o *maxChanges*: "Number|null" The maximum number of ids to return in 876 the response. The server MAY choose to return fewer than this 877 value, but MUST NOT return more. If not given by the client, the 878 server may choose how many to return. If supplied by the client, 879 the value MUST be a positive integer greater than 0. If a value 880 outside of this range is given, the server MUST reject the call 881 with an "invalidArguments" error. 883 The response to _getFooUpdates_ is called _fooUpdates_. It has the 884 following arguments: 886 o *accountId*: "String" The id of the account used for the call. 888 o *oldState*: "String" This is the _sinceState_ argument echoed 889 back; the state from which the server is returning changes. 891 o *newState*: "String" This is the state the client will be in after 892 applying the set of changes to the old state. 894 o *hasMoreUpdates*: "Boolean" If "true", the client may call 895 _getFooUpdates_ again with the _newState_ returned to get further 896 updates. If "false", _newState_ is the current server state. 898 o *changed*: "String[]|null" An array of ids for records which have 899 been created or changed but not destroyed since the oldState, or 900 "null" if none. 902 o *removed*: "String[]|null" An array of ids for records which have 903 been destroyed since the old state, or "null" if none. 905 If a _maxChanges_ is supplied, or set automatically by the server, 906 the server MUST ensure the number of ids returned across _changed_ 907 and _removed_ does not exceed this limit. If there are more changes 908 than this between the client's state and the current server state, 909 the update returned SHOULD generate an update to take the client to 910 an intermediate state, from which the client can continue to call 911 _getMessageUpdates_ until it is fully up to date. If it is unable to 912 calculate an intermediate state, it MUST return a 913 "cannotCalculateChanges" error response instead. 915 If a Foo record has been modified AND deleted since the oldState, the 916 server SHOULD just return the id in the _removed_ response, but MAY 917 return it in the changed response as well. If a Foo record has been 918 created AND deleted since the oldState, the server SHOULD remove the 919 id from the response entirely, but MAY include it in the _removed_ 920 response. 922 The following errors may be returned instead of the _fooUpdates_ 923 response: 925 "accountNotFound": An _accountId_ was explicitly included with the 926 request, but it does not correspond to a valid account. 928 "accountNotSupportedByMethod": The _accountId_ given corresponds to a 929 valid account, but the account does not support this data type. 931 "invalidArguments": The request does not include one of the required 932 arguments, or one of the arguments is of the wrong type, or otherwise 933 invalid. A _description_ property MAY be present on the response 934 object to help debug with an explanation of what the problem was. 936 "cannotCalculateChanges": The server cannot calculate the changes 937 from the state string given by the client. Usually due to the 938 client's state being too old, or the server being unable to produce 939 an update to an intermediate state when there are too many updates. 940 The client MUST invalidate its Foo cache. 942 Maintaining state to allow calculation of _getFooUpdates_ can be 943 expensive for the server, but always returning 944 _cannotCalculateChanges_ severely increases network traffic and 945 resource usage for the client. To allow efficient sync, servers 946 SHOULD be able to calculate changes from any state string that was 947 given to a client within the last 30 days (but of course may support 948 calculating updates from states older than this). 950 4.3. setFoos 952 Modifying the state of Foo objects on the server is done via the 953 _setFoos_ method. This encompasses creating, updating and destroying 954 Foo records. This allows the server to sort out ordering and 955 dependencies that may exist if doing multiple operations at once (for 956 example to ensure there is always a minimum number of a certain 957 record type). 959 The _setFoos_ method takes the following arguments: 961 o *accountId*: "String|null" The id of the Account to use. If 962 "null", the primary account is used. 964 o *ifInState*: "String|null" This is a state string as returned by 965 the _getFoos_ method. If supplied, the string must match the 966 current state, otherwise the method will be aborted and a 967 "stateMismatch" error returned. If "null", any changes will be 968 applied to the current state. 970 o *create*: "String[Foo]|null" A map of _creation id_ (an arbitrary 971 string set by the client) to Foo objects, or "null" if no objects 972 are to be created. The Foo object type definition MAY define 973 default values for properties. Any such property MAY be omitted 974 by the client. The client MUST omit any properties that may only 975 be set by the server (for example, the _id_ property on most 976 object types). 978 o *update*: "String[PatchObject]|null" A map of id to a Patch object 979 to apply to the current Foo object with that id, or "null" if no 980 objects are to be updated. A _PatchObject_ is of type 981 "String[*]", and represents an unordered set of patches. The keys 982 are a path in [RFC6901] JSON pointer format, with an implicit 983 leading "/" (i.e. prefix each key with "/" before applying the 984 JSON pointer evaluation algorithm). All paths MUST also conform 985 to the following restrictions; if there is any violation, the 986 update MUST be rejected with an "invalidPatch" error: 988 * The pointer MUST NOT reference inside an array (i.e. you MUST 989 NOT insert/delete from an array; the array MUST be replaced in 990 its entirety instead). 992 * All parts prior to the last (i.e. the value after the final 993 slash) MUST already exist on the object being patched. 995 * There MUST NOT be two patches in the PatchObject where the 996 pointer of one is the prefix of the pointer of the other, e.g. 997 "alerts/1/offset" and "alerts". 999 The value associated with each pointer determines how to apply 1000 that patch: 1002 * If "null", set to the default value if specified for this 1003 property, otherwise remove the property from the patched 1004 object. If the key is not present in the parent, this a no-op. 1006 * Anything else: The value to set for this property (this may be 1007 a replacement or addition to the object being patched). 1009 Any server-set properties MAY be included in the patch if their 1010 value is identical to the current server value (before applying 1011 the patches to the object). Otherwise, the update MUST be 1012 rejected with an _invalidProperties_ SetError. This patch 1013 definition is designed such that an entire Foo object is also a 1014 valid PatchObject. The client MAY choose to optimise network 1015 usage by just sending the diff, or MAY just send the whole object; 1016 the server processes it the same either way. 1018 o *destroy*: "String[]|null" A list of ids for Foo objects to 1019 permanently delete, or "null" if no objects are to be destroyed. 1021 Each creation, modification or destruction of an object is considered 1022 an atomic unit. It is permissible for the server to commit changes 1023 to some objects but not others, however it is not permissible to only 1024 commit part of an update to a single record (e.g. update a _name_ 1025 property but not a _count_ property, if both are supplied in the 1026 update object). 1028 The final state MUST be valid after the setFoos is finished, however 1029 the server may have to transition through invalid intermediate states 1030 (not exposed to the client) while processing the individual 1031 create/update/destroy requests. For example, suppose there is a 1032 "name" property that must be unique. A single method call could 1033 rename an object A => B, and simultaneously rename another object B 1034 => A. The final state is valid, so this is allowed, however if 1035 processed sequentially there will be an internal state where 1036 temporarily both objects have the same name. 1038 If a create, update or destroy is rejected, the appropriate error 1039 MUST be added to the notCreated/notUpdated/notDestroyed property of 1040 the response and the server MUST continue to the next create/update/ 1041 destroy. It does not terminate the method. 1043 If an id given cannot be found, the update or destroy MUST be 1044 rejected with a "notFound" set error. 1046 Some record objects may hold references to others (foreign keys). 1047 When records are created or modified, they may reference other 1048 records being created _in the same API request_ by using the creation 1049 id prefixed with a "#". The order of the method calls in the request 1050 by the client MUST be such that the record being referenced is 1051 created in the same or an earlier call. The server thus never has to 1052 look ahead. Instead, while processing a request (a series of method 1053 calls), the server MUST keep a simple map for the duration of the 1054 request of creation id to record id for each newly created record, so 1055 it can substitute in the correct value if necessary in later method 1056 calls. 1058 Creation ids are scoped by type; a separate "creation id -> id" map 1059 MUST be kept for each type for the duration of the request. Foreign 1060 key references are always for a particular record type, so use of the 1061 same creation key in two different types cannot cause any ambiguity. 1062 Creation ids sent by the client SHOULD be unique within the single 1063 API request for a particular data type. If a creation id is reused 1064 for the same type, the server MUST map the creation id to the most 1065 recently created item with that id. 1067 The response to _setFoos_ is called _foosSet_. It has the following 1068 arguments: 1070 o *accountId*: "String" The id of the account used for the call. 1072 o *oldState*: "String|null" The state string that would have been 1073 returned by _getFoos_ before making the requested changes, or 1074 "null" if the server doesn't know what the previous state string 1075 was. 1077 o *newState*: "String" The state string that will now be returned by 1078 _getFoos_. 1080 o *created*: "String[Foo]|null" A map of the creation id to an 1081 object containing any properties of the created Foo object that 1082 were not sent by the client. This includes all server-set 1083 properties (such as the _id_ in most object types) and any 1084 properties that were omitted by the client and so set to a default 1085 by the server. This argument is "null" if no Foo objects were 1086 successfully created. 1088 o *updated*: "String[Foo|null]|null" The _keys_ in this map are the 1089 ids of all Foos that were successfully updated, or "null" if none 1090 successful. The _value_ for each id is a Foo object containing 1091 any property that changed in a way _not_ explicitly requested by 1092 the _PatchObject_ sent to the server, or "null" if none. This 1093 lets the client know of any changes to server-set or computed 1094 properties. 1096 o *destroyed*: "String[]|null" A list of Foo ids for records that 1097 were successfully destroyed, or "null" if none successful. 1099 o *notCreated*: "String[SetError]|null" A map of creation id to a 1100 SetError object for each record that failed to be created, or 1101 "null" if all successful. 1103 o *notUpdated*: "String[SetError]|null" A map of Foo id to a 1104 SetError object for each record that failed to be updated, or 1105 "null" if all successful. 1107 o *notDestroyed*: "String[SetError]|null" A map of Foo id to a 1108 SetError object for each record that failed to be destroyed, or 1109 "null" if all successful. 1111 A *SetError* object has the following properties: 1113 o *type*: "String" The type of error. 1115 o *description*: "String|null" A description of the error to display 1116 to the user. 1118 The following SetError types are defined and may be returned for set 1119 operations on any record type: 1121 o "notFound": The id given in an update/destroy cannot be found. 1123 o "invalidPatch": The PatchObject given to update a Foo record was 1124 invalid. 1126 o "invalidProperties": The Foo record given in a create/update is 1127 invalid in some way. For example: 1129 * It contains properties which are invalid according to the type 1130 specification of this record type. 1132 * It contains a property that may only be set by the server (e.g. 1133 "id") and are different to the current value. Note, to allow 1134 clients to pass whole objects back, it is not an error to 1135 include a server-set property so long as the value is identical 1136 to the current value on the server (or the value that will be 1137 set by the server if a create). 1139 * There is a reference to another record (foreign key) and the 1140 given id does not correspond to a valid record. 1142 The SetError object SHOULD also have a property called 1143 _properties_ of type "String[]" that lists *all* the properties 1144 that were invalid. Individual methods MAY specify more specific 1145 errors for certain conditions that would otherwise result in an 1146 invalidProperties error. If the condition of one of these is met, 1147 it MUST be returned instead of the invalidProperties error. 1149 Other possible SetError types MAY be given in specific method 1150 descriptions. Other properties MAY also be present on the _SetError_ 1151 object, as described in the relevant methods. 1153 The following errors may be returned instead of the "foosSet" 1154 response: 1156 "accountNotFound": An _accountId_ was explicitly included with the 1157 request, but it does not correspond to a valid account. 1159 "accountNotSupportedByMethod": The _accountId_ given corresponds to a 1160 valid account, but the account does not support this data type. 1162 "accountReadOnly": The account has isReadOnly == true. 1164 "requestTooLarge": The total number of objects to create, update or 1165 destroy exceeds the maximum number the server is willing to process 1166 in a single method call. 1168 "invalidArguments": One of the arguments is of the wrong type, or 1169 otherwise invalid. A "description" property MAY be present on the 1170 response object to help debug with an explanation of what the problem 1171 was. 1173 "stateMismatch": An "ifInState" argument was supplied and it does not 1174 match the current state. 1176 4.3.1. Example 1178 Suppose we have a type _Todo_ with the following properties: 1180 o *id*: "String" (immutable; server-set) The id of the object. 1182 o *title*: "String" A brief summary of what is to be done. 1184 o *keywords*: "String[Boolean]" (mutable; default: "{}") A set of 1185 keywords that apply to the todo. The set is represented as an 1186 object, with the keys being the _keywords_. The value for each key 1187 in the object MUST be "true". 1189 o *neuralNetworkTimeEstimation*: "Number" (server-set) The title and 1190 keywords are fed into the server's state-of-the-art neural network 1191 to get an estimation of how long this todo will take, in seconds. 1193 Now we fetched a Todo of id "a" (let's presume we already knew a Todo 1194 with this id existed): 1196 [["getTodos", { 1197 "ids": ["a"] 1198 }, "0"]] 1200 and got back 1202 [["todos", { 1203 "accountId": "x", 1204 "state": "10324", 1205 "list": [{ 1206 "id": "a", 1207 "title": "Practice Piano", 1208 "keywords": { 1209 "beethoven": true, 1210 "mozart": true, 1211 "liszt": true, 1212 "rachmaninov": true 1213 }, 1214 "neuralNetworkTimeEstimation": 3600 1215 }] 1216 }, "0"]] 1218 Now the user adds a keyword "chopin" and removes the keyword 1219 "mozart". The client may send the whole object to the server, as 1220 this is a valid PatchObject: 1222 [["setTodos", { 1223 "ifInState": "10324", 1224 "update": { 1225 "a": { 1226 "id": "a", 1227 "title": "Practice Piano", 1228 "keywords": { 1229 "beethoven": true, 1230 "chopin": true, 1231 "liszt": true, 1232 "rachmaninov": true, 1233 } 1234 "neuralNetworkTimeEstimation": 360 1235 } 1236 } 1237 }, "0"]] 1239 or it may send a minimal patch: 1241 [["setTodos", { 1242 "ifInState": "10324", 1243 "update": { 1244 "a": { 1245 "keywords/chopin": true, 1246 "keywords/mozart": null 1247 } 1248 } 1249 }, "0"]] 1251 The effect is exactly the same on the server in either case, and 1252 presuming the server is still in state "10324" it will probably 1253 return success: 1255 [["todosSet", { 1256 "accountId": "x", 1257 "oldState": "10324", 1258 "newState": "10329", 1259 "updated": { 1260 "a": { 1261 "neuralNetworkTimeEstimation": 5400 1262 } 1263 } 1264 }, "0"]] 1266 The server changed the "neuralNetworkTimeEstimation" property on the 1267 object as part of this change; as this changed in a way _not_ 1268 explicitly requested by the PatchObject sent to the server, it is 1269 returned with the "updated" confirmation. 1271 4.4. getFooList 1273 For data sets where the total amount of data is expected to be very 1274 small, clients can just fetch the complete set of data and then do 1275 any sorting/filtering locally. However, for large data sets (e.g. 1276 multi-gigabyte mailboxes), the client needs to be able to perform a 1277 query on the server for the data type. 1279 A query on the set of Foos in an account is made by calling 1280 _getFooList_. This takes a number of arguments to determine which 1281 records to include, how they should be sorted, and which part of the 1282 result should be returned (the full list may be _very_ long). The 1283 result is returned as a list of Foo ids. 1285 A call to _getFooList_ takes the following arguments: 1287 o *accountId*: "String|null" The id of the Account to use. If 1288 "null", the primary account is used. 1290 o *filter*: "FilterCondition|null" Determines the set of Foos 1291 returned in the results. This is an "object", whose allowed 1292 properties and semantics depend on the data type. If "null", all 1293 objects in the account of this type are included in the results. 1295 o *sort*: "String[]|null" Lists the names of properties to compare 1296 between two Foo records to determine which comes first in the 1297 sort. If two Foo records have an identical value for the first 1298 property, the next property will be considered and so on. If all 1299 properties are the same (this includes the case where an empty 1300 array or "null" is given as the _sort_ argument), the sort order 1301 is server-dependent, but MUST be stable between calls to 1302 "getFooList". Following each property name there MUST be a space 1303 and then either the string "asc" or "desc" to specify ascending or 1304 descending sort for that property. e.g. "[ "date desc", "name asc" 1305 ]" The method of comparison depends on the type of the property: 1307 * "String": Comparison function is server-dependent. It SHOULD 1308 be case-insensitive and SHOULD take into account locale- 1309 specific conventions if known for the user. However, the 1310 server MAY choose to just sort based on unicode code point, 1311 after best-effort translation to lower-case. 1313 * "Date"/"UTCDate": If sorting in ascending order, the earlier 1314 date MUST come first. 1316 * "Boolean": If sorting in ascending order, a "false" value MUST 1317 come before a "true" value. 1319 o *position*: "Number" (default: "0") The 0-based index of the first 1320 id in the full list of results to return. If a negative value is 1321 given, the call MUST be rejected with an "invalidArguments" error. 1322 If the index is greater than or equal to the total number of 1323 objects in the results list then there are no results to return, 1324 but this is not an error. 1326 o *anchor*: "String|null" A Foo id. If supplied the _position_ 1327 argument is ignored. The index of this id in the results will be 1328 used in combination with the "anchorOffset" argument to determine 1329 the index of the first result to return (see below for more 1330 details). 1332 o *anchorOffset*: "Number|null" The index of the anchor object 1333 relative to the index of the first result to return. This MAY be 1334 negative. For example, "-1" means the first Foo after the anchor 1335 Foo should be the first result in the results returned (see below 1336 for more details). 1338 o *limit*: "Number|null" The maximum number of results to return. 1339 If "null", no limit presumed. The server MAY choose to enforce a 1340 maximum "limit" argument. In this case, if a greater value is 1341 given (or if it is "null"), the limit should be clamped to the 1342 maximum; since the total number of results in the list is 1343 returned, the client can determine if it has received all the 1344 results. If a negative value is given, the call MUST be rejected 1345 with an "invalidArguments" error. 1347 If an *anchor* argument is given, then after filtering and sorting 1348 the anchor is searched for in the results list. If found, the 1349 *anchor offset* is then subtracted from this index. If the resulting 1350 index is now negative, it is clamped to 0. This index is now used 1351 exactly as though it were supplied as the "position" argument. If 1352 the anchor is not found, the call is rejected with an 1353 "anchorNotFound" error. 1355 If an _anchor_ is specified, any position argument supplied by the 1356 client MUST be ignored. If _anchorOffset_ is "null", it defaults to 1357 "0". If no _anchor_ is supplied, any anchor offset argument MUST be 1358 ignored. 1360 A client can use _anchor_ instead of _position_ to find the index of 1361 an id within a large set of results. 1363 The response to a call to _getFooList_ is called _fooList_. It has 1364 the following arguments: 1366 o *accountId*: "String" The id of the account used for the call. 1368 o *filter*: "FilterCondition|null" The filter of the foo list. 1369 Echoed back from the call. 1371 o *sort*: "String[]|null" A list of Foo property names used to sort 1372 by. Echoed back from the call. 1374 o *state*: "String" A string encoding the current state on the 1375 server. This string MUST change if the results of the Foo list 1376 may have changed (for example, there has been a change to the 1377 state of the set of Foos; it does not guarantee that anything in 1378 the list has changed). It may be passed to _getFooListUpdates_ to 1379 efficiently get the set of changes from the client's current 1380 state. Should a client receive back a response with a different 1381 state string to a previous call, it MUST either throw away the 1382 currently cached list and fetch it again (note, this does not 1383 require fetching the foos again, just the list of ids) or, call 1384 _getFooListUpdates_ to get the delta difference. 1386 o *canCalculateUpdates*: "Boolean" This is "true" if the server 1387 supports calling _getFooListUpdates_ with these "filter"/"sort" 1388 parameters. Note, this does not guarantee that the 1389 _getFooListUpdates_ call will succeed, as it may only be possible 1390 for a limited time afterwards due to server internal 1391 implementation details. 1393 o *position*: "Number" The 0-based index of the first result in the 1394 "ids" array within the complete list of results. 1396 o *total*: "Number" The total number of foos in the foos list (given 1397 the _filter_). 1399 o *ids*: "String[]" The list of ids for each foo in the list after 1400 filtering and sorting, starting at the index given by the 1401 _position_ argument of this response, and continuing until it hits 1402 the end of the list or reaches the "limit" number of ids. If 1403 _position_ is >= _total_, this MUST be the empty list. 1405 The following errors may be returned instead of the "fooList" 1406 response: 1408 "accountNotFound": An _accountId_ was explicitly included with the 1409 request, but it does not correspond to a valid account. 1411 "accountNotSupportedByMethod": The _accountId_ given corresponds to a 1412 valid account, but the account does not support this data type. 1414 "anchorNotFound": An anchor argument was supplied, but it cannot be 1415 found in the Foo list. 1417 "unsupportedSort": The _sort_ is syntactically valid, but includes a 1418 property the server does not support sorting on. 1420 "unsupportedFilter": The _filter_ is syntactically valid, but the 1421 server cannot process it. 1423 "invalidArguments": The request does not include one of the required 1424 arguments, or one of the arguments is of the wrong type, or otherwise 1425 invalid. A "description" property MAY be present on the response 1426 object to help debug with an explanation of what the problem was. 1428 4.5. getFooListUpdates 1430 The "getFooListUpdates" call allows a client to efficiently update 1431 the state of any cached foo list to match the new state on the 1432 server. It takes the following arguments: 1434 o *accountId*: "String|null" The id of the account to use for this 1435 call. If "null", the primary account will be used. 1437 o *filter*: "FilterCondition|null" The filter argument that was used 1438 with _getFooList_. 1440 o *sort*: "String[]|null" The sort argument that was used with 1441 _getFooList_. 1443 o *sinceState*: "String" The current state of the client. This is 1444 the string that was returned as the _state_ argument in the 1445 _fooList_ response. The server will return the changes made since 1446 this state. 1448 o *maxChanges*: "Number|null" The maximum number of changes to 1449 return in the response. See error descriptions below for more 1450 details. 1452 o *uptoId*: "String|null" The last id the client currently has 1453 cached from the list. When there are a large number of results, 1454 in a common case the client may have only downloaded and cached a 1455 small subset from the beginning of the list. If the sort and 1456 filter are both only on immutable properties, this allows the 1457 server to omit changes after this point in the list, which can 1458 significantly increase efficiency. If they are not immutable, 1459 this argument is ignored. 1461 The response to _getFooListUpdates_ is called _fooListUpdates_ It has 1462 the following arguments: 1464 o *accountId*: "String" The id of the account used for the call. 1466 o *filter*: "FilterCondition|null" The filter of the foo list. 1467 Echoed back from the call. 1469 o *sort*: "String[]|null" A list of Foo property names used to sort 1470 by. Echoed back from the call. 1472 o *oldState*: "String" This is the "sinceState" argument echoed 1473 back; the state from which the server is returning changes. 1475 o *newState*: "String" This is the state the client will be in after 1476 applying the set of changes to the old state. 1478 o *uptoId*: "String|null" Echoed back from the call. 1480 o *total*: "Number" The total number of foos in the current foo list 1481 (given the _filter_). 1483 o *removed*: "String[]" The _id_ for every foo that was in the list 1484 in the old state and is not in the list in the new state. If the 1485 sort and filter are both only on immutable properties and an 1486 _uptoId_ is supplied and exists in the list, any ids that were 1487 removed but have a higher index than _uptoId_ SHOULD be omitted. 1488 If the server cannot calculate this exactly, the server MAY return 1489 extra foos in addition that may have been in the old list but are 1490 not in the new list. If the _filter_ or _sort_ includes a mutable 1491 property, the server MUST include all foos in the current list for 1492 which this property MAY have changed. 1494 o *added*: "AddedItem[]" The id and index in the list (in the new 1495 state) for every foo that has been added to the list since the old 1496 state AND every foo in the current list that was included in the 1497 _removed_ array (due to a filter or sort based upon a mutable 1498 property). If the sort and filter are both only on immutable 1499 properties and an _uptoId_ is supplied and exists in the list, any 1500 ids that were added but have a higher index than _uptoId_ SHOULD 1501 be omitted. The array MUST be sorted in order of index, lowest 1502 index first. An *AddedItem* object has the following properties: 1504 * *id*: "String" 1506 * *index*: "Number" 1508 The result of this should be that if the client has a cached sparse 1509 array of foo ids in the list in the old state: 1511 fooIds = [ "id1", "id2", null, null, "id3", "id4", null, null, null ] 1513 then if it *splices out* all foos in the removed array: 1515 removed = [ "id2", ... ]; 1516 fooIds => [ "id1", null, null, "id3", "id4", null, null, null ] 1518 and *splices in* (in order) all of the foos in the added array: 1520 added = [{ fooId: "id5", index: 0, ... }]; 1521 fooIds => [ "id5", "id1", null, null, "id3", "id4", null, null, null ] 1523 and *truncates* or *extends* to the new total length, then the foo 1524 list will now be in the new state. 1526 The following errors may be returned instead of the "fooListUpdates" 1527 response: 1529 "accountNotFound": An _accountId_ was explicitly included with the 1530 request, but it does not correspond to a valid account. 1532 "accountNotSupportedByMethod": The _accountId_ given corresponds to a 1533 valid account, but the account does not support this data type. 1535 "invalidArguments": The request does not include one of the required 1536 arguments, or one of the arguments is of the wrong type, or otherwise 1537 invalid. A _description_ property MAY be present on the response 1538 object to help debug with an explanation of what the problem was. 1540 "tooManyChanges": There are more changes the the client's 1541 _maxChanges_ argument. Each item in the removed or added array is 1542 considered as one change. The client may retry with a higher max 1543 changes or invalidate its cache of the foo list. 1545 "cannotCalculateChanges": The server cannot calculate the changes 1546 from the state string given by the client. Usually due to the 1547 client's state being too old. The client MUST invalidate its cache 1548 of the foo list. 1550 5. Binary data 1552 Binary data is referenced by a _blobId_ in JMAP, and uploaded/ 1553 downloaded separately to the core API. A blobId does not have a name 1554 inherent to it, but this is normally given in the same object that 1555 contains the blobId. The data represented by a blobId is immutable. 1557 Any blobId that exists within an account may be used when creating/ 1558 updating another object in that account. For example, an Email type 1559 may have a blobId that represents the RFC5322 representation of the 1560 message. A client could create a new Email object with an attachment 1561 and use this blobId, in effect attaching the old message to the new 1562 one. Similarly it could attach any existing existing attachment of 1563 an old message without having to download and upload it again. 1565 When the client uses a blobId in a create/update, the server MAY 1566 assign a new blobId to refer to the same binary data from the new/ 1567 updated object. If it does so, it MUST return any properties that 1568 contain a changed blobId in the created/updated response so the 1569 client gets the new ids. 1571 A blob that is not referenced by a JMAP object (e.g. as a message 1572 attachment), MAY be deleted by the server to free up resources. 1573 Uploads (see below) are initially unreferenced blobs. To ensure 1574 interoperability: 1576 o The server SHOULD use a separate quota for unreferenced blobs to 1577 the user's usual quota. 1579 o This quota SHOULD be at least the maximum total size that a single 1580 object can reference on this server. For example, if supporting 1581 JMAP Mail, this should be at least the maximum total attachments 1582 size for a message. 1584 o When an upload would take the user over quota, the server MUST 1585 delete unreferenced blobs in date order, oldest first, until there 1586 is room for the new blob. 1588 o Except where quota restrictions force early deletion, an 1589 unreferenced blob SHOULD NOT be deleted for at least 24h from the 1590 time of upload; if reuploaded, the same blobId MAY be returned, 1591 but this SHOULD reset the expiry time. 1593 o A blob MUST NOT be deleted during the method call which removed 1594 the last reference, so that a client can issue a create and a 1595 destroy that both reference the blob within the same method call. 1597 5.1. Uploading binary data 1599 There is a single endpoint which handles all file uploads for an 1600 account, regardless of what they are to be used for. The JMAP 1601 session object has an _uploadUrl_ property in [RFC6570] URI Template 1602 (level 1) format, which MAY contain a variable called "accountId". 1603 The client may use this template in combination with an _accountId_ 1604 (if required in the template) to get the URL of the file upload 1605 resource. 1607 To upload a file, the client submits an authenticated POST request to 1608 the file upload resource. 1610 A successful request MUST return a single JSON object with the 1611 following properties as the response: 1613 o *accountId*: "String" The id of the account used for the call. 1615 o *blobId*: "String", The id representing the binary data uploaded. 1616 The data for this id is immutable. The id _only_ refers to the 1617 binary data, not any metadata. 1619 o *type*: "String" The media type of the file (as specified in 1620 [RFC6838], section 4.2) as set in the Content-Type header of the 1621 upload HTTP request, with CFWS collapsed to SP and 1622 [RFC2231]/[RFC2047] encoding removed. 1624 o *size*: "Number" The size of the file in bytes. 1626 If identical binary content to an existing blob in the account is 1627 uploaded, the existing blobId MAY be returned. 1629 5.2. Downloading binary data 1631 The JMAP session object has a _downloadUrl_ property, which is in 1632 [RFC6570] URI Template (level 1) format. The URL MUST contain a 1633 variable called "blobId", MAY contain a variable called "accountId", 1634 and SHOULD contain a variable called "name". 1636 The client may use this template in combination with an _accountId_ 1637 (if required in the URL template) and _blobId_ to download any binary 1638 data (files) referenced by other objects. Since a blob is not 1639 associated with a particular name, the template SHOULD allow a name 1640 to be substituted in as well; the server will return this as the 1641 filename if it sets a "Content-Disposition" header. 1643 To download the data the client makes an authenticated GET request to 1644 the download URL with the appropriate variables substituted in. The 1645 client SHOULD send an "Accept" header with the content type they 1646 would like the server to return for the file. The "Content-Type" 1647 header of a successful response SHOULD be set to the type as 1648 requested in the "Accept" header by the client, or "application/ 1649 octet-stream" if unknown and no "Accept" header given. 1651 6. Push 1653 Push notifications allow clients to efficiently update (almost) 1654 instantly to stay in sync with data changes on the server. In JMAP, 1655 push notifications occur out-of-band (i.e. not over the same 1656 connection as API exchanges), so that they can make use of efficient 1657 native push mechanisms on different platforms. 1659 The general model for push is simple and sends minimal data over the 1660 push channel. The format allows multiple changes to be coalesced 1661 into a single push update, and the frequency of pushes to be rate 1662 limited by the server. It doesn't matter if some push events are 1663 dropped before they reach the client; it will still get all changes 1664 next time it syncs. 1666 6.1. The StateChange object 1668 When something changes on the server, the server pushes a 1669 *StateChange* object to the client. A *StateChange* object has the 1670 following properties: 1672 o *changed*: "String[TypeState]" A map of _account id_ to an object 1673 encoding the state of data types that have changed for that 1674 account since the last push event, for each of the accounts to 1675 which the user has access and for which something has changed. A 1676 *TypeState* object is a map. The keys are the plural type name 1677 "Foos" (e.g. "Mailboxes" or "Messages"), and the value is the 1678 _state_ property that would currently be returned by a call to 1679 _getFoos_. The client can compare the new state strings with its 1680 current values to see whether it has the current data for these 1681 types. If not, the changes can then be efficiently fetched in a 1682 single standard API request (using the _getFooUpdates_ type 1683 methods). 1685 o *trigger*: "String" What caused this change. The following causes 1686 are defined: 1688 * "delivery": The arrival of a new message caused the change. 1690 * "user": An action by the user caused the change. 1692 * "unknown": The cause of the change is unknown. 1694 Future specifications may define further values. Clients MUST 1695 treat an unrecognised value the same as "unknown". Clients in 1696 battery constrained environments may use this information to 1697 decide whether to immediately fetch the changes. 1699 6.2. PushSubscription 1701 A push subscription is a message delivery context established between 1702 the client and a push service. A *PushSubscription* object has the 1703 following properties: 1705 o *url*: "String" An absolute URL where the JMAP server will POST 1706 the data for the push message. This MUST begin with "https://". 1708 o *expires*: "UTCDate|null" The time this push subscription expires. 1709 If specified, the JMAP server MUST NOT make further requests to 1710 this resource after this time. It MAY automatically remove the 1711 push subscription at or after this time. 1713 o *keys*: "Object|null" Client-generated encryption keys. If 1714 supplied the server MUST use them as specified in 1715 to 1716 encrypt all data sent to the push subscription. The object MUST 1717 have the following properties: 1719 * *p256dh*: the P-256 ECDH Diffie-Hellman public key as described 1720 in , encoded in URL-safe base64 representation as defined in 1722 [RFC4648]. 1724 * *auth*: the authentication secret as described in 1725 , 1726 encoded in URL-safe base64 representation as defined in 1727 [RFC4648]. 1729 Clients may register the push subscription with the JMAP server, 1730 which will then make a POST request to the associated push endpoint 1731 whenever an event occurs. 1733 The POST request MUST have a content type of "application/json" and 1734 contain the utf-8 JSON encoded _StateChange_ object as the body. The 1735 request MUST have a "TTL" header, and MAY have "Urgency" and/or 1736 "Topic" headers, as specified in section 5 of [RFC8030]. 1738 If the response code is "503" (Service Unavailable), the JMAP server 1739 MAY try again later, but may also just drop the event. If the 1740 response code is "429" (Too Many Requests) the JMAP server SHOULD 1741 attempt to reduce the frequency of pushes to that URL. Any other 1742 "4xx" or "5xx" response code MUST be considered a *permanent failure* 1743 and the push subscription should be deregistered (not tried again 1744 even for future events unless explicitly re-registered by the 1745 client). 1747 The use of this push endpoint conforms with the use of a push 1748 endpoint by an Application Server as defined in [RFC8030]. A client 1749 MAY use the rest of [RFC8030] in combination with its own Push Server 1750 to form a complete end-to-end solution, or MAY rely on alternative 1751 mechanisms to ensure the delivery of the pushed data after it leaves 1752 the JMAP server. 1754 6.2.1. setPushSubscription 1756 Each session may only have a single push subscription registered. 1757 The push subscription is tied to the access token used to create it. 1758 Should the access token expire or be revoked, the push subscription 1759 MUST be removed by the JMAP server. The client MUST re-register the 1760 push subscription after reauthenticating to resume callbacks. 1762 To set the push subscription, make a call to _setPushSubscription_. 1763 It takes the following argument: 1765 o *pushSubscription*: "PushSubscription|null" The PushSubscription 1766 object representing the endpoint the JMAP server will POST events 1767 to. This will replace any previously set subscription. Set to 1768 "null" to remove any previously registered subscription. 1770 The response to _setPushSubscription_ is called 1771 _pushSubscriptionSet_. It has no arguments. 1773 The following errors may be returned instead of the 1774 _pushSubscriptionSet_ response: 1776 "invalidUrl": Returned if the URL does not begin with "https://", or 1777 is otherwise syntactically invalid or does not resolve. 1779 "forbidden": Returned if the URL is valid, but for policy reasons the 1780 server is not willing to connect to it. 1782 6.2.2. getPushSubscription 1784 To check the currently set push subscription (if any), make a call to 1785 _getPushSubscription_. It does not take any arguments. The response 1786 is called _pushSubscription_ and it has a single argument: 1788 o *pushSubscription*: "PushSubscription|null" The PushSubscription 1789 object the JMAP server is currently posting push events to, or 1790 "null" if none. 1792 6.3. Event Source 1794 Clients that can hold open TCP connections can connect directly to 1795 the JMAP server to receive push notifications via a "text/event- 1796 stream" resource, as described in . This is a long running HTTP request down which the 1798 server can push data. 1800 When a change occurs in the data on the server, it pushes an event 1801 called *state* to any connected clients, with the _StateChange_ 1802 object as the data. 1804 The server SHOULD also send a new event id that encodes the entire 1805 server state visible to the user immediately after sending a _state_ 1806 event. When a new connection is made to the event-source endpoint, a 1807 client following the server-sent events specification [1] will send a 1808 Last-Event-ID HTTP header with the last id it saw, which the server 1809 can use to work out whether the client has missed some changes. If 1810 so, it SHOULD send these changes immediately on connection. 1812 The client MAY add a query parameter called "closeafter" with value 1813 "state" to the event-source resource URL when requesting the event- 1814 source resource. If set, the server MUST end the HTTP response after 1815 pushing a _state_ event. This can be used by clients in environments 1816 where buffering proxies prevent the pushed data from arriving 1817 immediately, or indeed at all, when operating in the usual mode. 1819 The client MAY add a query parameter called "ping", with a positive 1820 integer value representing a length of time in seconds, e.g. 1821 "ping=300". If set, the server MUST send an event called *ping* 1822 whenever this time elapses since the previous event was sent. This 1823 MUST NOT set a new event id. 1825 The server MAY modify the interval given as a query parameter to be 1826 subject to a minimum and/or maximum value. For interoperability, 1827 servers MUST NOT have a minimum allowed value higher than 30 or a 1828 maximum allowed value less than 300. 1830 The data for the ping event MUST be a JSON object containing an 1831 _interval_ property, the value (type "Number") being the interval in 1832 seconds the server is using to send pings (this may be different to 1833 the requested value if the server clamped it to be within a min/max 1834 value). 1836 Clients can monitor for the _ping_ event to help determine when the 1837 closeafter mode may be required. 1839 Refer to the Authentication section of this spec for details on how 1840 to get the URL for the event-source resource. Requests to the 1841 resource MUST be authenticated. 1843 A client MAY hold open multiple connections to the event-source 1844 resource, although it SHOULD try to use a single connection for 1845 efficiency. 1847 7. Security considerations 1849 7.1. Transport confidentiality 1851 All HTTP requests MUST use [RFC5246] TLS (https) transport to ensure 1852 the confidentiality of data sent and received via JMAP. Clients MUST 1853 validate TLS certificate chains to protect against man-in-the-middle 1854 attacks. 1856 7.2. Authentication scheme 1858 A number of HTTP authentication schemes have been standardised 1859 (). Servers should take care to assess the security 1861 characteristics of different schemes in relation to their needs when 1862 deciding what to implement. 1864 If offering the Basic authentication scheme, services are strongly 1865 recommended to not allow a user's regular password but require 1866 generation of a unique "app password" via some external mechanism for 1867 each client they wish to connect. This allows connections from 1868 different devices to be differentiated by the server, and access to 1869 be individually revoked. 1871 7.3. Service autodiscovery 1873 Unless secured by something like DNSSEC, autodiscovery of server 1874 details is vulnerable to a DNS poisoning attack leading to the client 1875 talking to an attacker's server instead of the real JMAP server. The 1876 attacker may then man-in-the-middle requests and depending on the 1877 authentication scheme, steal credentials to generate its own 1878 requests. 1880 7.4. JSON parsing 1882 The security considerations of [RFC7159] apply to the use of JSON as 1883 the data interchange format. 1885 7.5. Denial of service 1887 A small request may result in a very large response, and require 1888 considerable work on the server if resource limits are not enforced. 1889 JMAP provides mechanisms for advertising and enforcing a wide variety 1890 of limits for mitigating this threat, including limits on number of 1891 objects fetched in a single method call, number of methods in a 1892 single request, number of concurrent requests, etc. 1894 JMAP servers MUST implement sensible limits to mitigate against 1895 resource exhaustion attacks. 1897 7.6. Push encryption 1899 When data changes, a small object is pushed with the new state 1900 strings for the types that have changed. While the data here is 1901 minimal, a passive man-in-the-middle attacker may be able to gain 1902 useful information. To ensure confidentiality, if the push is sent 1903 via a third party outside of the control of the client and JMAP 1904 server the client MUST specify encryption keys when establishing the 1905 PushSubscription. 1907 The privacy and security considerations of [RFC8030] and 1908 also 1909 all apply to the use of the PushSubscription mechanism. 1911 8. References 1913 8.1. Normative References 1915 [RFC2047] Moore, K., "MIME (Multipurpose Internet Mail Extensions) 1916 Part Three: Message Header Extensions for Non-ASCII Text", 1917 RFC 2047, DOI 10.17487/RFC2047, November 1996, 1918 . 1920 [RFC2119] Bradner, S., "Key words for use in RFCs to Indicate 1921 Requirement Levels", BCP 14, RFC 2119, 1922 DOI 10.17487/RFC2119, March 1997, 1923 . 1925 [RFC2231] Freed, N. and K. Moore, "MIME Parameter Value and Encoded 1926 Word Extensions: Character Sets, Languages, and 1927 Continuations", RFC 2231, DOI 10.17487/RFC2231, November 1928 1997, . 1930 [RFC3339] Klyne, G. and C. Newman, "Date and Time on the Internet: 1931 Timestamps", RFC 3339, DOI 10.17487/RFC3339, July 2002, 1932 . 1934 [RFC3629] Yergeau, F., "UTF-8, a transformation format of ISO 1935 10646", STD 63, RFC 3629, DOI 10.17487/RFC3629, November 1936 2003, . 1938 [RFC4648] Josefsson, S., "The Base16, Base32, and Base64 Data 1939 Encodings", RFC 4648, DOI 10.17487/RFC4648, October 2006, 1940 . 1942 [RFC5246] Dierks, T. and E. Rescorla, "The Transport Layer Security 1943 (TLS) Protocol Version 1.2", RFC 5246, 1944 DOI 10.17487/RFC5246, August 2008, 1945 . 1947 [RFC5785] Nottingham, M. and E. Hammer-Lahav, "Defining Well-Known 1948 Uniform Resource Identifiers (URIs)", RFC 5785, 1949 DOI 10.17487/RFC5785, April 2010, 1950 . 1952 [RFC6186] Daboo, C., "Use of SRV Records for Locating Email 1953 Submission/Access Services", RFC 6186, 1954 DOI 10.17487/RFC6186, March 2011, 1955 . 1957 [RFC6570] Gregorio, J., Fielding, R., Hadley, M., Nottingham, M., 1958 and D. Orchard, "URI Template", RFC 6570, 1959 DOI 10.17487/RFC6570, March 2012, 1960 . 1962 [RFC6764] Daboo, C., "Locating Services for Calendaring Extensions 1963 to WebDAV (CalDAV) and vCard Extensions to WebDAV 1964 (CardDAV)", RFC 6764, DOI 10.17487/RFC6764, February 2013, 1965 . 1967 [RFC6838] Freed, N., Klensin, J., and T. Hansen, "Media Type 1968 Specifications and Registration Procedures", BCP 13, 1969 RFC 6838, DOI 10.17487/RFC6838, January 2013, 1970 . 1972 [RFC6901] Bryan, P., Ed., Zyp, K., and M. Nottingham, Ed., 1973 "JavaScript Object Notation (JSON) Pointer", RFC 6901, 1974 DOI 10.17487/RFC6901, April 2013, 1975 . 1977 [RFC7159] Bray, T., Ed., "The JavaScript Object Notation (JSON) Data 1978 Interchange Format", RFC 7159, DOI 10.17487/RFC7159, March 1979 2014, . 1981 [RFC7230] Fielding, R., Ed. and J. Reschke, Ed., "Hypertext Transfer 1982 Protocol (HTTP/1.1): Message Syntax and Routing", 1983 RFC 7230, DOI 10.17487/RFC7230, June 2014, 1984 . 1986 [RFC7235] Fielding, R., Ed. and J. Reschke, Ed., "Hypertext Transfer 1987 Protocol (HTTP/1.1): Authentication", RFC 7235, 1988 DOI 10.17487/RFC7235, June 2014, 1989 . 1991 [RFC7493] Bray, T., Ed., "The I-JSON Message Format", RFC 7493, 1992 DOI 10.17487/RFC7493, March 2015, 1993 . 1995 [RFC8030] Thomson, M., Damaggio, E., and B. Raymor, Ed., "Generic 1996 Event Delivery Using HTTP Push", RFC 8030, 1997 DOI 10.17487/RFC8030, December 2016, 1998 . 2000 8.2. URIs 2002 [1] https://html.spec.whatwg.org/multipage/server-sent-events.html 2004 Author's Address 2006 Neil Jenkins 2007 FastMail 2008 Level 2, 114 William St 2009 Melbourne VIC 3000 2010 Australia 2012 Email: neilj@fastmailteam.com 2013 URI: https://www.fastmail.com