Browse Source

[http] Automatically retry request on a 503 Service Unavailable

A web server may return a 503 Service Unavailable response along with
a Retry-After header to direct the client to retry the request at a
later time.

The Retry-After header may be a number of seconds, or a full HTTP
timestamp (e.g. "Fri, 7 Mar 2014 17:22:14 GMT").  We have no
reasonable way of parsing a full HTTP timestamp; if the server chooses
to use this format then we simply retry after a fixed 5-second delay.

As per RFC 2616, in the absence of a Retry-After header we treat a
status code of 503 Service Unavailable as being equivalent to 500
Internal Server Error, and immediately fail the request.

Requested-by: Suresh Sundriyal <ssundriy@vmware.com>
Signed-off-by: Michael Brown <mcb30@ipxe.org>
tags/v1.20.1
Michael Brown 11 years ago
parent
commit
42bf3b9aa9
1 changed files with 45 additions and 1 deletions
  1. 45
    1
      src/net/tcp/httpcore.c

+ 45
- 1
src/net/tcp/httpcore.c View File

43
 #include <ipxe/tcpip.h>
43
 #include <ipxe/tcpip.h>
44
 #include <ipxe/process.h>
44
 #include <ipxe/process.h>
45
 #include <ipxe/retry.h>
45
 #include <ipxe/retry.h>
46
+#include <ipxe/timer.h>
46
 #include <ipxe/linebuf.h>
47
 #include <ipxe/linebuf.h>
47
 #include <ipxe/base64.h>
48
 #include <ipxe/base64.h>
48
 #include <ipxe/base16.h>
49
 #include <ipxe/base16.h>
88
 /** Block size used for HTTP block device request */
89
 /** Block size used for HTTP block device request */
89
 #define HTTP_BLKSIZE 512
90
 #define HTTP_BLKSIZE 512
90
 
91
 
92
+/** Retry delay used when we cannot understand the Retry-After header */
93
+#define HTTP_RETRY_SECONDS 5
94
+
91
 /** HTTP flags */
95
 /** HTTP flags */
92
 enum http_flags {
96
 enum http_flags {
93
 	/** Request is waiting to be transmitted */
97
 	/** Request is waiting to be transmitted */
185
 
189
 
186
 	/** Request retry timer */
190
 	/** Request retry timer */
187
 	struct retry_timer timer;
191
 	struct retry_timer timer;
192
+	/** Retry delay (in timer ticks) */
193
+	unsigned long retry_delay;
188
 };
194
 };
189
 
195
 
190
 /**
196
 /**
342
 	}
348
 	}
343
 
349
 
344
 	/* Start request retry timer */
350
 	/* Start request retry timer */
345
-	start_timer_nodelay ( &http->timer );
351
+	start_timer_fixed ( &http->timer, http->retry_delay );
352
+	http->retry_delay = 0;
346
 }
353
 }
347
 
354
 
348
 /**
355
 /**
664
 	return 0;
671
 	return 0;
665
 }
672
 }
666
 
673
 
674
+/**
675
+ * Handle HTTP Retry-After header
676
+ *
677
+ * @v http		HTTP request
678
+ * @v value		HTTP header value
679
+ * @ret rc		Return status code
680
+ */
681
+static int http_rx_retry_after ( struct http_request *http, char *value ) {
682
+	unsigned long seconds;
683
+	char *endp;
684
+
685
+	DBGC ( http, "HTTP %p retry requested (%s)\n", http, value );
686
+
687
+	/* If we received a 503 Service Unavailable response, then
688
+	 * retry after the specified number of seconds.  If the value
689
+	 * is not a simple number of seconds (e.g. a full HTTP date),
690
+	 * then retry after a fixed delay, since we don't have code
691
+	 * able to parse full HTTP dates.
692
+	 */
693
+	if ( http->code == 503 ) {
694
+		seconds = strtoul ( value, &endp, 10 );
695
+		if ( *endp != '\0' ) {
696
+			seconds = HTTP_RETRY_SECONDS;
697
+			DBGC ( http, "HTTP %p cannot understand \"%s\"; "
698
+			       "using %ld seconds\n", http, value, seconds );
699
+		}
700
+		http->flags |= HTTP_TRY_AGAIN;
701
+		http->retry_delay = ( seconds * TICKS_PER_SEC );
702
+	}
703
+
704
+	return 0;
705
+}
706
+
667
 /** An HTTP header handler */
707
 /** An HTTP header handler */
668
 struct http_header_handler {
708
 struct http_header_handler {
669
 	/** Name (e.g. "Content-Length") */
709
 	/** Name (e.g. "Content-Length") */
701
 		.header = "WWW-Authenticate",
741
 		.header = "WWW-Authenticate",
702
 		.rx = http_rx_www_authenticate,
742
 		.rx = http_rx_www_authenticate,
703
 	},
743
 	},
744
+	{
745
+		.header = "Retry-After",
746
+		.rx = http_rx_retry_after,
747
+	},
704
 	{ NULL, NULL }
748
 	{ NULL, NULL }
705
 };
749
 };
706
 
750
 

Loading…
Cancel
Save