Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -80,9 +80,9 @@ def write_from_path(self, path: PathBuf, operator: Operator | None = None):
Write into remote file with content from local file
"""
original_url = None
if isinstance(path, str) and path.startswith(("http://", "https://")):
original_url = path
if operator is None:
if isinstance(path, str) and path.startswith(("http://", "https://")):
original_url = path
path, operator, _ = operator_for_path(path)

with OpendalAdapter(client=self.client, operator=operator, path=path, original_url=original_url) as handle:
Expand Down Expand Up @@ -634,9 +634,9 @@ def _flash_single(
):
"""Flash image to DUT"""
original_url = None
if isinstance(image, str) and image.startswith(("http://", "https://")):
original_url = image
if operator is None:
if isinstance(image, str) and image.startswith(("http://", "https://")):
original_url = image
image, operator, _ = operator_for_path(image)

with OpendalAdapter(
Expand Down Expand Up @@ -772,9 +772,9 @@ def flash(
self.host()

original_url = None
if isinstance(path, str) and path.startswith(("http://", "https://")):
original_url = path
if operator is None:
if isinstance(path, str) and path.startswith(("http://", "https://")):
original_url = path
path, operator, _ = operator_for_path(path)

with OpendalAdapter(
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import hashlib
import os
from contextlib import contextmanager
from http.server import BaseHTTPRequestHandler, HTTPServer
from pathlib import Path
from random import randbytes
Expand Down Expand Up @@ -325,6 +326,73 @@ def test_copy_and_rename_tracking(tmp_path):
assert len(created_paths) == 4


@contextmanager
def _http_path_recording_server():
"""Start an HTTP server that records request paths and serves minimal responses."""
received_paths = []

class Handler(BaseHTTPRequestHandler):
def do_HEAD(self):
self.send_response(200)
self.send_header("content-length", "4")
self.end_headers()

def do_GET(self):
received_paths.append(self.path)
self.send_response(200)
self.send_header("content-length", "4")
self.end_headers()
self.wfile.write(b"data")

def log_message(self, format, *args):
pass

server = HTTPServer(("127.0.0.1", 0), Handler)
port = server.server_address[1]
thread = Thread(target=server.serve_forever, daemon=True)
thread.start()
try:
yield port, received_paths
finally:
server.shutdown()
server.server_close()
thread.join(timeout=2)


def _assert_encoding_preserved(received_paths):
assert len(received_paths) >= 1
assert "%40" in received_paths[-1], (
f"Server received decoded path {received_paths[-1]!r} — "
f"original_url bypass did not activate with explicit operator"
)


def test_write_from_path_http_with_explicit_operator(tmp_path):
"""write_from_path must use original_url bypass even when operator is passed explicitly.

Callers like RideSX resolve the operator themselves via operator_for_path() and
pass it in. The original_url detection must happen before the `if operator is None`
guard, otherwise the HTTP URL goes through OpenDAL presign_read which mangles it
into a double-host path like endpoint/https%3A/host/path.
"""
with serve(Opendal(scheme="fs", kwargs={"root": str(tmp_path)})) as client:
with _http_path_recording_server() as (port, received_paths):
url = f"http://127.0.0.1:{port}/path%40encoded/file.bin"
explicit_operator = Operator("http", endpoint=f"http://127.0.0.1:{port}")
client.write_from_path("dest.bin", url, operator=explicit_operator)
_assert_encoding_preserved(received_paths)


def test_flash_http_with_explicit_operator():
"""FlasherClient.flash must use original_url bypass even when operator is passed explicitly."""
with serve(MockFlasher()) as flasher:
with _http_path_recording_server() as (port, received_paths):
url = f"http://127.0.0.1:{port}/path%40encoded/file.bin"
explicit_operator = Operator("http", endpoint=f"http://127.0.0.1:{port}")
flasher.flash(url, operator=explicit_operator)
_assert_encoding_preserved(received_paths)


def test_flash_http_url_preserves_percent_encoding():
"""Flashing from HTTP URL with percent-encoded path must preserve encoding.

Expand Down
Loading