forked from sdatspun2/idempotency-header
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathdraft.xml
More file actions
574 lines (418 loc) · 30.3 KB
/
draft.xml
File metadata and controls
574 lines (418 loc) · 30.3 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
<?xml version="1.0" encoding="utf-8"?>
<?xml-stylesheet type="text/xsl" href="rfc2629.xslt" ?>
<!-- generated by https://github.com/cabo/kramdown-rfc2629 version 1.3.15 -->
<!DOCTYPE rfc SYSTEM "rfc2629.dtd" [
]>
<?rfc toc="yes"?>
<?rfc tocindent="yes"?>
<?rfc sortrefs="yes"?>
<?rfc symrefs="yes"?>
<?rfc strict="yes"?>
<?rfc compact="yes"?>
<?rfc comments="yes"?>
<?rfc inline="yes"?>
<rfc ipr="trust200902" docName="draft-idempotency-header-00" category="std">
<front>
<title>The Idempotency HTTP Header Field</title>
<author initials="J." surname="Jena" fullname="Jayadeba Jena">
<organization></organization>
<address>
<email>jjena@paypal.com</email>
<uri>https://github.com/jjena</uri>
</address>
</author>
<author initials="S." surname="Dalal" fullname="Sanjay Dalal">
<organization></organization>
<address>
<email>sanjay.dalal@cal.berkeley.edu</email>
<uri>https://github.com/sdatspun2</uri>
</address>
</author>
<date year="2020" month="November" day="11"/>
<abstract>
<t>The <spanx style="verb">HTTP</spanx> Idempotency request header field can be used to carry idempotency key in order to make non-idempotent <spanx style="verb">HTTP</spanx> methods such as <spanx style="verb">POST</spanx> or <spanx style="verb">PATCH</spanx> fault-tolerant.</t>
</abstract>
</front>
<middle>
<section anchor="introduction" title="Introduction">
<t>Idempotence is the property of certain operations in mathematics and computer science whereby they can be applied multiple times without changing the result beyond the initial application. It does not matter if the operation is called only once, or 10s of times over. The result <spanx style="verb">SHOULD</spanx> be the same.</t>
<t>Idempotency is important in building a fault-tolerant <spanx style="verb">HTTP API</spanx>. An <spanx style="verb">HTTP</spanx> request method is considered <spanx style="verb">idempotent</spanx> if the intended effect on the server of multiple identical requests with that method is the same as the effect for a single such request. <xref target="RFC7231"/> defines methods <spanx style="verb">OPTIONS</spanx>, <spanx style="verb">HEAD</spanx>, <spanx style="verb">GET</spanx>, <spanx style="verb">PUT</spanx> and <spanx style="verb">DELETE</spanx> as idempotent. However, <spanx style="verb">POST</spanx> and <spanx style="verb">PATCH</spanx> methods are <spanx style="verb">NOT</spanx> idempotent.</t>
<t>Suppose a client on <spanx style="verb">HTTP API</spanx> wants to create or update a resource using <spanx style="verb">POST</spanx> method. Since <spanx style="verb">POST</spanx> is <spanx style="verb">NOT</spanx> an idempotent method, calling it multiple times can result in duplication or wrong updates. What would happen if you sent out the POST request to the server, but you get a timeout? Is the resource actually created or updated? Does the timeout happened during sending of the request to the server, or while receiving the response on the client? Can we safely retry again, or do we need to figure out first what has happened with the resource? If <spanx style="verb">POST</spanx> was an idempotent method, we would not have to answer such questions. We could safely resend a request until we actually get a response back from the server.</t>
<t>For many use cases in <spanx style="verb">HTTP API</spanx>, creation of duplicate records is a severe problem from business perspective. For example, in Fintech industry, duplicate records for requests involving any kind of payment transaction on a financial account <spanx style="verb">MUST NOT</spanx> be allowed. In other cases, processing of duplicate webhooks due to retries is not warranted.</t>
<section anchor="notational-conventions" title="Notational Conventions">
<t>The key words “MUST”, “MUST NOT”, “REQUIRED”, “SHALL”, “SHALL NOT”, “SHOULD”, “SHOULD NOT”, “RECOMMENDED”, “NOT RECOMMENDED”, “MAY”, and “OPTIONAL” in this document are to be interpreted as described in BCP 14 <xref target="RFC2119"/> <xref target="RFC8174"/> when, and only when, they appear in all capitals, as shown here.</t>
<t>This specification uses the Augmented Backus-Naur Form (ABNF) notation of <xref target="RFC5234"/> and includes, by reference, the IMF-fixdate rule as defined in Section 7.1.1.1 of <xref target="RFC7231"/>.</t>
<t>The term “resource” is to be interpreted as defined in Section 2 of <xref target="RFC7231"/>, that is identified by an URI.</t>
</section>
</section>
<section anchor="the-idempotency-http-request-header-field" title="The Idempotency HTTP Request Header Field">
<t>An idempotency key is a unique value generated by the client which the server uses to recognize subsequent retries of the same request. The <spanx style="verb">Idempotency-Key</spanx> HTTP request header field carries this key.</t>
<section anchor="syntax" title="Syntax">
<t>The <spanx style="verb">Idempotency-Key</spanx> request header field describes</t>
<figure><artwork><![CDATA[
Idempotency-Key = idempotency-key-value
idempotency-key-value = opaque-value
opaque-value = DQUOTE *idempotencyvalue DQUOTE
idempotencyvalue = %x21 / %x23-7E / obs-text
; VCHAR except double quotes, plus obs-text
]]></artwork></figure>
<t>Clients MUST NOT include more than one <spanx style="verb">Idempotency-Key</spanx> header field in the same request.</t>
<t>The following example shows an idempotency key using UUID version 4 scheme:</t>
<figure><artwork><![CDATA[
Idempotency-Key: "8e03978e-40d5-43e8-bc93-6894a57f9324"
]]></artwork></figure>
</section>
<section anchor="uniqueness-of-idempotency-key" title="Uniqueness of Idempotency Key">
<t>The idempotency key that is supplied as part of every <spanx style="verb">POST</spanx> request MUST be unique and can not be reused with another request with a different request payload.</t>
<t>How to make the key unique is up to the client and it’s agreed protocol with the server. It is <spanx style="verb">RECOMMENDED</spanx> that <spanx style="verb">UUID</spanx> or a similar random identifier be used as the idempotency key.</t>
</section>
<section anchor="resource-behavior" title="Resource Behavior">
<t>How an idempotency key is made unique key is determined by the client. We <spanx style="verb">RECOMMEND</spanx> using <spanx style="verb">UUID</spanx> or similar random string with enough entropy to avoid collisions.</t>
<t>The resource SHOULD save the resulting <spanx style="verb">HTTP</spanx> status code and body of the first request made for any given idempotency key, regardless of whether it succeeded or failed. Subsequent requests with the same key <spanx style="verb">MUST</spanx> return the same result, including errors.</t>
<t>It is also recommended that the resource implements the idempotency keys to be time-based and, thus, be able to purge or delete a key upon its expiry. Resource SHOULD publish expiration policy related documentation.</t>
</section>
<section anchor="error-scenarios" title="Error Scenarios">
<t>If the <spanx style="verb">Idempotency-Key</spanx> request header is missing for a documented idempotent operation requiring this header, the resource MUST reply with an <spanx style="verb">HTTP</spanx> <spanx style="verb">400</spanx> status code with body containing a link pointing to the relevant documentation. Alternately, using the <spanx style="verb">HTTP</spanx> header <spanx style="verb">Link</spanx>, client could be informed about the error too as shown below.</t>
<figure><artwork><![CDATA[
HTTP/1.1 400 Bad Request
Link: <https://developer.example.com/idempotency>;
rel="describedby"; type="text/html"
]]></artwork></figure>
<t>If there is an attempt to reuse an idempotency key with a different request payload, the resource MUST reply with an <spanx style="verb">HTTP</spanx> <spanx style="verb">422</spanx> status code with body containing a link pointing to the relevant documentation. Using the <spanx style="verb">HTTP</spanx> header <spanx style="verb">Link</spanx>, client could be informed about the error as following.</t>
<figure><artwork><![CDATA[
HTTP/1.1 422 Unprocessable Entity
Link: <https://developer.example.com/idempotency>;
rel="describedby"; type="text/html"
]]></artwork></figure>
<t>For other errors, the resource MUST return the appropriate status code and error message.</t>
</section>
</section>
<section anchor="iana-considerations" title="IANA Considerations">
<section anchor="the-idempotency-key-http-request-header-field" title="The Idempotency-Key HTTP Request Header Field">
<t>The <spanx style="verb">Idempotency-Key</spanx> request header should be added to the permanent registry of message header fields (see <xref target="RFC3864"/>), taking into account the guidelines given by HTTP/1.1 <xref target="RFC7231"/>.</t>
<figure><artwork><![CDATA[
Header Field Name: Idempotency-Key
Applicable Protocol: Hypertext Transfer Protocol (HTTP)
Status: Standard
Author: Jayadeba Jena, <jjean@paypal.com>
Sanjay Dalal <sanjay.dalal@cal.berkeley.edu>
Change controller: IETF
Specification document: this specification,
Section 2 "The Idempotency HTTP Request Header Field"
]]></artwork></figure>
</section>
</section>
<section anchor="implementation-status" title="Implementation Status">
<t>Note to RFC Editor: Please remove this section before publication.</t>
<t>This section records the status of known implementations of the protocol defined by this specification at the time of posting of this Internet-Draft, and is based on a proposal described in <xref target="RFC7942"/>. The description of implementations in this section is intended to assist the IETF in its decision processes in progressing drafts to RFCs. Please note that the listing of any individual implementation here does not imply endorsement by the IETF. Furthermore, no effort has been spent to verify the information presented here that was supplied by IETF contributors. This is not intended as, and must not be construed to be, a catalog of available implementations or their features. Readers are advised to note that
other implementations may exist.</t>
<t>According to RFC 7942, “this will allow reviewers and working groups to assign due consideration to documents that have the benefit of running code, which may serve as evidence of valuable experimentation and feedback that have made the implemented protocols more mature. It is up to the individual working groups to use this information as they see fit”.</t>
<t>Organization: Stripe</t>
<t><list style="symbols">
<t>Description: Stripe uses custom HTTP header named <spanx style="verb">Idempotency-Key</spanx></t>
<t>Reference: https://stripe.com/docs/idempotency</t>
</list></t>
<t>Organization: Adyen</t>
<t><list style="symbols">
<t>Description: Adyen uses custom HTTP header named <spanx style="verb">Idempotency-Key</spanx></t>
<t>Reference: https://docs.adyen.com/development-resources/api-idempotency/</t>
</list></t>
<t>Organization: Dwolla</t>
<t><list style="symbols">
<t>Description: Dwolla uses custom HTTP header named <spanx style="verb">Idempotency-Key</spanx></t>
<t>Reference: https://docs.dwolla.com/</t>
</list></t>
<t>Organization: Interledger</t>
<t><list style="symbols">
<t>Description: Interledger uses custom HTTP header named <spanx style="verb">Idempotency-Key</spanx></t>
<t>Reference: https://github.com/interledger/</t>
</list></t>
<t>Organization: WorldPay</t>
<t><list style="symbols">
<t>Description: WorldPay uses custom HTTP header named <spanx style="verb">Idempotency-Key</spanx></t>
<t>Reference: https://developer.worldpay.com/docs/wpg/idempotency</t>
</list></t>
<t>Organization: Yandex</t>
<t><list style="symbols">
<t>Description: Yandex uses custom HTTP header named <spanx style="verb">Idempotency-Key</spanx></t>
<t>Reference: https://cloud.yandex.com/docs/api-design-guide/concepts/idempotency</t>
</list></t>
<section anchor="implementing-the-concept" title="Implementing the Concept">
<t>This is a list of implementations that implement the general concept, but do so using different mechanisms:</t>
<t>Organization: Django</t>
<t><list style="symbols">
<t>Description: Django uses custom HTTP header named <spanx style="verb">HTTP_IDEMPOTENCY_KEY</spanx></t>
<t>Reference: https://pypi.org/project/django-idempotency-key</t>
</list></t>
<t>Organization: PayPal</t>
<t><list style="symbols">
<t>Description: PayPal uses custom HTTP header named <spanx style="verb">PayPal-Request-Id</spanx></t>
<t>Reference: https://developer.paypal.com/docs/business/develop/idempotency</t>
</list></t>
<t>Organization: RazorPay</t>
<t><list style="symbols">
<t>Description: PayPal uses custom HTTP header named <spanx style="verb">X-Payout-Idempotency</spanx></t>
<t>Reference: https://razorpay.com/docs/razorpayx/api/idempotency/</t>
</list></t>
<t>Organization: Twilio</t>
<t><list style="symbols">
<t>Description: Twilio uses custom HTTP header named <spanx style="verb">I-Twilio-Idempotency-Token</spanx> in webhooks</t>
<t>Reference: https://www.twilio.com/docs/usage/webhooks/webhooks-connection-overrides</t>
</list></t>
<t>Organization: OpenBanking</t>
<t><list style="symbols">
<t>Description: OpenBanking using custom HTTP header called <spanx style="verb">x-idempotency-key</spanx></t>
<t>Reference: https://openbankinguk.github.io/read-write-api-site3/v3.1.6/profiles/read-write-data-api-profile.html#request-headers</t>
</list></t>
<t>Organization: Square</t>
<t><list style="symbols">
<t>Description: To make an idempotent API call, Square recommends adding a property named <spanx style="verb">idempotency_key</spanx> with a unique value in the request body.</t>
<t>Reference: https://developer.squareup.com/docs/build-basics/using-rest-api</t>
</list></t>
<t>Organization: Google Standard Payments</t>
<t><list style="symbols">
<t>Description: Google Standard Payments API uses a property named <spanx style="verb">requestId</spanx> in request body in order to provider idempotency in various use cases.</t>
<t>Reference: https://developers.google.com/standard-payments/payment-processor-service-api/rest/v1/TopLevel/capture</t>
</list></t>
</section>
</section>
<section anchor="security-considerations" title="Security Considerations">
<t>This section is meant to inform developers, information providers,
and users of known security concerns specific to the HTTP conditional
request mechanisms. More general security considerations are
addressed in HTTP “Message Syntax and Routing” <xref target="RFC7230"/> and
“Semantics and Content” <xref target="RFC7231"/>.</t>
<t>The validators defined by this specification are not intended to
ensure the validity of a representation, guard against malicious
changes, or detect man-in-the-middle attacks. At best, they enable
more efficient …? when
all participants are behaving nicely. At worst, the conditions will
fail and the client will receive a response that is no more harmful
than an HTTP exchange without conditional requests.</t>
<t>An entity-tag can be abused in ways that create ? risks.</t>
</section>
<section anchor="examples" title="Examples">
<t>The first example shows an idempotency-key header field with key value using UUID version 4 scheme:</t>
<figure><artwork><![CDATA[
Idempotency-Key: "8e03978e-40d5-43e8-bc93-6894a57f9324"
]]></artwork></figure>
<t>Second example shows an idempotency-key header field with key value using some random string generator:</t>
<figure><artwork><![CDATA[
Idempotency-Key: "clkyoesmbgybucifusbbtdsbohtyuuwz"
]]></artwork></figure>
</section>
</middle>
<back>
<references title='Normative References'>
<reference anchor="RFC7231" target='https://www.rfc-editor.org/info/rfc7231'>
<front>
<title>Hypertext Transfer Protocol (HTTP/1.1): Semantics and Content</title>
<author initials='R.' surname='Fielding' fullname='R. Fielding' role='editor'><organization /></author>
<author initials='J.' surname='Reschke' fullname='J. Reschke' role='editor'><organization /></author>
<date year='2014' month='June' />
<abstract><t>The Hypertext Transfer Protocol (HTTP) is a stateless \%application- level protocol for distributed, collaborative, hypertext information systems. This document defines the semantics of HTTP/1.1 messages, as expressed by request methods, request header fields, response status codes, and response header fields, along with the payload of messages (metadata and body content) and mechanisms for content negotiation.</t></abstract>
</front>
<seriesInfo name='RFC' value='7231'/>
<seriesInfo name='DOI' value='10.17487/RFC7231'/>
</reference>
<reference anchor="RFC2119" target='https://www.rfc-editor.org/info/rfc2119'>
<front>
<title>Key words for use in RFCs to Indicate Requirement Levels</title>
<author initials='S.' surname='Bradner' fullname='S. Bradner'><organization /></author>
<date year='1997' month='March' />
<abstract><t>In many standards track documents several words are used to signify the requirements in the specification. These words are often capitalized. This document defines these words as they should be interpreted in IETF documents. This document specifies an Internet Best Current Practices for the Internet Community, and requests discussion and suggestions for improvements.</t></abstract>
</front>
<seriesInfo name='BCP' value='14'/>
<seriesInfo name='RFC' value='2119'/>
<seriesInfo name='DOI' value='10.17487/RFC2119'/>
</reference>
<reference anchor="RFC8174" target='https://www.rfc-editor.org/info/rfc8174'>
<front>
<title>Ambiguity of Uppercase vs Lowercase in RFC 2119 Key Words</title>
<author initials='B.' surname='Leiba' fullname='B. Leiba'><organization /></author>
<date year='2017' month='May' />
<abstract><t>RFC 2119 specifies common key words that may be used in protocol specifications. This document aims to reduce the ambiguity by clarifying that only UPPERCASE usage of the key words have the defined special meanings.</t></abstract>
</front>
<seriesInfo name='BCP' value='14'/>
<seriesInfo name='RFC' value='8174'/>
<seriesInfo name='DOI' value='10.17487/RFC8174'/>
</reference>
<reference anchor="RFC5234" target='https://www.rfc-editor.org/info/rfc5234'>
<front>
<title>Augmented BNF for Syntax Specifications: ABNF</title>
<author initials='D.' surname='Crocker' fullname='D. Crocker' role='editor'><organization /></author>
<author initials='P.' surname='Overell' fullname='P. Overell'><organization /></author>
<date year='2008' month='January' />
<abstract><t>Internet technical specifications often need to define a formal syntax. Over the years, a modified version of Backus-Naur Form (BNF), called Augmented BNF (ABNF), has been popular among many Internet specifications. The current specification documents ABNF. It balances compactness and simplicity with reasonable representational power. The differences between standard BNF and ABNF involve naming rules, repetition, alternatives, order-independence, and value ranges. This specification also supplies additional rule definitions and encoding for a core lexical analyzer of the type common to several Internet specifications. [STANDARDS-TRACK]</t></abstract>
</front>
<seriesInfo name='STD' value='68'/>
<seriesInfo name='RFC' value='5234'/>
<seriesInfo name='DOI' value='10.17487/RFC5234'/>
</reference>
<reference anchor="RFC3864" target='https://www.rfc-editor.org/info/rfc3864'>
<front>
<title>Registration Procedures for Message Header Fields</title>
<author initials='G.' surname='Klyne' fullname='G. Klyne'><organization /></author>
<author initials='M.' surname='Nottingham' fullname='M. Nottingham'><organization /></author>
<author initials='J.' surname='Mogul' fullname='J. Mogul'><organization /></author>
<date year='2004' month='September' />
<abstract><t>This specification defines registration procedures for the message header fields used by Internet mail, HTTP, Netnews and other applications. This document specifies an Internet Best Current Practices for the Internet Community, and requests discussion and suggestions for improvements.</t></abstract>
</front>
<seriesInfo name='BCP' value='90'/>
<seriesInfo name='RFC' value='3864'/>
<seriesInfo name='DOI' value='10.17487/RFC3864'/>
</reference>
<reference anchor="RFC7230" target='https://www.rfc-editor.org/info/rfc7230'>
<front>
<title>Hypertext Transfer Protocol (HTTP/1.1): Message Syntax and Routing</title>
<author initials='R.' surname='Fielding' fullname='R. Fielding' role='editor'><organization /></author>
<author initials='J.' surname='Reschke' fullname='J. Reschke' role='editor'><organization /></author>
<date year='2014' month='June' />
<abstract><t>The Hypertext Transfer Protocol (HTTP) is a stateless application-level protocol for distributed, collaborative, hypertext information systems. This document provides an overview of HTTP architecture and its associated terminology, defines the "http" and "https" Uniform Resource Identifier (URI) schemes, defines the HTTP/1.1 message syntax and parsing requirements, and describes related security concerns for implementations.</t></abstract>
</front>
<seriesInfo name='RFC' value='7230'/>
<seriesInfo name='DOI' value='10.17487/RFC7230'/>
</reference>
</references>
<references title='Informative References'>
<reference anchor="RFC7942" target='https://www.rfc-editor.org/info/rfc7942'>
<front>
<title>Improving Awareness of Running Code: The Implementation Status Section</title>
<author initials='Y.' surname='Sheffer' fullname='Y. Sheffer'><organization /></author>
<author initials='A.' surname='Farrel' fullname='A. Farrel'><organization /></author>
<date year='2016' month='July' />
<abstract><t>This document describes a simple process that allows authors of Internet-Drafts to record the status of known implementations by including an Implementation Status section. This will allow reviewers and working groups to assign due consideration to documents that have the benefit of running code, which may serve as evidence of valuable experimentation and feedback that have made the implemented protocols more mature.</t><t>This process is not mandatory. Authors of Internet-Drafts are encouraged to consider using the process for their documents, and working groups are invited to think about applying the process to all of their protocol specifications. This document obsoletes RFC 6982, advancing it to a Best Current Practice.</t></abstract>
</front>
<seriesInfo name='BCP' value='205'/>
<seriesInfo name='RFC' value='7942'/>
<seriesInfo name='DOI' value='10.17487/RFC7942'/>
</reference>
</references>
<section anchor="acknowledgments" title="Acknowledgments">
<t>The authors would like to thank Mark Nottingham for his support for this Internet Draft. We would like to acknowledge that this draft is inspired by Idempotency related patterns described in API documentation of <eref target="https://github.com/paypal/api-standards/blob/master/patterns.md#idempotency">PayPal</eref> and <eref target="https://stripe.com/docs/idempotency">Stripe</eref> as well as Internet Draft on <eref target="https://tools.ietf.org/html/draft-nottingham-http-poe-00">POST Once Exactly</eref> authored by Mark Nottingham.</t>
<t>The authors take all responsibility for errors and omissions.</t>
</section>
<section anchor="appendix" title="Appendix">
<section anchor="appendix-a-imported-abnf" title="Appendix A. Imported ABNF">
<t>The following core rules are included by reference, as defined in Appendix B.1 of <xref target="RFC5234"></xref>: ALPHA (letters), CR (carriage return), CRLF (CR LF), CTL (controls), DIGIT (decimal 0-9), DQUOTE (double quote), HEXDIG (hexadecimal 0-9/A-F/a-f), LF (line feed), OCTET (any 8-bit sequence of data), SP (space), and VCHAR (any visible US-ASCII character).</t>
<t>The rules below are defined in <xref target="RFC7230"></xref>:</t>
<figure><artwork><![CDATA[
obs-text = <obs-text, see [RFC7230], Section 3.2.6>
]]></artwork></figure>
</section>
</section>
</back>
<!-- ##markdown-source:
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
MQAA
-->
</rfc>