draft-ietf-httpapi-ratelimit-headers-00.unpg.txt | draft-ietf-httpapi-ratelimit-headers-latest.txt | |||
---|---|---|---|---|
HTTPAPI Working Group R. Polli | HTTPAPI Working Group R. Polli | |||
Internet-Draft Team Digitale, Italian Government | Internet-Draft Team Digitale, Italian Government | |||
Intended status: Standards Track A. Martinez | Intended status: Standards Track A. Martinez | |||
Expires: June 21, 2021 Red Hat | Expires: August 9, 2021 Red Hat | |||
December 18, 2020 | February 05, 2021 | |||
RateLimit Header Fields for HTTP | RateLimit Header Fields for HTTP | |||
draft-ietf-httpapi-ratelimit-headers-00 | draft-ietf-httpapi-ratelimit-headers-latest | |||
Abstract | Abstract | |||
This document defines the RateLimit-Limit, RateLimit-Remaining, | This document defines the RateLimit-Limit, RateLimit-Remaining, | |||
RateLimit-Reset fields for HTTP, thus allowing servers to publish | RateLimit-Reset fields for HTTP, thus allowing servers to publish | |||
current request quotas and clients to shape their request policy and | current request quotas and clients to shape their request policy and | |||
avoid being throttled out. | avoid being throttled out. | |||
Note to Readers | Note to Readers | |||
skipping to change at line 44 ¶ | skipping to change at page 1, line 45 ¶ | |||
Internet-Drafts are working documents of the Internet Engineering | Internet-Drafts are working documents of the Internet Engineering | |||
Task Force (IETF). Note that other groups may also distribute | Task Force (IETF). Note that other groups may also distribute | |||
working documents as Internet-Drafts. The list of current Internet- | working documents as Internet-Drafts. The list of current Internet- | |||
Drafts is at https://datatracker.ietf.org/drafts/current/. | Drafts is at https://datatracker.ietf.org/drafts/current/. | |||
Internet-Drafts are draft documents valid for a maximum of six months | Internet-Drafts are draft documents valid for a maximum of six months | |||
and may be updated, replaced, or obsoleted by other documents at any | and may be updated, replaced, or obsoleted by other documents at any | |||
time. It is inappropriate to use Internet-Drafts as reference | time. It is inappropriate to use Internet-Drafts as reference | |||
material or to cite them other than as "work in progress." | material or to cite them other than as "work in progress." | |||
This Internet-Draft will expire on June 21, 2021. | This Internet-Draft will expire on August 9, 2021. | |||
Copyright Notice | Copyright Notice | |||
Copyright (c) 2020 IETF Trust and the persons identified as the | Copyright (c) 2021 IETF Trust and the persons identified as the | |||
document authors. All rights reserved. | document authors. All rights reserved. | |||
This document is subject to BCP 78 and the IETF Trust's Legal | This document is subject to BCP 78 and the IETF Trust's Legal | |||
Provisions Relating to IETF Documents | Provisions Relating to IETF Documents | |||
(https://trustee.ietf.org/license-info) in effect on the date of | (https://trustee.ietf.org/license-info) in effect on the date of | |||
publication of this document. Please review these documents | publication of this document. Please review these documents | |||
carefully, as they describe your rights and restrictions with respect | carefully, as they describe your rights and restrictions with respect | |||
to this document. Code Components extracted from this document must | to this document. Code Components extracted from this document must | |||
include Simplified BSD License text as described in Section 4.e of | include Simplified BSD License text as described in Section 4.e of | |||
the Trust Legal Provisions and are provided without warranty as | the Trust Legal Provisions and are provided without warranty as | |||
described in the Simplified BSD License. | described in the Simplified BSD License. | |||
Table of Contents | Table of Contents | |||
1. Introduction | 1. Introduction . . . . . . . . . . . . . . . . . . . . . . . . 3 | |||
1.1. Rate-limiting and quotas | 1.1. Rate-limiting and quotas . . . . . . . . . . . . . . . . 3 | |||
1.2. Current landscape of rate-limiting headers | 1.2. Current landscape of rate-limiting headers . . . . . . . 4 | |||
1.2.1. Interoperability issues | 1.2.1. Interoperability issues . . . . . . . . . . . . . . . 4 | |||
1.3. This proposal | 1.3. This proposal . . . . . . . . . . . . . . . . . . . . . . 5 | |||
1.4. Goals | 1.4. Goals . . . . . . . . . . . . . . . . . . . . . . . . . . 5 | |||
1.5. Notational Conventions | 1.5. Notational Conventions . . . . . . . . . . . . . . . . . 6 | |||
2. Expressing rate-limit policies | 2. Expressing rate-limit policies . . . . . . . . . . . . . . . 6 | |||
2.1. Time window | 2.1. Time window . . . . . . . . . . . . . . . . . . . . . . . 6 | |||
2.2. Request quota | 2.2. Request quota . . . . . . . . . . . . . . . . . . . . . . 6 | |||
2.3. Quota policy | 2.3. Quota policy . . . . . . . . . . . . . . . . . . . . . . 7 | |||
3. Header Specifications | 3. Header Specifications . . . . . . . . . . . . . . . . . . . . 8 | |||
3.1. RateLimit-Limit | 3.1. RateLimit-Limit . . . . . . . . . . . . . . . . . . . . . 8 | |||
3.2. RateLimit-Remaining | 3.2. RateLimit-Remaining . . . . . . . . . . . . . . . . . . . 9 | |||
3.3. RateLimit-Reset | 3.3. RateLimit-Reset . . . . . . . . . . . . . . . . . . . . . 9 | |||
4. Providing RateLimit headers | 4. Providing RateLimit headers . . . . . . . . . . . . . . . . . 10 | |||
5. Intermediaries | 5. Intermediaries . . . . . . . . . . . . . . . . . . . . . . . 11 | |||
6. Caching | 6. Caching . . . . . . . . . . . . . . . . . . . . . . . . . . . 11 | |||
7. Receiving RateLimit headers | 7. Receiving RateLimit headers . . . . . . . . . . . . . . . . . 11 | |||
8. Examples | 8. Examples . . . . . . . . . . . . . . . . . . . . . . . . . . 12 | |||
8.1. Unparameterized responses | 8.1. Unparameterized responses . . . . . . . . . . . . . . . . 12 | |||
8.1.1. Throttling informations in responses | 8.1.1. Throttling informations in responses . . . . . . . . 12 | |||
8.1.2. Use in conjunction with custom headers | 8.1.2. Use in conjunction with custom headers . . . . . . . 13 | |||
8.1.3. Use for limiting concurrency | 8.1.3. Use for limiting concurrency . . . . . . . . . . . . 13 | |||
8.1.4. Use in throttled responses | 8.1.4. Use in throttled responses . . . . . . . . . . . . . 14 | |||
8.2. Parameterized responses | 8.2. Parameterized responses . . . . . . . . . . . . . . . . . 15 | |||
8.2.1. Throttling window specified via parameter | 8.2.1. Throttling window specified via parameter . . . . . . 15 | |||
8.2.2. Dynamic limits with parameterized windows | 8.2.2. Dynamic limits with parameterized windows . . . . . . 16 | |||
8.2.3. Dynamic limits for pushing back and slowing down | 8.2.3. Dynamic limits for pushing back and slowing down . . 16 | |||
8.3. Dynamic limits for pushing back with Retry-After and slow | 8.3. Dynamic limits for pushing back with Retry-After and slow | |||
down | down . . . . . . . . . . . . . . . . . . . . . . . . . . 17 | |||
8.3.1. Missing Remaining informations | ||||
8.3.2. Use with multiple windows | 8.3.1. Missing Remaining informations . . . . . . . . . . . 18 | |||
9. Security Considerations | 8.3.2. Use with multiple windows . . . . . . . . . . . . . . 19 | |||
9.1. Throttling does not prevent clients from issuing requests | 9. Security Considerations . . . . . . . . . . . . . . . . . . . 19 | |||
9.2. Information disclosure | 9.1. Throttling does not prevent clients from issuing requests 19 | |||
9.3. Remaining quota-units are not granted requests | 9.2. Information disclosure . . . . . . . . . . . . . . . . . 20 | |||
9.4. Reliability of RateLimit-Reset | 9.3. Remaining quota-units are not granted requests . . . . . 20 | |||
9.5. Resource exhaustion | 9.4. Reliability of RateLimit-Reset . . . . . . . . . . . . . 20 | |||
9.6. Denial of Service | 9.5. Resource exhaustion . . . . . . . . . . . . . . . . . . . 20 | |||
10. IANA Considerations | 9.6. Denial of Service . . . . . . . . . . . . . . . . . . . . 21 | |||
10.1. RateLimit-Limit Field Registration | 10. IANA Considerations . . . . . . . . . . . . . . . . . . . . . 21 | |||
10.2. RateLimit-Remaining Field Registration | 10.1. RateLimit-Limit Field Registration . . . . . . . . . . . 21 | |||
10.3. RateLimit-Reset Field Registration | 10.2. RateLimit-Remaining Field Registration . . . . . . . . . 21 | |||
11. References | 10.3. RateLimit-Reset Field Registration . . . . . . . . . . . 22 | |||
11.1. Normative References | 11. References . . . . . . . . . . . . . . . . . . . . . . . . . 22 | |||
11.2. Informative References | 11.1. Normative References . . . . . . . . . . . . . . . . . . 22 | |||
11.3. URIs | 11.2. Informative References . . . . . . . . . . . . . . . . . 23 | |||
Appendix A. Change Log | 11.3. URIs . . . . . . . . . . . . . . . . . . . . . . . . . . 23 | |||
Appendix B. Acknowledgements | Appendix A. Change Log . . . . . . . . . . . . . . . . . . . . . 23 | |||
Appendix C. RateLimit headers currently used on the web | Appendix B. Acknowledgements . . . . . . . . . . . . . . . . . . 23 | |||
Appendix D. FAQ | Appendix C. RateLimit headers currently used on the web . . . . 24 | |||
Authors' Addresses | Appendix D. FAQ . . . . . . . . . . . . . . . . . . . . . . . . 25 | |||
Changes . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 28 | ||||
E.1. Since draft-ietf-httpapi-ratelimit-headers-00 . . . . . . 28 | ||||
Authors' Addresses . . . . . . . . . . . . . . . . . . . . . . . 28 | ||||
1. Introduction | 1. Introduction | |||
The widespreading of HTTP as a distributed computation protocol | The widespreading of HTTP as a distributed computation protocol | |||
requires an explicit way of communicating service status and usage | requires an explicit way of communicating service status and usage | |||
quotas. | quotas. | |||
This was partially addressed with the "Retry-After" header field | This was partially addressed with the "Retry-After" header field | |||
defined in [SEMANTICS] to be returned in "429 Too Many Requests" or | defined in [SEMANTICS] to be returned in "429 Too Many Requests" or | |||
"503 Service Unavailable" responses. | "503 Service Unavailable" responses. | |||
skipping to change at line 207 ¶ | skipping to change at page 5, line 23 ¶ | |||
o "RateLimit-Limit": containing the requests quota in the time | o "RateLimit-Limit": containing the requests quota in the time | |||
window; | window; | |||
o "RateLimit-Remaining": containing the remaining requests quota in | o "RateLimit-Remaining": containing the remaining requests quota in | |||
the current window; | the current window; | |||
o "RateLimit-Reset": containing the time remaining in the current | o "RateLimit-Reset": containing the time remaining in the current | |||
window, specified in seconds. | window, specified in seconds. | |||
The behavior of "RateLimit-Reset" is compatible with the "delta- | The behavior of "RateLimit-Reset" is compatible with the "delay- | |||
seconds" notation of "Retry-After". | seconds" notation of "Retry-After". | |||
The fields definition allows to describe complex policies, including | The fields definition allows to describe complex policies, including | |||
the ones using multiple and variable time windows and dynamic quotas, | the ones using multiple and variable time windows and dynamic quotas, | |||
or implementing concurrency limits. | or implementing concurrency limits. | |||
1.4. Goals | 1.4. Goals | |||
The goals of this proposal are: | The goals of this proposal are: | |||
skipping to change at line 233 ¶ | skipping to change at page 5, line 49 ¶ | |||
3. Simplify API documentation avoiding expliciting rate-limit fields | 3. Simplify API documentation avoiding expliciting rate-limit fields | |||
semantic in documentation. | semantic in documentation. | |||
The goals do not include: | The goals do not include: | |||
Authorization: The rate-limit headers described here are not meant | Authorization: The rate-limit headers described here are not meant | |||
to support authorization or other kinds of access controls. | to support authorization or other kinds of access controls. | |||
Throttling scope: This specification does not cover the throttling | Throttling scope: This specification does not cover the throttling | |||
scope, that may be the given resource-target, its parent path or | scope, that may be the given resource-target, its parent path or | |||
the whole Origin [RFC6454] section 7. | the whole Origin (see Section 7 of [RFC6454]). | |||
Response status code: The rate-limit headers may be returned in both | Response status code: The rate-limit headers may be returned in both | |||
Successful and non Successful responses. This specification does | Successful and non Successful responses. This specification does | |||
not cover whether non Successful responses count on quota usage. | not cover whether non Successful responses count on quota usage. | |||
Throttling policy: This specification does not mandate a specific | Throttling policy: This specification does not mandate a specific | |||
throttling policy. The values published in the headers, including | throttling policy. The values published in the headers, including | |||
the window size, can be statically or dynamically evaluated. | the window size, can be statically or dynamically evaluated. | |||
Service Level Agreement: Conveyed quota hints do not imply any | Service Level Agreement: Conveyed quota hints do not imply any | |||
skipping to change at line 256 ¶ | skipping to change at page 6, line 26 ¶ | |||
1.5. Notational Conventions | 1.5. Notational Conventions | |||
The key words "MUST", "MUST NOT", "REQUIRED", "SHALL", "SHALL NOT", | The key words "MUST", "MUST NOT", "REQUIRED", "SHALL", "SHALL NOT", | |||
"SHOULD", "SHOULD NOT", "RECOMMENDED", "NOT RECOMMENDED", "MAY", and | "SHOULD", "SHOULD NOT", "RECOMMENDED", "NOT RECOMMENDED", "MAY", and | |||
"OPTIONAL" in this document are to be interpreted as described in | "OPTIONAL" in this document are to be interpreted as described in | |||
BCP 14 [RFC2119] [RFC8174] when, and only when, they appear in all | BCP 14 [RFC2119] [RFC8174] when, and only when, they appear in all | |||
capitals, as shown here. | capitals, as shown here. | |||
This document uses the Augmented BNF defined in [RFC5234] and updated | This document uses the Augmented BNF defined in [RFC5234] and updated | |||
by [RFC7405] along with the "#rule" extension defined in Section 7 of | by [RFC7405] along with the "#rule" extension defined in | |||
[MESSAGING]. | Section 5.6.1 of [SEMANTICS]. | |||
The term Origin is to be interpreted as described in [RFC6454] | The term Origin is to be interpreted as described in Section 7 of | |||
section 7. | [RFC6454]. | |||
The "delta-seconds" rule is defined in [CACHING] section 1.2.1. | The "delay-seconds" rule is defined in Section 10.2.4 of [SEMANTICS]. | |||
2. Expressing rate-limit policies | 2. Expressing rate-limit policies | |||
2.1. Time window | 2.1. Time window | |||
Rate limit policies limit the number of acceptable requests in a | Rate limit policies limit the number of acceptable requests in a | |||
given time window. | given time window. | |||
A time window is expressed in seconds, using the following syntax: | A time window is expressed in seconds, using the following syntax: | |||
time-window = delta-seconds | time-window = delay-seconds | |||
Subsecond precision is not supported. | Subsecond precision is not supported. | |||
2.2. Request quota | 2.2. Request quota | |||
The request-quota is a value associated to the maximum number of | The request-quota is a value associated to the maximum number of | |||
requests that the server is willing to accept from one or more | requests that the server is willing to accept from one or more | |||
clients on a given basis (originating IP, authenticated user, | clients on a given basis (originating IP, authenticated user, | |||
geographical, ..) during a "time-window" as defined in Section 2.1. | geographical, ..) during a "time-window" as defined in Section 2.1. | |||
skipping to change at line 412 ¶ | skipping to change at page 9, line 38 ¶ | |||
RateLimit-Remaining: 50 | RateLimit-Remaining: 50 | |||
3.3. RateLimit-Reset | 3.3. RateLimit-Reset | |||
The "RateLimit-Reset" response field indicates either | The "RateLimit-Reset" response field indicates either | |||
o the number of seconds until the quota resets. | o the number of seconds until the quota resets. | |||
The header value is | The header value is | |||
RateLimit-Reset = delta-seconds | RateLimit-Reset = delay-seconds | |||
The delta-seconds format is used because: | The delay-seconds format is used because: | |||
o it does not rely on clock synchronization and is resilient to | o it does not rely on clock synchronization and is resilient to | |||
clock adjustment and clock skew between client and server (see | clock adjustment and clock skew between client and server (see | |||
[SEMANTICS] Section 4.1.1.1); | Section 5.6.7 of [SEMANTICS]); | |||
o it mitigates the risk related to thundering herd when too many | o it mitigates the risk related to thundering herd when too many | |||
clients are serviced with the same timestamp. | clients are serviced with the same timestamp. | |||
This header MUST NOT occur multiple times and can be sent in a | This header MUST NOT occur multiple times and can be sent in a | |||
trailer section. | trailer section. | |||
An example of "RateLimit-Reset" use is below. | An example of "RateLimit-Reset" use is below. | |||
RateLimit-Reset: 50 | RateLimit-Reset: 50 | |||
skipping to change at line 477 ¶ | skipping to change at page 11, line 7 ¶ | |||
field values between subsequent requests, eg. to respond to Denial of | field values between subsequent requests, eg. to respond to Denial of | |||
Service attacks or in case of resource saturation. | Service attacks or in case of resource saturation. | |||
Servers usually establish whether the request is in-quota before | Servers usually establish whether the request is in-quota before | |||
creating a response, so the RateLimit field values should be already | creating a response, so the RateLimit field values should be already | |||
available in that moment. Nonetheless servers MAY decide to send the | available in that moment. Nonetheless servers MAY decide to send the | |||
"RateLimit" fields in a trailer section. | "RateLimit" fields in a trailer section. | |||
5. Intermediaries | 5. Intermediaries | |||
This section documents the considerations advised in Section 15.3.3 | This section documents the considerations advised in Section 16.3.3 | |||
of [SEMANTICS]. | of [SEMANTICS]. | |||
An intermediary that is not part of the originating service | An intermediary that is not part of the originating service | |||
infrastructure and is not aware of the quota-policy semantic used by | infrastructure and is not aware of the quota-policy semantic used by | |||
the Origin Server SHOULD NOT alter the RateLimit fields' values in | the Origin Server SHOULD NOT alter the RateLimit fields' values in | |||
such a way as to communicate a more permissive quota-policy; this | such a way as to communicate a more permissive quota-policy; this | |||
includes removing the RateLimit fields. | includes removing the RateLimit fields. | |||
An intermediary MAY alter the RateLimit fields in such a way as to | An intermediary MAY alter the RateLimit fields in such a way as to | |||
communicate a more restrictive quota-policy when: | communicate a more restrictive quota-policy when: | |||
skipping to change at line 556 ¶ | skipping to change at page 12, line 38 ¶ | |||
8.1. Unparameterized responses | 8.1. Unparameterized responses | |||
8.1.1. Throttling informations in responses | 8.1.1. Throttling informations in responses | |||
The client exhausted its request-quota for the next 50 seconds. The | The client exhausted its request-quota for the next 50 seconds. The | |||
"time-window" is communicated out-of-band or inferred by the header | "time-window" is communicated out-of-band or inferred by the header | |||
values. | values. | |||
Request: | Request: | |||
GET /items/123 | GET /items/123 HTTP/1.1 | |||
Host: api.example | ||||
Response: | Response: | |||
HTTP/1.1 200 Ok | HTTP/1.1 200 Ok | |||
Content-Type: application/json | Content-Type: application/json | |||
RateLimit-Limit: 100 | RateLimit-Limit: 100 | |||
Ratelimit-Remaining: 0 | Ratelimit-Remaining: 0 | |||
Ratelimit-Reset: 50 | Ratelimit-Reset: 50 | |||
{"hello": "world"} | {"hello": "world"} | |||
skipping to change at line 591 ¶ | skipping to change at page 13, line 28 ¶ | |||
The server then exposes the "RateLimit-*" headers to inform the | The server then exposes the "RateLimit-*" headers to inform the | |||
client that: | client that: | |||
o it has only 100 quota-units left; | o it has only 100 quota-units left; | |||
o the window will reset in 10 hours. | o the window will reset in 10 hours. | |||
Request: | Request: | |||
GET /items/123 | GET /items/123 HTTP/1.1 | |||
Host: api.example | ||||
Response: | Response: | |||
HTTP/1.1 200 Ok | HTTP/1.1 200 Ok | |||
Content-Type: application/json | Content-Type: application/json | |||
acme-RateLimit-DayLimit: 5000 | acme-RateLimit-DayLimit: 5000 | |||
acme-RateLimit-HourLimit: 1000 | acme-RateLimit-HourLimit: 1000 | |||
RateLimit-Limit: 5000 | RateLimit-Limit: 5000 | |||
RateLimit-Remaining: 100 | RateLimit-Remaining: 100 | |||
RateLimit-Reset: 36000 | RateLimit-Reset: 36000 | |||
skipping to change at line 619 ¶ | skipping to change at page 14, line 9 ¶ | |||
increasing availability. | increasing availability. | |||
The server adopted a basic policy of 100 quota-units per minute, and | The server adopted a basic policy of 100 quota-units per minute, and | |||
in case of resource exhaustion adapts the returned values reducing | in case of resource exhaustion adapts the returned values reducing | |||
both "RateLimit-Limit" and "RateLimit-Remaining". | both "RateLimit-Limit" and "RateLimit-Remaining". | |||
After 2 seconds the client consumed 40 quota-units | After 2 seconds the client consumed 40 quota-units | |||
Request: | Request: | |||
GET /items/123 | GET /items/123 HTTP/1.1 | |||
Host: api.example | ||||
Response: | Response: | |||
HTTP/1.1 200 Ok | HTTP/1.1 200 Ok | |||
Content-Type: application/json | Content-Type: application/json | |||
RateLimit-Limit: 100 | RateLimit-Limit: 100 | |||
RateLimit-Remaining: 60 | RateLimit-Remaining: 60 | |||
RateLimit-Reset: 58 | RateLimit-Reset: 58 | |||
{"elapsed": 2, "issued": 40} | {"elapsed": 2, "issued": 40} | |||
At the subsequent request - due to resource exhaustion - the server | At the subsequent request - due to resource exhaustion - the server | |||
advertises only "RateLimit-Remaining: 20". | advertises only "RateLimit-Remaining: 20". | |||
Request: | Request: | |||
GET /items/123 | GET /items/123 HTTP/1.1 | |||
Host: api.example | ||||
Response: | Response: | |||
HTTP/1.1 200 Ok | HTTP/1.1 200 Ok | |||
Content-Type: application/json | Content-Type: application/json | |||
RateLimit-Limit: 100 | RateLimit-Limit: 100 | |||
RateLimit-Remaining: 20 | RateLimit-Remaining: 20 | |||
RateLimit-Reset: 56 | RateLimit-Reset: 56 | |||
{"elapsed": 4, "issued": 41} | {"elapsed": 4, "issued": 41} | |||
skipping to change at line 661 ¶ | skipping to change at page 15, line 7 ¶ | |||
sending the "Retry-After" response header field. | sending the "Retry-After" response header field. | |||
In this example, the values of "Retry-After" and "RateLimit-Reset" | In this example, the values of "Retry-After" and "RateLimit-Reset" | |||
reference the same moment, but this is not a requirement. | reference the same moment, but this is not a requirement. | |||
The "429 Too Many Requests" HTTP status code is just used as an | The "429 Too Many Requests" HTTP status code is just used as an | |||
example. | example. | |||
Request: | Request: | |||
GET /items/123 | GET /items/123 HTTP/1.1 | |||
Host: api.example | ||||
Response: | Response: | |||
HTTP/1.1 429 Too Many Requests | HTTP/1.1 429 Too Many Requests | |||
Content-Type: application/json | Content-Type: application/json | |||
Date: Mon, 05 Aug 2019 09:27:00 GMT | Date: Mon, 05 Aug 2019 09:27:00 GMT | |||
Retry-After: Mon, 05 Aug 2019 09:27:05 GMT | Retry-After: Mon, 05 Aug 2019 09:27:05 GMT | |||
RateLimit-Reset: 5 | RateLimit-Reset: 5 | |||
RateLimit-Limit: 100 | RateLimit-Limit: 100 | |||
Ratelimit-Remaining: 0 | Ratelimit-Remaining: 0 | |||
skipping to change at line 689 ¶ | skipping to change at page 15, line 36 ¶ | |||
8.2. Parameterized responses | 8.2. Parameterized responses | |||
8.2.1. Throttling window specified via parameter | 8.2.1. Throttling window specified via parameter | |||
The client has 99 "quota-units" left for the next 50 seconds. The | The client has 99 "quota-units" left for the next 50 seconds. The | |||
"time-window" is communicated by the "w" parameter, so we know the | "time-window" is communicated by the "w" parameter, so we know the | |||
throughput is 100 "quota-units" per minute. | throughput is 100 "quota-units" per minute. | |||
Request: | Request: | |||
GET /items/123 | GET /items/123 HTTP/1.1 | |||
Host: api.example | ||||
Response: | Response: | |||
HTTP/1.1 200 Ok | HTTP/1.1 200 Ok | |||
Content-Type: application/json | Content-Type: application/json | |||
RateLimit-Limit: 100, 100;w=60 | RateLimit-Limit: 100, 100;w=60 | |||
Ratelimit-Remaining: 99 | Ratelimit-Remaining: 99 | |||
Ratelimit-Reset: 50 | Ratelimit-Reset: 50 | |||
{"hello": "world"} | {"hello": "world"} | |||
skipping to change at line 718 ¶ | skipping to change at page 16, line 22 ¶ | |||
The "RateLimit-Remaining" then advertises only 9 quota-units for the | The "RateLimit-Remaining" then advertises only 9 quota-units for the | |||
next 50 seconds to slow down the client. | next 50 seconds to slow down the client. | |||
Note that the server could have lowered even the other values in | Note that the server could have lowered even the other values in | |||
"RateLimit-Limit": this specification does not mandate any relation | "RateLimit-Limit": this specification does not mandate any relation | |||
between the field values contained in subsequent responses. | between the field values contained in subsequent responses. | |||
Request: | Request: | |||
GET /items/123 | GET /items/123 HTTP/1.1 | |||
Host: api.example | ||||
Response: | Response: | |||
HTTP/1.1 200 Ok | HTTP/1.1 200 Ok | |||
Content-Type: application/json | Content-Type: application/json | |||
RateLimit-Limit: 10, 100;w=60 | RateLimit-Limit: 10, 100;w=60 | |||
Ratelimit-Remaining: 9 | Ratelimit-Remaining: 9 | |||
Ratelimit-Reset: 50 | Ratelimit-Reset: 50 | |||
{ | { | |||
skipping to change at line 746 ¶ | skipping to change at page 17, line 5 ¶ | |||
seconds and performs a new request which, due to resource exhaustion, | seconds and performs a new request which, due to resource exhaustion, | |||
the server rejects and pushes back, advertising "RateLimit-Remaining: | the server rejects and pushes back, advertising "RateLimit-Remaining: | |||
0" for the next 20 seconds. | 0" for the next 20 seconds. | |||
The server advertises a smaller window with a lower limit to slow | The server advertises a smaller window with a lower limit to slow | |||
down the client for the rest of its original window after the 20 | down the client for the rest of its original window after the 20 | |||
seconds elapse. | seconds elapse. | |||
Request: | Request: | |||
GET /items/123 | GET /items/123 HTTP/1.1 | |||
Host: api.example | ||||
Response: | Response: | |||
HTTP/1.1 429 Too Many Requests | HTTP/1.1 429 Too Many Requests | |||
Content-Type: application/json | Content-Type: application/json | |||
RateLimit-Limit: 0, 15;w=20 | RateLimit-Limit: 0, 15;w=20 | |||
Ratelimit-Remaining: 0 | Ratelimit-Remaining: 0 | |||
Ratelimit-Reset: 20 | Ratelimit-Reset: 20 | |||
{ | { | |||
skipping to change at line 774 ¶ | skipping to change at page 17, line 34 ¶ | |||
starts, we can convey the same information to the client via the | starts, we can convey the same information to the client via the | |||
Retry-After header, with the advantage that the server can now | Retry-After header, with the advantage that the server can now | |||
specify the policy's nominal limit and window that will apply after | specify the policy's nominal limit and window that will apply after | |||
the reset, ie. assuming the resource exhaustion is likely to be gone | the reset, ie. assuming the resource exhaustion is likely to be gone | |||
by then, so the advertised policy does not need to be adjusted, yet | by then, so the advertised policy does not need to be adjusted, yet | |||
we managed to stop requests for a while and slow down the rest of the | we managed to stop requests for a while and slow down the rest of the | |||
current window. | current window. | |||
Request: | Request: | |||
GET /items/123 | GET /items/123 HTTP/1.1 | |||
Host: api.example | ||||
Response: | Response: | |||
HTTP/1.1 429 Too Many Requests | HTTP/1.1 429 Too Many Requests | |||
Content-Type: application/json | Content-Type: application/json | |||
Retry-After: 20 | Retry-After: 20 | |||
RateLimit-Limit: 15, 100;w=60 | RateLimit-Limit: 15, 100;w=60 | |||
Ratelimit-Remaining: 15 | Ratelimit-Remaining: 15 | |||
Ratelimit-Reset: 40 | Ratelimit-Reset: 40 | |||
skipping to change at line 789 ¶ | skipping to change at page 18, line 4 ¶ | |||
Content-Type: application/json | Content-Type: application/json | |||
Retry-After: 20 | Retry-After: 20 | |||
RateLimit-Limit: 15, 100;w=60 | RateLimit-Limit: 15, 100;w=60 | |||
Ratelimit-Remaining: 15 | Ratelimit-Remaining: 15 | |||
Ratelimit-Reset: 40 | Ratelimit-Reset: 40 | |||
{ | { | |||
"status": 429, | "status": 429, | |||
"detail": "Wait 20 seconds, then slow down!" | "detail": "Wait 20 seconds, then slow down!" | |||
} | } | |||
Note that in this last response the client is expected to honor the | Note that in this last response the client is expected to honor the | |||
"Retry-After" header and perform no requests for the specified amount | "Retry-After" header and perform no requests for the specified amount | |||
of time, whereas the previous example would not force the client to | of time, whereas the previous example would not force the client to | |||
stop requests before the reset time is elapsed, as it would still be | stop requests before the reset time is elapsed, as it would still be | |||
free to query again the server even if it is likely to have the | free to query again the server even if it is likely to have the | |||
request rejected. | request rejected. | |||
8.3.1. Missing Remaining informations | 8.3.1. Missing Remaining informations | |||
The server does not expose "RateLimit-Remaining" values, but resets | The server does not expose "RateLimit-Remaining" values, but resets | |||
the limit counter every second. | the limit counter every second. | |||
It communicates to the client the limit of 10 quota-units per second | It communicates to the client the limit of 10 quota-units per second | |||
always returning the couple "RateLimit-Limit" and "RateLimit-Reset". | always returning the couple "RateLimit-Limit" and "RateLimit-Reset". | |||
Request: | Request: | |||
GET /items/123 | GET /items/123 HTTP/1.1 | |||
Host: api.example | ||||
Response: | Response: | |||
HTTP/1.1 200 Ok | HTTP/1.1 200 Ok | |||
Content-Type: application/json | Content-Type: application/json | |||
RateLimit-Limit: 10 | RateLimit-Limit: 10 | |||
Ratelimit-Reset: 1 | Ratelimit-Reset: 1 | |||
{"first": "request"} | {"first": "request"} | |||
Request: | Request: | |||
GET /items/123 | GET /items/123 HTTP/1.1 | |||
Host: api.example | ||||
Response: | Response: | |||
HTTP/1.1 200 Ok | HTTP/1.1 200 Ok | |||
Content-Type: application/json | Content-Type: application/json | |||
RateLimit-Limit: 10 | RateLimit-Limit: 10 | |||
Ratelimit-Reset: 1 | Ratelimit-Reset: 1 | |||
{"second": "request"} | {"second": "request"} | |||
skipping to change at line 856 ¶ | skipping to change at page 19, line 30 ¶ | |||
that: | that: | |||
o it has only 100 quota-units left; | o it has only 100 quota-units left; | |||
o the window will reset in 10 hours; | o the window will reset in 10 hours; | |||
o the "expiring-limit" is 5000. | o the "expiring-limit" is 5000. | |||
Request: | Request: | |||
GET /items/123 | GET /items/123 HTTP/1.1 | |||
Host: api.example | ||||
Response: | Response: | |||
HTTP/1.1 200 OK | HTTP/1.1 200 OK | |||
Content-Type: application/json | Content-Type: application/json | |||
RateLimit-Limit: 5000, 1000;w=3600, 5000;w=86400 | RateLimit-Limit: 5000, 1000;w=3600, 5000;w=86400 | |||
RateLimit-Remaining: 100 | RateLimit-Remaining: 100 | |||
RateLimit-Reset: 36000 | RateLimit-Reset: 36000 | |||
{"hello": "world"} | {"hello": "world"} | |||
skipping to change at line 986 ¶ | skipping to change at page 22, line 20 ¶ | |||
Field name: "RateLimit-Reset" | Field name: "RateLimit-Reset" | |||
Status: permanent | Status: permanent | |||
Specification document(s): Section 3.3 of this document | Specification document(s): Section 3.3 of this document | |||
11. References | 11. References | |||
11.1. Normative References | 11.1. Normative References | |||
[CACHING] Fielding, R., Ed., Nottingham, M., Ed., and J. Reschke, | ||||
Ed., "Hypertext Transfer Protocol (HTTP/1.1): Caching", | ||||
RFC 7234, DOI 10.17487/RFC7234, June 2014, | ||||
<https://www.rfc-editor.org/info/rfc7234>. | ||||
[MESSAGING] | ||||
Fielding, R., Ed. and J. Reschke, Ed., "Hypertext Transfer | ||||
Protocol (HTTP/1.1): Message Syntax and Routing", | ||||
RFC 7230, DOI 10.17487/RFC7230, June 2014, | ||||
<https://www.rfc-editor.org/info/rfc7230>. | ||||
[RFC2119] Bradner, S., "Key words for use in RFCs to Indicate | [RFC2119] Bradner, S., "Key words for use in RFCs to Indicate | |||
Requirement Levels", BCP 14, RFC 2119, | Requirement Levels", BCP 14, RFC 2119, | |||
DOI 10.17487/RFC2119, March 1997, | DOI 10.17487/RFC2119, March 1997, | |||
<https://www.rfc-editor.org/info/rfc2119>. | <https://www.rfc-editor.org/info/rfc2119>. | |||
[RFC5234] Crocker, D., Ed. and P. Overell, "Augmented BNF for Syntax | [RFC5234] Crocker, D., Ed. and P. Overell, "Augmented BNF for Syntax | |||
Specifications: ABNF", STD 68, RFC 5234, | Specifications: ABNF", STD 68, RFC 5234, | |||
DOI 10.17487/RFC5234, January 2008, | DOI 10.17487/RFC5234, January 2008, | |||
<https://www.rfc-editor.org/info/rfc5234>. | <https://www.rfc-editor.org/info/rfc5234>. | |||
skipping to change at line 1020 ¶ | skipping to change at page 22, line 43 ¶ | |||
[RFC7405] Kyzivat, P., "Case-Sensitive String Support in ABNF", | [RFC7405] Kyzivat, P., "Case-Sensitive String Support in ABNF", | |||
RFC 7405, DOI 10.17487/RFC7405, December 2014, | RFC 7405, DOI 10.17487/RFC7405, December 2014, | |||
<https://www.rfc-editor.org/info/rfc7405>. | <https://www.rfc-editor.org/info/rfc7405>. | |||
[RFC8174] Leiba, B., "Ambiguity of Uppercase vs Lowercase in RFC | [RFC8174] Leiba, B., "Ambiguity of Uppercase vs Lowercase in RFC | |||
2119 Key Words", BCP 14, RFC 8174, DOI 10.17487/RFC8174, | 2119 Key Words", BCP 14, RFC 8174, DOI 10.17487/RFC8174, | |||
May 2017, <https://www.rfc-editor.org/info/rfc8174>. | May 2017, <https://www.rfc-editor.org/info/rfc8174>. | |||
[SEMANTICS] | [SEMANTICS] | |||
Fielding, R., Ed. and J. Reschke, Ed., "Hypertext Transfer | Fielding, R., Nottingham, M., and J. Reschke, "HTTP | |||
Protocol (HTTP/1.1): Semantics and Content", RFC 7231, | Semantics", draft-ietf-httpbis-semantics-14 (work in | |||
DOI 10.17487/RFC7231, June 2014, | progress), January 2021. | |||
<https://www.rfc-editor.org/info/rfc7231>. | ||||
[UNIX] The Open Group, ., "The Single UNIX Specification, Version | [UNIX] The Open Group, ., "The Single UNIX Specification, Version | |||
2 - 6 Vol Set for UNIX 98", February 1997. | 2 - 6 Vol Set for UNIX 98", February 1997. | |||
11.2. Informative References | 11.2. Informative References | |||
[RFC3339] Klyne, G. and C. Newman, "Date and Time on the Internet: | [RFC3339] Klyne, G. and C. Newman, "Date and Time on the Internet: | |||
Timestamps", RFC 3339, DOI 10.17487/RFC3339, July 2002, | Timestamps", RFC 3339, DOI 10.17487/RFC3339, July 2002, | |||
<https://www.rfc-editor.org/info/rfc3339>. | <https://www.rfc-editor.org/info/rfc3339>. | |||
skipping to change at line 1159 ¶ | skipping to change at page 25, line 41 ¶ | |||
as an example of a throttled request, that could instead use even | as an example of a throttled request, that could instead use even | |||
403 or whatever status code. | 403 or whatever status code. | |||
4. Why don't pass the throttling scope as a parameter? | 4. Why don't pass the throttling scope as a parameter? | |||
After a discussion on a similar thread [3] we will probably add a | After a discussion on a similar thread [3] we will probably add a | |||
new "RateLimit-Scope" header to this spec. | new "RateLimit-Scope" header to this spec. | |||
I'm open to suggestions: comment on this issue [4] | I'm open to suggestions: comment on this issue [4] | |||
5. Why using delta-seconds instead of a UNIX Timestamp? Why not | 5. Why using delay-seconds instead of a UNIX Timestamp? Why not | |||
using subsecond precision? | using subsecond precision? | |||
Using delta-seconds aligns with "Retry-After", which is returned | Using delay-seconds aligns with "Retry-After", which is returned | |||
in similar contexts, eg on 429 responses. | in similar contexts, eg on 429 responses. | |||
delta-seconds as defined in [CACHING] section 1.2.1 clarifies | ||||
some parsing rules too. | ||||
Timestamps require a clock synchronization protocol (see | Timestamps require a clock synchronization protocol (see | |||
[SEMANTICS] section 4.1.1.1). This may be problematic (eg. clock | Section 5.6.7 of [SEMANTICS]). This may be problematic (eg. | |||
adjustment, clock skew, failure of hardcoded clock | clock adjustment, clock skew, failure of hardcoded clock | |||
synchronization servers, IoT devices, ..). Moreover timestamps | synchronization servers, IoT devices, ..). Moreover timestamps | |||
may not be monotonically increasing due to clock adjustment. See | may not be monotonically increasing due to clock adjustment. See | |||
Another NTP client failure story [5] | Another NTP client failure story [5] | |||
We did not use subsecond precision because: | We did not use subsecond precision because: | |||
* that is more subject to system clock correction like the one | * that is more subject to system clock correction like the one | |||
implemented via the adjtimex() Linux system call; | implemented via the adjtimex() Linux system call; | |||
* response-time latency may not make it worth. A brief | * response-time latency may not make it worth. A brief | |||
discussion on the subject is on the httpwg ml [6] | discussion on the subject is on the httpwg ml [6] | |||
* almost all rate-limit headers implementations do not use it. | * almost all rate-limit headers implementations do not use it. | |||
skipping to change at line 1275 ¶ | skipping to change at page 28, line 7 ¶ | |||
2. Can intermediaries alter RateLimit fields? | 2. Can intermediaries alter RateLimit fields? | |||
Generally, they should not because it might result in unserviced | Generally, they should not because it might result in unserviced | |||
requests. There are reasonable use cases for intermediaries | requests. There are reasonable use cases for intermediaries | |||
mangling RateLimit fields though, e.g. when they enforce stricter | mangling RateLimit fields though, e.g. when they enforce stricter | |||
quota-policies, or when they are an active component of the | quota-policies, or when they are an active component of the | |||
service. In those case we will consider them as part of the | service. In those case we will consider them as part of the | |||
originating infrastructure. | originating infrastructure. | |||
Changes | ||||
_RFC Editor: Please remove this section before publication._ | ||||
E.1. Since draft-ietf-httpapi-ratelimit-headers-00 | ||||
o Use I-D.httpbis-semantics, which includes referencing "delay- | ||||
seconds" instead of "delta-seconds". #5 | ||||
Authors' Addresses | Authors' Addresses | |||
Roberto Polli | Roberto Polli | |||
Team Digitale, Italian Government | Team Digitale, Italian Government | |||
Italy | ||||
Email: robipolli@gmail.com | Email: robipolli@gmail.com | |||
Alejandro Martinez Ruiz | Alejandro Martinez Ruiz | |||
Red Hat | Red Hat | |||
Email: amr@redhat.com | Email: amr@redhat.com | |||
End of changes. 38 change blocks. | ||||
105 lines changed or deleted | 113 lines changed or added | |||
This html diff was produced by rfcdiff 1.44jr. The latest version is available from http://tools.ietf.org/tools/rfcdiff/ |