요약

  • POP3는 현재 메일드롭을 열고 난 뒤에야 메시지 번호를 부여했다. 더 이른LAST명령은 '지금까지 접근한 가장 높은 번호'라는 경계 하나를 기억했지만, 구성이 바뀌었을 때 접속하지 않은 클라이언트에게 메시지별로 내구성 있는 신원을 줄 수는 없었다.
  • RFC 1725는 LAST를 제거하고 선택 사항인 UIDL을 추가했다. 고유 ID는 하나의 메일드롭 안에서 세션을 넘어 유지되어 클라이언트가 자체 '읽음' 상태를 유지하게 했고, RFC 1939는 전 세계적 식별자, 물리적 사본당 하나의 식별자, 서버의 무기한 보관을 보장하는 데까지는 의도적으로 나아가지 않았다.

월요일에 어떤 POP3 클라이언트가 세 개의 메시지를 담은 메일드롭을 연다. 그 클라이언트가 내려받았지만 서버에 남겨둔 메시지는 2번이다. 화요일 접속 전에 메시지 1이 제거된다. 메일드롭이 다시 열리면 남겨둔 메시지는 이제 1번이다.

두 번호 중 어느 쪽도 잘못된 것이 없다. POP3는 현재 메일드롭을 연 뒤에 위치를 부여한다. 첫 번째 메시지는 1, 두 번째는 2, 이런 식이다. 번호는 그 트랜잭션 안에서RETR,DELE,LIST에 넘기기 좋은 효율적 피연산자일 뿐이다. 사서함의 서로 다른 두 시점 사이에서 항목에 대한 내구성 있는 이름은 아니다.

이 구분이 중요해진 이유는 POP3가 상시 연결을 유지할 수 없는 기계들을 위해 만들어졌기 때문이다. 초기 전제는 상주 메일 전송 시스템을 돌릴 자원이나 연결성이 부족한 더 작은 워크스테이션 또는 개인용 컴퓨터였다. 서버가 메일드롭에 메일을 보관하고, 클라이언트가 동적으로 접속해 가져오는 구조였다. 보통은 메시지를 내려받은 뒤 삭제했다.

클라이언트에 '서버에 메일 남기기' 기능이 등장하면서 단순한 프로토콜은 기억 문제를 떠안게 되었다. 다음 접속에서 클라이언트는 어떻게 남겨둔 모든 메시지를 다시 내려받는 일을 피할 수 있을까? 서버가 안정적인 토큰을 제공하고 클라이언트가 자기가 처리한 토큰을 기억하도록 하면 서버는 단순하게 유지될 수 있다. 그러나 세션 내 위치와 '지금까지 본 가장 높은 번호' 하나로는 그 책임을 안전하게 짊어질 수 없었다.

UIDL명령이 좁은 해답이었다. 이 명령은 현재 메시지 번호와 재접속 후에도 살아남도록 의도된 식별자를 짝지었다.

LAST는 집합이 아니라 경계 하나를 기억했다

1993년 6월에 발표된 RFC 1460은 세션 내 위치들을 메시지 ID라고 불렀다. 서버가 메일드롭을 해석한 뒤 첫 번째 메시지를 1, 두 번째를 2, n번째를 n으로 번호 매겼다. 용어는 내구성 있게 들릴 수 있지만, 그 메커니즘은 위치 기반이었다.

이 버전에는LAST명령도 있었다. 서버는 이전 트랜잭션에서 접근된 가장 높은 메시지 번호를 돌려주었다. 클라이언트는 그보다 높은 번호의 메시지가 아직 접근되지 않았음을 추론할 수 있었다. 더 높은 번호를 가져오거나 삭제하면 경계가 앞으로 옮겨지고,RSET은 경계를 0으로 되돌렸다.

이 모델은 역사를 하나의 정수로 압축했다. '이미 처리됨'이 깨끗한 접두사를 이룰 때만 동작했다. 메시지 1과 3은 로컬에 저장됐지만 2는 저장되지 않은 빈 구멍을 표현할 수 없었다. 서로 다른 로컬 이력을 가진 두 클라이언트를 구분하지도 못했다. 리셋은 경계를 지웠고, 낮은 번호의 메시지가 제거되면 나중 위치들의 의미 자체가 바뀔 수 있었다.

