]> git.ipfire.org Git - thirdparty/dovecot/core.git/commitdiff
http: Preparse Retry-After header if response status is 503 or 3xx.
authorStephan Bosch <stephan@rename-it.nl>
Fri, 22 Nov 2013 20:08:44 +0000 (22:08 +0200)
committerStephan Bosch <stephan@rename-it.nl>
Fri, 22 Nov 2013 20:08:44 +0000 (22:08 +0200)
src/lib-http/http-response-parser.c
src/lib-http/http-response.h

index 7e3632bc87209d10f6657eba859fa5e1bb206512..87d5b0ff45b2cbbe17e7605f28278e9998ddb9fb 100644 (file)
@@ -3,6 +3,7 @@
 #include "lib.h"
 #include "istream.h"
 #include "http-parser.h"
+#include "http-date.h"
 #include "http-message-parser.h"
 #include "http-response-parser.h"
 
@@ -232,10 +233,41 @@ http_response_parse_status_line(struct http_response_parser *parser)
        return 0;
 }
 
+static int
+http_response_parse_retry_after(const char *hdrval, time_t resp_time,
+       time_t *retry_after_r)
+{
+       time_t delta;
+
+       /* http://tools.ietf.org/html/draft-ietf-httpbis-p2-semantics-23
+            Section 7.1.3:
+
+          The value of this field can be either an HTTP-date or an integer
+          number of seconds (in decimal) after the time of the response.
+          Time spans are non-negative decimal integers, representing time in
+          seconds.
+
+     Retry-After = HTTP-date / delta-seconds
+     delta-seconds  = 1*DIGIT
+        */
+       if (str_to_time(hdrval, &delta) >= 0) {
+               if (resp_time == (time_t)-1) {
+                       return -1;
+               }
+               *retry_after_r = resp_time + delta;
+               return 0;
+       }
+
+       return (http_date_parse
+               ((unsigned char *)hdrval, strlen(hdrval), retry_after_r) ? 0 : -1);
+}
+
 int http_response_parse_next(struct http_response_parser *parser,
                             enum http_response_payload_type payload_type,
                             struct http_response *response, const char **error_r)
 {
+       const char *hdrval;
+       time_t retry_after = (time_t)-1;
        int ret;
 
        /* make sure we finished streaming payload from previous response
@@ -300,6 +332,26 @@ int http_response_parse_next(struct http_response_parser *parser,
                }
        }
 
+       /* http://tools.ietf.org/html/draft-ietf-httpbis-p2-semantics-23
+            Section 7.1.3:
+       
+          Servers send the "Retry-After" header field to indicate how long the
+          user agent ought to wait before making a follow-up request.  When
+          sent with a 503 (Service Unavailable) response, Retry-After indicates
+          how long the service is expected to be unavailable to the client.
+          When sent with any 3xx (Redirection) response, Retry-After indicates
+          the minimum time that the user agent is asked to wait before issuing
+          the redirected request.
+        */
+       if (parser->response_status == 503 || (parser->response_status / 100) == 3) {           
+               hdrval = http_header_field_get(parser->parser.msg.header, "Retry-After");
+               if (hdrval != NULL) {
+                       (void)http_response_parse_retry_after
+                               (hdrval, parser->parser.msg.date, &retry_after);
+                       /* broken Retry-After header is ignored */
+               }
+       }
+
        parser->state = HTTP_RESPONSE_PARSE_STATE_INIT;
 
        memset(response, 0, sizeof(*response));
@@ -309,6 +361,7 @@ int http_response_parse_next(struct http_response_parser *parser,
        response->version_minor = parser->parser.msg.version_minor;
        response->location = parser->parser.msg.location;
        response->date = parser->parser.msg.date;
+       response->retry_after = retry_after;
        response->payload = parser->parser.payload;
        response->header = parser->parser.msg.header;
        response->headers = *http_header_get_fields(response->header); /* FIXME: remove in v2.3 */
index 1fe5a02597a66a644fc64ba329acae15e7825a44..dde386efe4fbf148143b40658ad2b0229db24fc6 100644 (file)
@@ -22,7 +22,7 @@ struct http_response {
        const char *reason;
        const char *location;
 
-       time_t date;
+       time_t date, retry_after;
        const struct http_header *header;
        struct istream *payload;