@@ -58,6 +58,7 @@ def _get_image_layer(image_id, headers=None, bytes_range=None):
58
58
if headers is None :
59
59
headers = {}
60
60
61
+ headers ['Content-Type' ] = 'application/octet-stream'
61
62
accel_uri_prefix = cfg .nginx_x_accel_redirect
62
63
path = store .image_layer_path (image_id )
63
64
if accel_uri_prefix :
@@ -71,11 +72,29 @@ def _get_image_layer(image_id, headers=None, bytes_range=None):
71
72
logger .warn ('nginx_x_accel_redirect config set,'
72
73
' but storage is not LocalStorage' )
73
74
status = None
74
- if bytes_range :
75
- status = 206
76
- headers ['Content-Range' ] = '{0}-{1}/*' .format (* bytes_range )
75
+ layer_size = 0
76
+
77
77
if not store .exists (path ):
78
78
raise IOError ("Image layer absent from store" )
79
+ try :
80
+ layer_size = store .get_size (store .image_layer_path (image_id ))
81
+ except OSError :
82
+ pass
83
+ if bytes_range and bytes_range [1 ] == - 1 and not layer_size == 0 :
84
+ bytes_range = (bytes_range [0 ], layer_size )
85
+
86
+ if bytes_range :
87
+ content_length = bytes_range [1 ] - bytes_range [0 ]
88
+ if not _valid_bytes_range (bytes_range ):
89
+ return flask .Response (status = 416 , headers = headers )
90
+ status = 206
91
+ content_range = (bytes_range [0 ], bytes_range [1 ], layer_size )
92
+ headers ['Content-Range' ] = '{0}-{1}/{2}' .format (* content_range )
93
+ headers ['Content-Length' ] = content_length
94
+ elif layer_size > 0 :
95
+ headers ['Content-Length' ] = layer_size
96
+ else :
97
+ return flask .Response (status = 416 , headers = headers )
79
98
return flask .Response (store .stream_read (path , bytes_range ),
80
99
headers = headers , status = status )
81
100
@@ -106,15 +125,29 @@ def _parse_bytes_range():
106
125
logger .debug (log_msg )
107
126
return
108
127
bytes_range = range_header [6 :].split ('-' )
109
- if len (bytes_range ) != 2 :
128
+ if len (bytes_range ) != 2 and not range_header [ - 1 ] == '-' :
110
129
logger .debug (log_msg )
111
130
return
131
+ if len (bytes_range ) == 1 or bytes_range [1 ] == '' :
132
+ bytes_range = (bytes_range [0 ], - 1 )
133
+ try :
134
+ return (int (bytes_range [0 ]), - 1 )
135
+ except ValueError :
136
+ logger .debug (log_msg )
112
137
try :
113
138
return (int (bytes_range [0 ]), int (bytes_range [1 ]))
114
139
except ValueError :
115
140
logger .debug (log_msg )
116
141
117
142
143
+ def _valid_bytes_range (bytes_range ):
144
+ if bytes_range [0 ] < 0 or bytes_range [1 ] < 1 :
145
+ return False
146
+ if bytes_range [1 ] - bytes_range [0 ] < 0 :
147
+ return False
148
+ return True
149
+
150
+
118
151
@app .route ('/v1/private_images/<image_id>/layer' , methods = ['GET' ])
119
152
@toolkit .requires_auth
120
153
@require_completion
0 commit comments