하이 워터 마크는 '이 순서 아래에서 어떤 접근이 얼마나 진행되었는가'에는 답한다. '이 특정 항목이 이 클라이언트가 이미 받은 바로 그 항목인가'에는 답하지 않는다.

RFC 1725는 개정 목록에서 이 변화를 이례적으로 뚜렷하게 드러냈다. LAST를 제거하고 선택 사항인 UIDL을 추가한 것이다. 본문은 하나의 인과 사슬을 주장하지 않았지만, 이 짝을 이룬 변경은 서버가 쥔 하나의 조악한 진행 표식을, 클라이언트가 자기 상태를 만들어 나갈 수 있는 메시지별 토큰으로 바꾸었다.

UIDL은 일시적 위치를 영속적 토큰과 연결했다

트랜잭션 상태에서UIDL은 메시지 번호를 받거나 인수 없이 쓸 수 있다. 메시지를 하나 지정하면 서버는 현재 번호와 그 메시지의 고유 ID를 돌려준다. 인수 없이 호출하면 삭제 표시되지 않은 각 메시지에 대해 여러 줄짜리 목록을 돌려준다.

이 두 열은 수명이 다르다. 번호는 이렇게 열어 둔 메일드롭 안에서 메시지를 어떻게 지시할지 알려준다. 고유 ID는 서버가 그 항목을 이전 세션에서 식별된 바로 그 항목으로 여기는지를 알려준다.

RFC 1939는 이 토큰을 서버가 임의로 정한 1~70개의 인쇄 가능한 문자로 이루어진 문자열로 정의한다. 메일드롭 안에서 메시지를 유일하게 식별해야 하고 세션을 넘어 유지되어야 한다. 이전 세션이 UPDATE 상태에 들어가지 못한 채 끝났더라도 유지가 요구된다.

이 비정상 종료 조항이 중요하다. 클라이언트는 연결이 끊기기 전에 메시지를 받아 저장했을 수 있다. 세션이 정상적으로 끝나지 않았으므로 서버는 삭제 표시된 메시지를 제거해서는 안 된다. 재접속하면 같은 메시지가 여전히 있을 수 있다. 이전 트랜잭션이 UPDATE에 이르지 못했다는 이유만으로 UID가 바뀐다면, 클라이언트는 중복 사본을 내려받거나 깨진 기억을 근거로 파괴적인 결정을 내릴 수 있다.

서버는 그 항목이 존재하는 동안 같은 메일드롭에서 고유 ID를 재사용해서는 안 된다. 재사용은 새로운 또는 다른 항목이 클라이언트의 로컬 장부에 있는 오래된 항목을 사칭하게 만든다.

UIDL은 그리하여 작업 분담을 만들었다. 서버는 범위가 한정된 신원을 부여하고 보존한다. 클라이언트는 그 신원을 가져왔고, 표시했고, 보관했거나 그 밖의 방식으로 다루었다는 정책별 사실을 저장한다. POP3가 완전한 원격 사서함 관리자가 될 필요 없이 더 신중한 가져오기를 지원할 수 있었다.

'고유'는 저장된 사본 하나보다 의도적으로 좁게 정의되었다

규격은 UIDL을 전 세계적인 메시지 신원으로 만들지 않는다. 토큰은 메일드롭 안에서만 유일하다. 다른 계정, 다른 서버, 다른 메일드롭에서의 같은 문자열과는 정의된 관계가 없다. 이것은 인터넷 메시지 헤더Message-ID가 아니며, 발신자 신원의 증명도, 전달의 증명도, 무결성 서명도 아니다.

물리적 사본과 일대일일 필요도 없다. RFC 1939는 서버가 일반적으로 임의로 할당된 ID를 저장해야 하지만, 메시지의 해시로 계산하는 것을 명시적으로 허용한다. 클라이언트는 하나의 메일드롭에 서로 같은 사본 두 개가 같은 고유 ID를 갖는 상황을 처리할 수 있어야 한다.

이 예외는 복수성을 토큰 바깥에 둔다. 목록에 같은 UID가 두 개의 현재 번호로 두 번 나타난다면, 클라이언트는 자기 캐시가 UID를 키로 쓴다는 이유만으로 그것들을 조용히 한 행으로 합칠 수 없다. 식별자는 범위가 한정된 인식 질문에 답한다. 서버가 현재 구분 불가능한 사본을 몇 개 보관하는지는 답하지 않을 수 있다.

