idnits 2.17.1 draft-ietf-jmap-websocket-05.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 : ---------------------------------------------------------------------------- No issues found here. Miscellaneous warnings: ---------------------------------------------------------------------------- == The copyright year in the IETF Trust and authors Copyright Line does not match the current year -- The document date (January 31, 2020) is 1540 days in the past. Is this intentional? Checking references for intended status: Proposed Standard ---------------------------------------------------------------------------- (See RFCs 3967 and 4897 for information about using normative references to lower-maturity documents in RFCs) ** Obsolete normative reference: RFC 2818 (Obsoleted by RFC 9110) ** Obsolete normative reference: RFC 5246 (Obsoleted by RFC 8446) ** Obsolete normative reference: RFC 7235 (Obsoleted by RFC 9110) ** Obsolete normative reference: RFC 7525 (Obsoleted by RFC 9325) ** Obsolete normative reference: RFC 7540 (Obsoleted by RFC 9113) Summary: 5 errors (**), 0 flaws (~~), 1 warning (==), 1 comment (--). Run idnits with the --verbose option for more detailed information about the items above. -------------------------------------------------------------------------------- 2 JMAP K. Murchison 3 Internet-Draft Fastmail 4 Intended status: Standards Track January 31, 2020 5 Expires: August 3, 2020 7 A JSON Meta Application Protocol (JMAP) Subprotocol for WebSocket 8 draft-ietf-jmap-websocket-05 10 Abstract 12 This document defines a binding for the JSON Meta Application 13 Protocol (JMAP) over a WebSocket transport layer. The WebSocket 14 binding for JMAP provides higher performance than the current HTTP 15 binding for JMAP. 17 Status of This Memo 19 This Internet-Draft is submitted in full conformance with the 20 provisions of BCP 78 and BCP 79. 22 Internet-Drafts are working documents of the Internet Engineering 23 Task Force (IETF). Note that other groups may also distribute 24 working documents as Internet-Drafts. The list of current Internet- 25 Drafts is at https://datatracker.ietf.org/drafts/current/. 27 Internet-Drafts are draft documents valid for a maximum of six months 28 and may be updated, replaced, or obsoleted by other documents at any 29 time. It is inappropriate to use Internet-Drafts as reference 30 material or to cite them other than as "work in progress." 32 This Internet-Draft will expire on August 3, 2020. 34 Copyright Notice 36 Copyright (c) 2020 IETF Trust and the persons identified as the 37 document authors. All rights reserved. 39 This document is subject to BCP 78 and the IETF Trust's Legal 40 Provisions Relating to IETF Documents 41 (https://trustee.ietf.org/license-info) in effect on the date of 42 publication of this document. Please review these documents 43 carefully, as they describe your rights and restrictions with respect 44 to this document. Code Components extracted from this document must 45 include Simplified BSD License text as described in Section 4.e of 46 the Trust Legal Provisions and are provided without warranty as 47 described in the Simplified BSD License. 49 Table of Contents 51 1. Introduction . . . . . . . . . . . . . . . . . . . . . . . . 2 52 2. Conventions Used in This Document . . . . . . . . . . . . . . 3 53 3. Discovering Support for JMAP over WebSocket . . . . . . . . . 3 54 4. JMAP Subprotocol . . . . . . . . . . . . . . . . . . . . . . 3 55 4.1. Authentication . . . . . . . . . . . . . . . . . . . . . 4 56 4.2. Handshake . . . . . . . . . . . . . . . . . . . . . . . . 4 57 4.3. WebSocket Messages . . . . . . . . . . . . . . . . . . . 5 58 4.3.1. Handling Invalid Data . . . . . . . . . . . . . . . . 5 59 4.3.2. JMAP Requests . . . . . . . . . . . . . . . . . . . . 5 60 4.3.3. JMAP Responses . . . . . . . . . . . . . . . . . . . 6 61 4.3.4. JMAP Request-Level Errors . . . . . . . . . . . . . . 6 62 4.3.5. JMAP Push Notifications . . . . . . . . . . . . . . . 6 63 4.4. Examples . . . . . . . . . . . . . . . . . . . . . . . . 7 64 5. Security Considerations . . . . . . . . . . . . . . . . . . . 12 65 6. IANA Considerations . . . . . . . . . . . . . . . . . . . . . 12 66 6.1. Registration of the WebSocket JMAP Subprotocol . . . . . 12 67 7. Acknowledgments . . . . . . . . . . . . . . . . . . . . . . . 12 68 8. References . . . . . . . . . . . . . . . . . . . . . . . . . 12 69 8.1. Normative References . . . . . . . . . . . . . . . . . . 12 70 8.2. Informative References . . . . . . . . . . . . . . . . . 14 71 Appendix A. Change History (To be removed by RFC Editor before 72 publication) . . . . . . . . . . . . . . . . . . . . 14 73 Author's Address . . . . . . . . . . . . . . . . . . . . . . . . 16 75 1. Introduction 77 JMAP [RFC8620] over HTTP [RFC7235] requires that every JMAP API 78 request be authenticated. Depending on the type of authentication 79 used by the JMAP client and the configuration of the JMAP server, 80 authentication could be an expensive operation both in time and 81 resources. In such circumstances, reauthenticating for every JMAP 82 API request may harm performance. 84 The WebSocket [RFC6455] binding for JMAP eliminates this performance 85 hit by authenticating just the WebSocket handshake request and having 86 those credentials remain in effect for the duration of the WebSocket 87 connection. This binding supports JMAP API requests and responses, 88 with optional support for push notifications. 90 Furthermore, the WebSocket binding for JMAP can optionally compress 91 [RFC7692] both JMAP API requests and responses. Although compression 92 of HTTP responses is ubiquitous, compression of HTTP requests has 93 very low, if any deployment, and therefore isn't a viable option for 94 JMAP API requests over HTTP. 96 2. Conventions Used in This Document 98 The key words "MUST", "MUST NOT", "REQUIRED", "SHALL", "SHALL NOT", 99 "SHOULD", "SHOULD NOT", "RECOMMENDED", "NOT RECOMMENDED", "MAY", and 100 "OPTIONAL" in this document are to be interpreted as described in 101 BCP 14 [RFC2119] [RFC8174] when, and only when, they appear in all 102 capitals, as shown here. 104 The same terminology is used in this document as in the core JMAP 105 specification. 107 3. Discovering Support for JMAP over WebSocket 109 The JMAP capabilities object is returned as part of the standard JMAP 110 Session object (see Section 2 of [RFC8620]). Servers supporting this 111 specification MUST add a property named 112 "urn:ietf:params:jmap:websocket" to the capabilities object. The 113 value of this property is an object which MUST contain the following 114 information on server capabilities: 116 o webSocketUrl: "String" 118 The wss-URI (see Section 3 of [RFC6455]) to use for initiating a 119 JMAP over WebSocket handshake. 121 o supportsWebSocketPush: "Boolean" 123 This is true if the server supports push notifications over the 124 WebSocket, as described in Section 4.3.5. 126 Example: 128 "urn:ietf:params:jmap:websocket": { 129 "webSocketUrl": "wss://server.example.com/jmap/ws/", 130 "supportsWebSocketPush": true 131 } 133 4. JMAP Subprotocol 135 The term WebSocket subprotocol refers to an application-level 136 protocol layered on top of a WebSocket connection. This document 137 specifies the WebSocket JMAP subprotocol for carrying JMAP API 138 requests, responses, and optional push notifications through a 139 WebSocket connection. Binary data MUST NOT be uploaded or downloaded 140 through a WebSocket JMAP connection. Binary data is handled per 141 Section 6 of [RFC8620] via a separate HTTP connection or stream. 143 4.1. Authentication 145 A JMAP WebSocket connection is authenticated by presenting a user's 146 credentials in the HTTP request [RFC7235] that initiates the 147 WebSocket handshake. The recommendations regarding the selection of 148 authentication scheme in Section 8.2 of [RFC8620] MUST be considered. 150 4.2. Handshake 152 The JMAP WebSocket client and JMAP WebSocket server negotiate the use 153 of the WebSocket JMAP subprotocol during the WebSocket handshake, 154 either via a HTTP/1.1 Upgrade request (see Section 4 of [RFC6455]) or 155 a HTTP/2 Extended CONNECT request (see Section 5 of [RFC8441]). The 156 WebSocket JMAP subprotocol is also intended to run over future 157 bindings of HTTP (e.g. HTTP/3) provided that there is a defined 158 mechanism for performing a WebSocket handshake over that binding. 160 Regardless of the method used for the WebSocket handshake, the client 161 MUST first perform a TLS handshake on a JMAP "webSocketUrl" 162 (Section 3) having the "wss://" scheme (WebSocket over TLS) in 163 accordance with the requirements of running the particular binding of 164 HTTP over TLS (see [RFC2818] and Section 4.1 of [RFC6455] for 165 HTTP/1.1 and Section 9.2 of [RFC7540] for HTTP/2). If the TLS 166 handshake fails, the client MUST close the connection. Otherwise, 167 the client MUST make an authenticated [RFC7235] HTTP request on the 168 encrypted connection, and MUST include the value "jmap" in the list 169 of protocols for the "Sec-WebSocket-Protocol" header field. 171 The reply from the server MUST also contain a corresponding "Sec- 172 WebSocket-Protocol" header field with a value of "jmap" in order for 173 a JMAP subprotocol connection to be established. If a client 174 receives a handshake response that does not include a "Sec-WebSocket- 175 Protocol" header field with a value of "jmap", then a JMAP 176 subprotocol WebSocket connection was not established and the client 177 MUST close the WebSocket connection. 179 Once the handshake has successfully completed, the WebSocket 180 connection is established and can be used for JMAP API requests, 181 responses, and optional push notifications. Other message types MUST 182 NOT be transmitted over this connection. 184 The credentials used for authenticating the HTTP request to initiate 185 the handshake remain in effect for the duration of the WebSocket 186 connection. If the authentication credentials for the user expire, 187 the server MUST send a Close frame with a 1008 status code and then 188 close the WebSocket connection. 190 4.3. WebSocket Messages 192 Data frame messages in the JMAP subprotocol MUST be text frames and 193 contain UTF-8 encoded data. The messages MUST be in the form of a 194 single JMAP Request object (see Section 3.3 of [RFC8620]), JMAP 195 WebSocketPushEnable object (see Section 4.3.5.2), or JMAP 196 WebSocketPushDisable object (see Section 4.3.5.3) when sent from the 197 client to the server, and in the form of a single JMAP Response 198 object, JSON Problem Details object, or JMAP StateChange object (see 199 Sections 3.4, 3.6.1, and 7.1 respectively of [RFC8620]) when sent 200 from the server to the client. 202 Note that fragmented WebSocket messages (split over multiple text 203 frames) MUST be coalesced prior to parsing them as JSON objects. 205 4.3.1. Handling Invalid Data 207 If a client or server receives a binary frame, the endpoint SHOULD 208 send a Close frame with a 1003 status code and then close the 209 WebSocket connection. 211 If a server receives a text frame containing an unsupported JMAP 212 object, the server SHOULD treat it as a JMAP Request-Level Error 213 (Section 4.3.4) and return an appropriate JSON Problem Details 214 object. 216 If a client receives a text frame containing an unsupported JSON 217 object, the client SHOULD send a Close frame with a 1007 status code 218 and then close the WebSocket connection. 220 4.3.2. JMAP Requests 222 This specification adds two extra arguments to the Request object: 224 o @type: "String" 226 This MUST be the string "Request". 228 o id: "String" (optional) 230 A client-specified identifier for the request to be echoed back in 231 the response to this request. 233 JMAP over WebSocket allows the server to process requests out of 234 order. The client-specified identifier is used as a mechanism for 235 the client to correlate requests and responses. 237 Additionally, the "maxConcurrentRequests" limit in the "capabilities" 238 object (see Section 2 of [RFC8620]) also applies to requests made on 239 the WebSocket connection. When using the WebSocket JMAP subprotocol 240 over a binding of HTTP that allows multiplexing of requests (e.g. 241 HTTP/2), this limit applies to the the sum of requests made on both 242 the JMAP API endpoint and the WebSocket connection. 244 4.3.3. JMAP Responses 246 This specification adds two extra arguments to the Response object: 248 o @type: "String" 250 This MUST be the string "Response". 252 o requestId: "String" (optional; MUST be returned if an id is 253 included in the request) 255 The client-specified identifier in the corresponding request. 257 4.3.4. JMAP Request-Level Errors 259 This specification adds two extra arguments to the Problem Details 260 object: 262 o @type: "String" 264 This MUST be the string "RequestError". 266 o requestId: "String" (optional; MUST be returned if given in the 267 request) 269 The client-specified identifier in the corresponding request. 271 4.3.5. JMAP Push Notifications 273 JMAP over WebSocket servers that support push notifications on the 274 WebSocket will advertise a "supportsWebSocketPush" property with a 275 value of true in the server capabilities object. 277 4.3.5.1. Notification Format 279 All push notifications take the form of a standard StateChange object 280 (see Section 7.1 of [RFC8620]). 282 This specification adds one extra argument to the StateChange object: 284 o pushState: "String" (optional) 285 A (preferably short) string that encodes the entire server state 286 visible to the user (not just the objects returned in this call). 288 The purpose of the "pushState" token is to allow a client to 289 immediately get any changes that occurred while is was 290 disconnected (see Section 4.3.5.2). If the server does not 291 support "pushState" tokens, the client will have issue a series of 292 "/changes" requests (see Section 5.2 of [RFC8620]) upon 293 reconnection to update its state to match that of the server. 295 4.3.5.2. Enabling Notifications 297 A client enables push notifications from the server for the current 298 connection by sending a WebSocketPushEnable object to the server. A 299 WebSocketPushEnable object has the following properties: 301 o @type: "String" This MUST be the string "WebSocketPushEnable". 303 o dataTypes: "String[]|null" 305 A list of data type names (e.g. "Mailbox", "Email") that the 306 client is interested in. A StateChange notification will only be 307 sent if the data for one of these types changes. Other types are 308 omitted from the TypeState object. If null, changes will be 309 pushed for all supported data types. 311 o pushState: "String" (optional) 313 The last "pushState" token that the client received from the 314 server. Upon receipt of a "pushState" token, the server SHOULD 315 immediately send all changes since that state token. 317 4.3.5.3. Disabling Notifications 319 A client disables push notifications from the server for the current 320 connection by sending a WebSocketPushDisable object to the server. A 321 WebSocketPushDisable object has the following property: 323 o @type: "String" 325 This MUST be the string "WebSocketPushDisable". 327 4.4. Examples 329 The following examples show WebSocket JMAP opening handshakes, a JMAP 330 Core/echo request and response, and a subsequent closing handshake. 331 The examples assume that the JMAP "webSocketUrl" has been advertised 332 in the JMAP Session object as having a path of "/jmap/ws/" and that 333 TLS negotiation has already succeeded. Note that folding of header 334 fields is for editorial purposes only. 336 WebSocket JMAP connection via HTTP/1.1 with push notifications for 337 mail [RFC8621] enabled. This example assumes that the client has 338 cached pushState "aaa" from a previous connection. 340 [[ From Client ]] [[ From Server ]] 342 GET /jmap/ws/ HTTP/1.1 343 Host: server.example.com 344 Upgrade: websocket 345 Connection: Upgrade 346 Authorization: Basic Zm9vOmJhcg== 347 Sec-WebSocket-Key: 348 dGhlIHNhbXBsZSBub25jZQ== 349 Sec-WebSocket-Protocol: jmap 350 Sec-WebSocket-Version: 13 351 Origin: http://www.example.com 353 HTTP/1.1 101 Switching Protocols 354 Upgrade: websocket 355 Connection: Upgrade 356 Sec-WebSocket-Accept: 357 s3pPLMBiTxaQ9kYGzzhZRbK+xOo= 358 Sec-WebSocket-Protocol: jmap 360 [WebSocket connection established] 362 WS_DATA 363 { 364 "@type": "WebSocketPushEnable", 365 "dataTypes": [ "Mailbox", "Email" ], 366 "pushState": "aaa" 367 } 369 WS_DATA 370 { 371 "@type": "StateChange", 372 "changed": { 373 "a456": { 374 "Mailbox": "d35ecb040aab" 375 } 376 }, 377 "pushState": "bbb" 378 } 380 WS_DATA 381 { 382 "@type": "Request", 383 "id": "R1", 384 "using": [ "urn:ietf:params:jmap:core" ], 385 "methodCalls": [ 386 [ 387 "Core/echo", { 388 "hello": true, 389 "high": 5 390 }, 391 "b3ff" 392 ] 393 ] 394 } 396 WS_DATA 397 { 398 "@type": "Response", 399 "requestId": "R1", 400 "methodResponses": [ 401 [ 402 "Core/echo", { 403 "hello": true, 404 "high": 5 405 }, 406 "b3ff" 407 ] 408 ] 409 } 411 WS_DATA 412 The quick brown fox jumps 413 over the lazy dog. 415 WS_DATA 416 { 417 "@type": "RequestError", 418 "requestId": null, 419 "type": 420 "urn:ietf:params:jmap:error:notJSON", 421 "status": 400, 422 "detail": 423 "The request did not parse as I-JSON." 424 } 426 [A new email is received] 428 WS_DATA 429 { 430 "@type": "StateChange", 431 "changed": { 432 "a123": { 433 "Email": "0af7a512ce70" 434 } 435 } 436 "pushState": "ccc" 437 } 439 WS_CLOSE 441 WS_CLOSE 443 [WebSocket connection closed] 444 WebSocket JMAP connection on a HTTP/2 stream which also negotiates 445 compression [RFC7692]: 447 [[ From Client ]] [[ From Server ]] 449 SETTINGS 450 SETTINGS_ENABLE_CONNECT_PROTOCOL = 1 452 HEADERS + END_HEADERS 453 :method = CONNECT 454 :protocol = websocket 455 :scheme = https 456 :path = /jmap/ws/ 457 :authority = server.example.com 458 authorization = Basic Zm9vOmJhcg== 459 sec-websocket-protocol = jmap 460 sec-websocket-version = 13 461 sec-websocket-extensions = 462 permessage-deflate 463 origin = http://www.example.com 465 HEADERS + END_HEADERS 466 :status = 200 467 sec-websocket-protocol = jmap 468 sec-websocket-extensions = 469 permessage-deflate 471 [WebSocket connection established] 473 DATA 474 WS_DATA 475 [compressed text] 477 DATA 478 WS_DATA 479 [compressed text] 481 ... 483 DATA + END_STREAM 484 WS_CLOSE 486 DATA + END_STREAM 487 WS_CLOSE 489 [WebSocket connection closed] 490 [HTTP/2 stream closed] 492 5. Security Considerations 494 The security considerations for both WebSocket (see Section 10 of 495 [RFC6455]) and JMAP (see Section 8 of [RFC8620]) apply to the 496 WebSocket JMAP subprotocol. 498 Specifically, to ensure the confidentiality and integrity of data 499 sent and received via JMAP over WebSocket, the WebSocket connection 500 MUST use TLS 1.2 [RFC5246] or later, following the recommendations in 501 [RFC7525]. Servers SHOULD support TLS 1.3 [RFC8446] or later. 503 6. IANA Considerations 505 6.1. Registration of the WebSocket JMAP Subprotocol 507 This specification requests IANA to register the WebSocket JMAP 508 subprotocol under the "WebSocket Subprotocol Name" Registry with the 509 following data: 511 Subprotocol Identifier: jmap 513 Subprotocol Common Name: WebSocket Transport for JMAP (JSON Meta 514 Application Protocol) 516 Subprotocol Definition: RFCXXXX (this document) 518 7. Acknowledgments 520 The author would like to thank the following individuals for 521 contributing their ideas and support for writing this specification: 522 Neil Jenkins, Robert Mueller, and Chris Newman. 524 8. References 526 8.1. Normative References 528 [RFC2119] Bradner, S., "Key words for use in RFCs to Indicate 529 Requirement Levels", BCP 14, RFC 2119, 530 DOI 10.17487/RFC2119, March 1997, 531 . 533 [RFC2818] Rescorla, E., "HTTP Over TLS", RFC 2818, 534 DOI 10.17487/RFC2818, May 2000, 535 . 537 [RFC5246] Dierks, T. and E. Rescorla, "The Transport Layer Security 538 (TLS) Protocol Version 1.2", RFC 5246, 539 DOI 10.17487/RFC5246, August 2008, 540 . 542 [RFC6455] Fette, I. and A. Melnikov, "The WebSocket Protocol", 543 RFC 6455, DOI 10.17487/RFC6455, December 2011, 544 . 546 [RFC7235] Fielding, R., Ed. and J. Reschke, Ed., "Hypertext Transfer 547 Protocol (HTTP/1.1): Authentication", RFC 7235, 548 DOI 10.17487/RFC7235, June 2014, 549 . 551 [RFC7525] Sheffer, Y., Holz, R., and P. Saint-Andre, 552 "Recommendations for Secure Use of Transport Layer 553 Security (TLS) and Datagram Transport Layer Security 554 (DTLS)", BCP 195, RFC 7525, DOI 10.17487/RFC7525, May 555 2015, . 557 [RFC7540] Belshe, M., Peon, R., and M. Thomson, Ed., "Hypertext 558 Transfer Protocol Version 2 (HTTP/2)", RFC 7540, 559 DOI 10.17487/RFC7540, May 2015, 560 . 562 [RFC7692] Yoshino, T., "Compression Extensions for WebSocket", 563 RFC 7692, DOI 10.17487/RFC7692, December 2015, 564 . 566 [RFC8174] Leiba, B., "Ambiguity of Uppercase vs Lowercase in RFC 567 2119 Key Words", BCP 14, RFC 8174, DOI 10.17487/RFC8174, 568 May 2017, . 570 [RFC8441] McManus, P., "Bootstrapping WebSockets with HTTP/2", 571 RFC 8441, DOI 10.17487/RFC8441, September 2018, 572 . 574 [RFC8446] Rescorla, E., "The Transport Layer Security (TLS) Protocol 575 Version 1.3", RFC 8446, DOI 10.17487/RFC8446, August 2018, 576 . 578 [RFC8620] Jenkins, N. and C. Newman, "The JSON Meta Application 579 Protocol (JMAP)", RFC 8620, DOI 10.17487/RFC8620, July 580 2019, . 582 8.2. Informative References 584 [RFC8621] Jenkins, N. and C. Newman, "The JSON Meta Application 585 Protocol (JMAP) for Mail", RFC 8621, DOI 10.17487/RFC8621, 586 August 2019, . 588 Appendix A. Change History (To be removed by RFC Editor before 589 publication) 591 Changes since ietf-04: 593 o Require the use of TLS for JMAP over WebSocket (per Alissa Cooper 594 and others). 596 o Added a section explaining how to handle unsupported messages (per 597 Bob Briscoe). 599 o Added a section specifically addressing authentication of the 600 WebSocket (per Leif Johansson). 602 o Corrected references into specific sections of RFC 8620 (per 603 Martin Vigoureax). 605 o Made RFC 7692 a normative reference (per Barry Leiba). 607 o Clarified that the "maxConcurrentRequests" limit applies to the 608 sum of all requests on the current connection (per Benjamin 609 Kaduk). 611 o Clarified that the "pushState" token represents the entire server 612 state visible to the user (per Banjamin Kaduk). 614 o Clarified that "WebSocketPushEnable/Disable" only effect the 615 current connection (per Benjamin Kaduk). 617 o Several editorial improvements from Benjamin Kaduk. 619 Changes since ietf-03: 621 o Updated JMAP Mail reference to RFC 8621. 623 o Specified that requestId MUST be present in a response if given in 624 the request. 626 Changes since ietf-02: 628 o Updated JMAP Core reference to RFC 8620. 630 o Added 'WebSocketPushDisable' object. 632 o Editorial and formatting changes. 634 Changes since ietf-01: 636 o Changed 'wsURL' to 'webSocketUrl' and removed push query option. 638 o Added 'supportsWebSocketPush' capability. 640 o Added '@type' argument to Request object. 642 o Added 'WebSocketPushEnable' object. 644 o Added 'pushState' argument to StateChange object. 646 o Updated example. 648 o Minor Editorial changes. 650 Changes since ietf-00: 652 o Added text describing advertisement of and selection of optional 653 push notifications. 655 o Minor Editorial changes. 657 Changes since murchison-02: 659 o Renamed as a JMAP WG document. 661 o Allow out of order processing. 663 o Allow push notifications. 665 o Modified examples. 667 o Add Security Considerations text. 669 o Minor Editorial changes. 671 Changes since murchison-01: 673 o Updated WebSocket over HTTP/2 reference to RFC8144. 675 Changes since murchison-00: 677 o Fleshed out section on discovery of support for JMAP over 678 WebSocket. 680 o Allow JSON Problem Details objects to be returned by the server 681 for toplevel errors. 683 o Mentioned the ability to compress JMAP API requests. 685 o Minor Editorial changes. 687 Author's Address 689 Kenneth Murchison 690 Fastmail US LLC 691 1429 Walnut Street - Suite 1201 692 Philadelphia, PA 19102 693 USA 695 Email: murch@fastmailteam.com 696 URI: http://www.fastmail.com/