lazy-wheel: be more robust with regard to Artifactory's incorrect han… · python-poetry/poetry@d8afecb (original) (raw)

`@@ -2,6 +2,7 @@

`

2

2

``

3

3

`import re

`

4

4

``

``

5

`+

from enum import IntEnum

`

5

6

`from pathlib import Path

`

6

7

`from typing import TYPE_CHECKING

`

7

8

`from typing import Any

`

`@@ -51,7 +52,10 @@ def call(

`

51

52

` ) -> None: ...

`

52

53

``

53

54

``

54

``

`-

NEGATIVE_OFFSET_AS_POSITIVE = -1

`

``

55

`+

class NegativeOffsetFailure(IntEnum):

`

``

56

`+

numbers must be negative to avoid conflicts with HTTP status codes

`

``

57

`+

as_positive = -1 # JFrog Artifactory bug (RTDEV-38572)

`

``

58

`+

one_more = -2 # JFrog Artifactory bug (one more byte than requested)

`

55

59

``

56

60

``

57

61

`def build_head_response(

`

`@@ -68,19 +72,26 @@ def build_partial_response(

`

68

72

`wheel_bytes: bytes,

`

69

73

`response_headers: dict[str, Any],

`

70

74

`*,

`

71

``

`-

negative_offset_as_positive: bool = False,

`

``

75

`+

negative_offset_failure: NegativeOffsetFailure | None = None,

`

72

76

`) -> HTTPrettyResponse:

`

73

77

`status_code = 206

`

74

78

`response_headers["Accept-Ranges"] = "bytes"

`

75

79

`total_length = len(wheel_bytes)

`

76

80

`if rng.startswith("-"):

`

77

81

`# negative offset

`

78

82

`offset = int(rng)

`

79

``

`-

if negative_offset_as_positive:

`

``

83

`+

if negative_offset_failure == NegativeOffsetFailure.as_positive:

`

80

84

`# some servers interpret a negative offset like "-10" as "0-10"

`

81

85

`start = 0

`

82

86

`end = min(-offset, total_length - 1)

`

83

87

`body = wheel_bytes[start : end + 1]

`

``

88

`+

elif negative_offset_failure == NegativeOffsetFailure.one_more:

`

``

89

`+

https://github.com/python-poetry/poetry/issues/9056#issuecomment-1973273721

`

``

90

`+

offset -= 1 # one more byte

`

``

91

`+

start = total_length + offset # negative start of content range possible!

`

``

92

`+

end = total_length - 1

`

``

93

`+

body = wheel_bytes[offset:]

`

``

94

`+

response_headers["Content-Length"] = -offset # just wrong...

`

84

95

`else:

`

85

96

`start = total_length + offset

`

86

97

`if start < 0:

`

`@@ -131,12 +142,14 @@ def handle_request(

`

131

142

``

132

143

`rng = request.headers.get("Range", "=").split("=")[1]

`

133

144

``

134

``

`-

negative_offset_as_positive = False

`

``

145

`+

negative_offset_failure = None

`

135

146

`if negative_offset_error and rng.startswith("-"):

`

136

147

`if negative_offset_error[0] == codes.requested_range_not_satisfiable:

`

137

148

`response_headers["Content-Range"] = f"bytes */{len(wheel_bytes)}"

`

138

``

`-

if negative_offset_error[0] == NEGATIVE_OFFSET_AS_POSITIVE:

`

139

``

`-

negative_offset_as_positive = True

`

``

149

`+

if negative_offset_error[0] == NegativeOffsetFailure.as_positive:

`

``

150

`+

negative_offset_failure = NegativeOffsetFailure.as_positive

`

``

151

`+

elif negative_offset_error[0] == NegativeOffsetFailure.one_more:

`

``

152

`+

negative_offset_failure = NegativeOffsetFailure.one_more

`

140

153

`else:

`

141

154

`return (

`

142

155

`negative_offset_error[0],

`

`@@ -148,7 +161,7 @@ def handle_request(

`

148

161

`rng,

`

149

162

`wheel_bytes,

`

150

163

`response_headers,

`

151

``

`-

negative_offset_as_positive=negative_offset_as_positive,

`

``

164

`+

negative_offset_failure=negative_offset_failure,

`

