URL.join() decodes percent-encoded characters in the base path (e.g. %2F becomes /)
- 主要語言
- Python
- 星號
- 1.5k
- 分支
- 215
- 平均合併
- 1 天 2 分鐘
- 30 天內合併 PR
- 13
描述
### Description
`URL.join()` decodes percent-encoded characters in the base URL's path when merging a relative reference (RFC 3986 §5.3, the branch used when the base path does not end with `/`). The merge is built from `self.parts`, which are already percent-decoded, so an encoded delimiter like `%2F` is turned into a real `/` and the path structure is corrupted.
### Reproduction
```python
from yarl import URL
print(URL("http://x/a%2Fb/c").join(URL("d"))) # http://x/a/b/d
print(URL("http://x/a%20b/c").join(URL("d"))) # http://x/a b/d
```
### Expected vs actual
| | result |
|---|---|
| expected | `http://x/a%2Fb/d` (the `a%2Fb` segment is preserved) |
| actual | `http://x/a/b/d` (`%2F` decoded into a separator -> the single segment splits into two) |
`%20` is likewise decoded into a literal space.
### Root cause
The RFC-3986 merge branch in `URL.join` constructs the merged path from `self.parts[:-1]`. `parts` runs the segments through `UNQUOTER` (decoded), so feeding them back into a path mixes decoded text with the still-encoded relative path. The raw/encoded segments (`raw_parts`) should be used for the merge so the original encoding round-trips.
(Distinct from #896, which is RFC-correct last-segment replacement; this is specifically the loss of percent-encoding.)
貢獻指南
研究方向
Start in URL.join, specifically the RFC 3986 merge branch used when the base path lacks a trailing slash, and compare how self.parts and raw_parts represent encoded segments. Add regression coverage for the supplied %2F and %20 examples; done means the encoded path is preserved in the joined URL.
由索引模型根據 Issue 內容生成。
評估
- 技術堆疊
- python
- 領域
- backend
- Issue 類型
- 缺陷
- 難度
- 2/5
- 預估耗時
- 1-3 小時
- 活躍度
- 冷清
- 描述清晰度
- 描述清楚
- 新手友好度
- 78/100