@@ -955,6 +955,83 @@ def test_vsicurl_retry_codes_no_match(server):
955955 assert len (data ) == 0
956956
957957
958+ ###############################################################################
959+ # Test that ReadMultiRange retries on 429
960+
961+
962+ def test_vsicurl_readmultirange_retry (server ):
963+
964+ gdal .VSICurlClearCache ()
965+
966+ filesize = 262976
967+
968+ def serve_range (request ):
969+ if "Range" not in request .headers :
970+ request .send_response (404 )
971+ request .end_headers ()
972+ return
973+ rng = request .headers ["Range" ][len ("bytes=" ) :]
974+ start = int (rng .split ("-" )[0 ])
975+ end = int (rng .split ("-" )[1 ])
976+ request .protocol_version = "HTTP/1.1"
977+ request .send_response (206 )
978+ request .send_header ("Content-type" , "application/octet-stream" )
979+ request .send_header ("Content-Range" , "bytes %d-%d/%d" % (start , end , filesize ))
980+ request .send_header ("Content-Length" , end - start + 1 )
981+ request .send_header ("Connection" , "close" )
982+ request .end_headers ()
983+ with open ("../gdrivers/data/utm.tif" , "rb" ) as f :
984+ f .seek (start , 0 )
985+ request .wfile .write (f .read (end - start + 1 ))
986+
987+ def serve_429 (request ):
988+ request .protocol_version = "HTTP/1.1"
989+ request .send_response (429 )
990+ request .send_header ("Connection" , "close" )
991+ request .end_headers ()
992+
993+ handler = webserver .SequentialHandler ()
994+ handler .add (
995+ "HEAD" ,
996+ "/readmultirange_retry.tif" ,
997+ 200 ,
998+ {"Content-Length" : "%d" % filesize },
999+ )
1000+ # GETs 1-3: header/IFD reads + first tile strip (all succeed)
1001+ for i in range (3 ):
1002+ handler .add ("GET" , "/readmultirange_retry.tif" , custom_method = serve_range )
1003+ # GET 4: second tile strip -> 429
1004+ handler .add ("GET" , "/readmultirange_retry.tif" , custom_method = serve_429 )
1005+ # GETs 5-6: remaining tile strips succeed
1006+ for i in range (2 ):
1007+ handler .add ("GET" , "/readmultirange_retry.tif" , custom_method = serve_range )
1008+ # GET 7: retry of the failed tile strip
1009+ handler .add ("GET" , "/readmultirange_retry.tif" , custom_method = serve_range )
1010+
1011+ with webserver .install_http_handler (handler ):
1012+ with gdaltest .config_options (
1013+ {
1014+ "GTIFF_DIRECT_IO" : "YES" ,
1015+ "CPL_VSIL_CURL_ALLOWED_EXTENSIONS" : ".tif" ,
1016+ "GDAL_DISABLE_READDIR_ON_OPEN" : "EMPTY_DIR" ,
1017+ "GDAL_HTTP_MAX_RETRY" : "2" ,
1018+ "GDAL_HTTP_RETRY_DELAY" : "0.01" ,
1019+ }
1020+ ):
1021+ ds = gdal .Open (
1022+ "/vsicurl/http://localhost:%d/readmultirange_retry.tif" % server .port
1023+ )
1024+ assert ds is not None
1025+ subsampled_data = ds .ReadRaster (0 , 0 , 512 , 32 , 128 , 4 )
1026+ ds = None
1027+ assert subsampled_data is not None
1028+ ds = gdal .GetDriverByName ("MEM" ).Create ("" , 128 , 4 )
1029+ ds .WriteRaster (0 , 0 , 128 , 4 , subsampled_data )
1030+ cs = ds .GetRasterBand (1 ).Checksum ()
1031+ ds = None
1032+ assert cs == 6429
1033+
1034+
9581035###############################################################################
9591036
9601037
0 commit comments