주소에서 www.를 떼려고 lstrip("www.")을 썼습니다.
테스트한 주소가 전부 정상으로 보여서 그대로 넘어갔고, 몇 달 뒤에야
w로 시작하는 도메인만 골라서 깨지고 있다는 걸 알았습니다.
이름 때문에 오해하기 쉽지만 lstrip의 인자는 접두사가 아니라 문자 집합입니다.
"www."을 넘기면 파이썬은 이걸 {'w', '.'}라는 문자 모음으로 해석하고,
문자열 왼쪽부터 그 집합에 속한 문자가 나오지 않을 때까지 계속 지웁니다.
>>> "www.example.com".lstrip("www.")
'example.com' # 맞는 것처럼 보인다
>>> "wave.co.kr".lstrip("www.")
'ave.co.kr' # w 가 지워졌다
>>> "world.example".lstrip("www.")
'orld.example' # 여기도
>>> "wwwww...abc".lstrip("www.")
'abc' # 몇 개가 있든 전부 지운다
www.example.com이 맞게 나오는 건 로직이 옳아서가 아닙니다.
w, w, w, .를 차례로 지우고 나서
다음 글자 e가 집합에 없으니 멈춘 것뿐입니다. 우연히 결과가 같았습니다.
확인에 쓴 주소가 하필 www.로 시작하거나 자음이 다른 도메인뿐이었습니다.
한 종류의 입력만으로는 이 버그가 절대 드러나지 않습니다.
경계를 건드리는 입력(w로 시작하는 도메인)을 일부러 넣어야 보입니다.
| 입력 | 기대 | 실제 |
|---|---|---|
www.example.com | example.com | example.com |
wave.co.kr | wave.co.kr | ave.co.kr |
world.example | world.example | orld.example |
web.example.com | web.example.com | eb.example.com |
.www.example.com | .www.example.com | example.com |
마지막 줄이 특히 고약합니다. 앞에 점이 붙어 있어도 집합에 .이 있으니 같이 지워집니다.
즉 입력이 이상해도 그럴듯한 결과가 나옵니다. 예외가 안 나니 로그에도 안 남습니다.
파이썬 3.9부터는 removeprefix가 있습니다. 이름 그대로 접두사일 때만 지웁니다.
# 3.9 이상
host = host.removeprefix("www.")
# 3.8 이하
if host.startswith("www."):
host = host[4:]
확장자를 떼려고 쓰는 rstrip(".html")도 집합 {'.', 'h', 't', 'm', 'l'}로 동작합니다.
끝을 자를 때는 removesuffix를 써야 합니다.
>>> "index.html".rstrip(".html")
'index' # 우연히 맞다
>>> "post.html".rstrip(".html")
'pos' # 끝의 t 가 지워졌다
>>> "about.html".rstrip(".html")
'abou' # 여기도
함수를 고친 뒤에 더 큰 문제를 마주했습니다.
검색엔진 웹마스터 도구는 www가 붙은 주소와 없는 주소를 서로 다른 사이트로 취급합니다.
등록은 www.example.com으로 해놓고 요청은 example.com으로 보내면
"등록되지 않은 사이트"로 거절당합니다. 코드가 조용히 주소를 바꿔놨다는 사실을 모르면
왜 거절되는지 알 수가 없습니다.
그래서 임의로 정규화하지 않는 쪽으로 방향을 바꿨습니다. 두 형태를 순서대로 시도하고, 성공한 주소가 무엇이었는지 결과에 남깁니다. 나중에 "왜 이 주소로 나갔지"를 되짚을 수 있어야 합니다.
lstrip·rstrip의 인자는 접두사가 아니라 문자 집합입니다.removeprefix / removesuffix를 씁니다.이 글은 EonsFlow가 자동화 도구를 만들며 겪은 내용을 정리한 것입니다. 조용히 실패하는 다른 사례로 사이트맵을 못 찾는 이유와 워드프레스 REST API로 글 전부 가져오기도 정리해 두었습니다.