152

165

` )

`

153

166

``

154

167

`status_code = 200

`

`@@ -219,7 +232,8 @@ def _assertion(

`

219

232

` (codes.requested_range_not_satisfiable, b"Requested range not satisfiable"),

`

220

233

` (codes.internal_server_error, b"Internal server error"), # GAR

`

221

234

` (codes.not_implemented, b"Unsupported client range"), # PyPI

`

222

``

`-

(NEGATIVE_OFFSET_AS_POSITIVE, b"handle negative offset as positive"),

`

``

235

`+

(NegativeOffsetFailure.as_positive, b"handle negative offset as positive"),

`

``

236

`+

(NegativeOffsetFailure.one_more, b"one more byte than requested"),

`

223

237

` ],

`

224

238

`)

`

225

239

`def test_metadata_from_wheel_url(

`

`@@ -236,10 +250,11 @@ def test_metadata_from_wheel_url(

`

236

250

`# 3.-5. see negative offsets 1.-3.

`

237

251

`expected_requests = 3

`

238

252

`if negative_offset_error:

`

239

``

`-

if negative_offset_error[0] in (

`

``

253

`+

if negative_offset_error[0] in {

`

240

254

`codes.requested_range_not_satisfiable,

`

241

``

`-

NEGATIVE_OFFSET_AS_POSITIVE,

`

242

``

`-

):

`

``

255

`+

NegativeOffsetFailure.as_positive,

`

``

256

`+

NegativeOffsetFailure.one_more,

`

``

257

`+

}:

`

243

258

`expected_requests += 1

`

244

259

`else:

`

245

260

`expected_requests += 2

`

`@@ -299,17 +314,25 @@ def test_metadata_from_wheel_url_with_redirect(

`

299

314

` )

`

300

315

``

301

316

``

302

``

`-

@pytest.mark.parametrize("negative_offset_as_positive", [False, True])

`

``

317

`+

@pytest.mark.parametrize(

`

``

318

`+

("negative_offset_failure", "expected_requests"),

`

``

319

`+

[

`

``

320

`+

(None, 1),

`

``

321

`+

(NegativeOffsetFailure.as_positive, 1),

`

``

322

`+

(NegativeOffsetFailure.one_more, 2),

`

``

323

`+

],

`

``

324

`+

)

`

303

325

`def test_metadata_from_wheel_url_smaller_than_initial_chunk_size(

`

304

326

`http: type[httpretty.httpretty],

`

305

327

`handle_request_factory: RequestCallbackFactory,

`

306

``

`-

negative_offset_as_positive: bool,

`

``

328

`+

negative_offset_failure: NegativeOffsetFailure | None,

`

``

329

`+

expected_requests: int,

`

307

330

`) -> None:

`

308

``

`-

domain = f"tiny-wheel-{str(negative_offset_as_positive).casefold()}.com"

`

``

331

`+

domain = f"tiny-wheel-{str(negative_offset_failure).casefold()}.com"

`

309

332

`uri_regex = re.compile(f"^https://{domain}/.*$")

`

310

333

`request_callback = handle_request_factory(

`

311

334

`negative_offset_error=(

`

312

``

`-

(NEGATIVE_OFFSET_AS_POSITIVE, b"") if negative_offset_as_positive else None

`

``

335

`+

(negative_offset_failure, b"") if negative_offset_failure else None

`

313

336

` )

`

314

337

` )

`

315

338

`http.register_uri(http.GET, uri_regex, body=request_callback)

`

`@@ -324,10 +347,8 @@ def test_metadata_from_wheel_url_smaller_than_initial_chunk_size(

`

324

347

`assert metadata["author"] == "Jason R. Coombs"

`

325

348

`assert len(metadata["requires_dist"]) == 12

`

326

349

``

327

``

`-

only one request because server gives a normal response with the entire wheel

`

328

``

`-

except for when server interprets negative offset as positive

`

329

350

`latest_requests = http.latest_requests()

`

330

``

`-

assert len(latest_requests) == 1

`

``

351

`+

assert len(latest_requests) == expected_requests

`

331

352

``

332

353

``

333

354

`@pytest.mark.parametrize("accept_ranges", [None, "none"])

`