이것은 중요한 근거 규율이다. 프로토콜 이름은 구현을 범위 상승으로 유혹하기 쉽다. 고유는 전 세계적으로 고유가 되고, 영속은 영구가 되고, 신원은 진위가 되는 식이다. UIDL의 본문은 이런 상승을 하나하나 막는다. 그 권위는 명시된 충돌 사례를 전제로, 하나의 메일드롭 안에서 세션을 넘는 인식에 충분하다.

영속성은 보관을 약속하지 않았다

식별자는 그 항목이 존재하는 동안 항목에 대해 영속될 수 있지만, 항목이 영원히 존재하도록 요구하지는 않는다. RFC 1939는 '서버에 남기기' 사용이 이미 읽은 메시지 수백·수천 통을 쌓을 수 있다고 경고한다. 운영자는 할당량이나 로컬 보관 정책을 둘 수 있고, 사용자에게 알리는 조건 아래 POP3 명령 흐름 바깥에서 메시지를 삭제할 수 있다.

따라서 클라이언트는 오래된 UID를 저장 보장으로 다룰 수 없다. 더 이상 나타나지 않는다면 서버가 정책을 적용했거나, 다른 클라이언트가 그 메시지를 삭제했거나, 목록 조회가 실패했을 수 있다. 부재를 결론으로 바꾸기 전에 클라이언트는 현재 세션에 대한 근거가 필요하다.

RFC 2449는 나중에 POP3 확장 메커니즘을 도입했다. 그 전에는 선택 명령과 동작을, 가능하다 해도 탐색(probing)으로 발견해야 했기 때문이다.CAPA응답의UIDL줄은 클라이언트에게 UIDL이 지원된다고 알려준다. 그러나 그것은 서버의 UID 할당 품질을 보증하거나, 서버가 어떤 메시지든 보관할 것임을 증명하지는 않는다.

같은 RFC는 사이트가 적용할 수 있는 최소 보관 동작을 광고하는EXPIRE를 정의했다. 며칠이라는 숫자, 0, 또는 NEVER다. 그 능력조차 의도적으로 특정 메시지의 정확한 만료 시각을 명명할 수 없다. 사이트는 도착, 첫 목록 조회, 가져오기 또는 다른 사건에 시계를 맞출 수 있다.

능력, 신원, 보관은 서로 다른 세 가지 사실이었다. UIDL은 제공되는 동안 항목을 어떻게 인식할지 말했고, CAPA는 명령이 사용 가능하다고 말했으며, EXPIRE는 사이트 정책의 범위를 정했다. 어느 하나도 다른 것을 대신할 수 없었다.

단순한 서버는 내구성 있는 기억을 가장자리로 옮겼다

RFC 1939는 확장된 목록 형식 대신 선택 명령들을 강력히 권장했고 설계 철학을 분명히 밝혔다. 지능은 서버가 아니라 POP3 클라이언트에 두라는 것이다. UIDL은 이 배분을 따랐다.

이점은 아키텍처적 절약이었다. 서버는 모든 기기마다 동기화된 읽음/안 읽음 모델을 가질 필요가 없었다. 서로 다른 클라이언트는 서로 다른 로컬 장부를 유지할 수 있었다. 일시적 접속은 모든 본문을 가져오는 대신 작은 목록을 비교하는 것으로 유용한 작업을 이어갈 수 있었다.

대가는 책임의 이전이었다. 클라이언트가 UID 데이터베이스를 잃으면 남겨둔 메일을 다시 내려받을 수 있다. 서버 이주가 식별자를 재생성하면 모든 클라이언트가 오래된 내용을 새것으로 해석할 수 있다. 클라이언트가 UID를 내용 신원으로 가정하면 동일한 사본이 놓칠 수 있다. UID 부재를 로컬 저장 성공의 증거로 다루면, 보관 정책이 장부 오류를 영구적인 손실로 바꿔놓을 수 있다.

UIDL의 역사적 가치는 사서함 동기화 문제를 풀었다는 데 있지 않았다. 두 개의 시계 사이에 좁고 다룰 수 있는 선을 그은 것이다. 서버는 어떤 항목들이 여전히 현재 메일드롭을 차지하는지 알았고, 간헐적으로 접속하는 클라이언트는 그 항목들 가운데 무엇을 이미 본 적이 있는지 알았다.

번호는 세션 동안만 살아남았다. 식별자는 기억이 단절을 건너갈 만큼 오래 남았다.

출처