|
@@ -43,6 +43,7 @@ FILE_LICENCE ( GPL2_OR_LATER );
|
43
|
43
|
#include <ipxe/tcpip.h>
|
44
|
44
|
#include <ipxe/process.h>
|
45
|
45
|
#include <ipxe/retry.h>
|
|
46
|
+#include <ipxe/timer.h>
|
46
|
47
|
#include <ipxe/linebuf.h>
|
47
|
48
|
#include <ipxe/base64.h>
|
48
|
49
|
#include <ipxe/base16.h>
|
|
@@ -88,6 +89,9 @@ FILE_LICENCE ( GPL2_OR_LATER );
|
88
|
89
|
/** Block size used for HTTP block device request */
|
89
|
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
|
95
|
/** HTTP flags */
|
92
|
96
|
enum http_flags {
|
93
|
97
|
/** Request is waiting to be transmitted */
|
|
@@ -185,6 +189,8 @@ struct http_request {
|
185
|
189
|
|
186
|
190
|
/** Request retry timer */
|
187
|
191
|
struct retry_timer timer;
|
|
192
|
+ /** Retry delay (in timer ticks) */
|
|
193
|
+ unsigned long retry_delay;
|
188
|
194
|
};
|
189
|
195
|
|
190
|
196
|
/**
|
|
@@ -342,7 +348,8 @@ static void http_done ( struct http_request *http ) {
|
342
|
348
|
}
|
343
|
349
|
|
344
|
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,6 +671,39 @@ static int http_rx_www_authenticate ( struct http_request *http, char *value ) {
|
664
|
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
|
707
|
/** An HTTP header handler */
|
668
|
708
|
struct http_header_handler {
|
669
|
709
|
/** Name (e.g. "Content-Length") */
|
|
@@ -701,6 +741,10 @@ static struct http_header_handler http_header_handlers[] = {
|
701
|
741
|
.header = "WWW-Authenticate",
|
702
|
742
|
.rx = http_rx_www_authenticate,
|
703
|
743
|
},
|
|
744
|
+ {
|
|
745
|
+ .header = "Retry-After",
|
|
746
|
+ .rx = http_rx_retry_after,
|
|
747
|
+ },
|
704
|
748
|
{ NULL, NULL }
|
705
|
749
|
};
|
706
|
750
|
|