요약

  • MIME은 본문 파트에 Message-ID 형태의Content-ID를 부여하여, 다른 파트가 그 위치나 외부 주소에 의존하지 않고도 해당 파트를 참조할 수 있게 했습니다.
  • multipart/related는 Content-ID를 사용해 복합 객체의 루트를 선택했고,cid:와 긴 형태의mid:는 동일한 레이블을 메시지 내부나 저장소에서 해석 가능한 참조로 바꾸었습니다.
  • 세계적으로 고유한 값으로 생성한다고 해서 그 레이블이 콘텐츠 해시, 인증 증명 또는 전역 검색 가능한 위치가 되는 것은 아니었습니다. 선택, 캐싱, 표시는 여전히 컨테이너 규칙과 수신 애플리케이션이 통제했습니다.

URL이 안쪽을 가리킬 수 있었다

URL의 평범한 이야기는 출발에서 시작됩니다. 문서가 주소를 담고 있고, 클라이언트가 그 주소를 따라 다른 자원으로 이동합니다. 복합 인터넷 메일은 더 기묘한 가능성을 도입했습니다. HTML 본문이cid:로 시작하는 이미지 참조를 담고 있을 수 있고, 그에 대응하는 이미지는 이미 같은 메시지의 다른 MIME 파트 안에 들어 있을 수 있었습니다. 해석이란 웹 서버에 접속하는 것이 아니라 감싸진 구조 안을 탐색하는 것을 의미했습니다.

이 구분 덕분에 리치 메일은 이식성을 얻었지만, 동시에 파일명과 본문 순서만으로는 신뢰 있게 답할 수 없는 질문도 만들어냈습니다. 게이트웨이, 저장소 또는 작성 도구가 메시지를 재배치한 뒤에 한 파트는 다른 파트를 어떻게 지정해야 할까? 그 답은 네트워크 위치인 척하지 않으면서 전송을 견뎌야 했습니다.

MIME에는 이미 그런 레이블에 필요한 형태가 있었습니다. 1992년 6월에 발표된RFC 1341은 평면적인 인터넷 메일 본문을 재귀적으로 중첩된 엔티티로 확장했습니다. 메시지나 본문 파트는 헤더와 본문을 가졌습니다. Content-Type과 Content-Transfer-Encoding과 함께, 이 규격은 선택적인 Content-ID와 Content-Description 필드를 도입했습니다. 첫 번째 필드는 어느 엔티티가 참조되는지를 말했고, 두 번째 필드는 그것이 무엇을 묘사하는지를 사람의 언어로 말할 수 있었습니다.

이 필드는 쉽게 간과되었습니다. 더 큰 MIME 혁명은 미디어 타입, 비 ASCII 텍스트, 멀티파트 프레이밍에 관한 것이었기 때문입니다. 그러나 Content-ID는 전혀 다른 문제를 해결했습니다. Content-Type은 디코딩된 바이트를 어떻게 해석해야 하는지 답했습니다. Content-Transfer-Encoding은 그 바이트가 전송을 위해 어떻게 표현되었는지 답했습니다. 멀티파트 경계는 직렬화된 파트 하나가 어디서 끝나는지 답했습니다. Content-ID는 어떤 참조가 어느 엔티티를 가리키는지 답했습니다. 이 질문들은 하나의 메시지에서 겹칠 수 있지만, 서로를 안전하게 대신할 수는 없었습니다.

레이블은 메시지의 문법을 빌렸을 뿐, 그 정체성을 빌리지는 않았다

개정된 MIME 규격인RFC 2045는 1996년에 이 필드의 계약을 명시했습니다. 그 값은 Message-ID와 동일한 문법을 사용했고, 세계적으로 고유하도록 생성되어야 했습니다. 그렇다고 본문 파트가 메시지가 되는 것은 아니었습니다. 이미 설치된 식별자 문법을 재사용하여, 상위 사용자 에이전트가 한 본문이 다른 본문을 참조하게 할 수 있도록 한 것입니다.

범위의 차이가 중요했습니다. Message-ID는 메시지 전체를 지정합니다. Content-ID는 하나의 MIME 엔티티에 레이블을 붙이며, 그 엔티티는 최상위 본문일 수도 있고 재귀 트리 안의 한 파트일 수도 있습니다. 꺾쇠 괄호 문법을 복사했다고 해서 애플리케이션 안에서 두 네임스페이스가 합쳐지는 것은 아니었습니다. 서로 다른 객체를 유지하면서, 두 값 모두에 주소와 유사한 로컬 파트와 도메인의 충돌 저항 관습을 부여한 것입니다.

RFC 2045는 캐싱을 활용 사례 중 하나로 명명했습니다.message/external-body엔티티는 직접적인 본문 밖에서 도달하는 데이터를 묘사하므로, 이 선택적 미디어 타입을 생성하는 구현은 Content-ID를 제공해야 했습니다. 캐시는 대체 접근 지침들 사이에서 참조된 엔티티를 인식할 수 있었습니다. 그러나 이 식별자는 옥텟으로부터 파생된 것이 아니었습니다. 같은 레이블은 작성자의 동일성 주장일 뿐이었고, 다른 레이블이 다른 바이트를 증명하지도, 같은 레이블이 동등함을 암호학적으로 증명하지도 않았습니다.

세계적으로 고유하다는 것이 전역적으로 검색 가능하다는 뜻도 아니었습니다. 생성에 대한 요구사항은 충돌 위험을 줄일 뿐입니다. 보편적인 Content-ID 인덱스, DNS 레코드, HTTP 오리진, 바이트를 반환할 의무가 있는 서비스를 만들지는 않습니다. 수신자는 완벽한 형태의 식별자를 가지고도, 그 파트를 사용하는 데 필요한 메시지, 저장소 문맥, 지원 미디어 타입 또는 권한을 갖지 못할 수 있었습니다.

때로는 하나의 레이블이 의도적으로 여러 표현을 아우렀다

표면적인 하나의 레이블/하나의 파트 규칙에는 통제된 예외가 있었습니다.RFC 2046은 동일한 정보의 서로 다른 표현을 위한multipart/alternative를 정의했습니다. 수신자는 일반적으로 자신이 표시할 수 있는 마지막 형식을 선택하며, 순서는 단순한 형식에서 풍부한 형식으로 갑니다.

Content-ID의 의미는 경계로 구분된 파트의 개수만이 아니라 정보를 따라갑니다. 대안 간의 변환에서 정보가 손실된다면, 파트들은 서로 다른 식별자를 사용해야 합니다. 여러message/external-body파트가 동일한 데이터에 도달하는 서로 다른 방법을 제공한다면, 캐시가 여러 접근 방식 뒤에 하나의 객체를 인식할 수 있도록 같은 Content-ID를 사용할 수 있습니다. 그러면 감싸는 멀티파트 규칙이 표현을 선택합니다.

이 예외는 필드의 진짜 수준을 드러냅니다. Content-ID는 직렬화된 노드 위의 데이터베이스 기본 키가 아닙니다. MIME 구조 안에서 해석되는, 의도된 콘텐츠 동일성에 대한 증거입니다. 감싸는 미디어 타입을 읽지 않고 모든 중복을 거부하는 파서는 유효한 대안을 버릴 수 있습니다. 모든 곳에서 중복을 수용하는 파서는 모호하거나 적대적인 메시지가 참조를 재지정하게 놔둘 수 있습니다. 어떤 동작이 정당한지는 문맥이 결정합니다.

복합 객체에는 명시적인 루트가 필요했다

이미지와 함께 HTML 페이지를 메일로 보내는 일은 첨부물의 모음 이상을 요구했습니다. 그 파트들은 하나의 복합 객체를 이루었습니다. 문서가 이미지, 스타일 또는 다른 구성요소를 참조하고, 각 파트를 독립적으로 표시하면 의도된 관계가 사라졌습니다.RFC 2110은 1997년에 집합 문서를 위한 초기 형태의 MIME 캡슐화를 표준화하며, 내장 링크를 Content-ID, CID URL, Content-Location과 연결했습니다.

RFC 2387은 1998년에 이 컨테이너를multipart/related로 일반화했습니다. 그type매개변수는 루트의 미디어 타입을 선언합니다. 선택적인start매개변수는 Content-ID를 통해 애플리케이션이 가장 먼저 처리할 파트를 가리킵니다.start가 없으면 첫 번째 본문 파트가 루트가 됩니다.

여기서 서로 다른 두 권한이 배분되었습니다. 직렬화 순서가 기본값을 제공했고, 명시적인 식별자가 그것을 재정의할 수 있었습니다. 게이트웨이는start관계를 보존하거나 올바르게 다시 쓰는 경우에만, 의도된 루트를 첫 번째 위치에서 옮길 수 있었습니다.type매개변수는 사전 정보를 제공했지만 마법 같은 강제 장치는 아니었습니다. 실제 루트의 Content-Type과 불일치하면, 규격은 사용자 에이전트의 동작을 미정으로 두었습니다.

related 처리는 또한 첨부물의 일반적인 표시 제안보다 우위에 있었습니다. 그림이 파일명이나 Content-Disposition을 가질 수 있지만, 복합 객체 안에서의 역할은 related 애플리케이션의 규칙에서 나왔습니다. 동일한 바이트가 한 구조에서는 독립적으로 내려받을 수 있는 첨부물이고, 다른 구조에서는 없어서는 안 될 인라인 구성요소일 수 있었습니다.

cid:는 헤더 값을 링크 문법으로 번역했다

RFC 2392는 Message-ID와 Content-ID에 URL 형태를 부여했습니다. CID URL은cid:뒤에 URL 인코딩된 addr-spec이 오는 형태입니다. 헤더 값을 복구하려면, 구현은 접두어를 제거하고 백분율 디코딩을 수행한 뒤 꺾쇠 괄호를 복원합니다. 복구된 addr-spec은 이후 MIME 트리 안의 Content-ID 값들과 직접 비교할 수 있습니다.

URL 문법이 메시지 문맥을 폐지하지는 않았습니다. 많은 저장소가 메시지는 색인했지만 감싸진 모든 본문 파트를 색인하지는 않았습니다. 따라서 RFC 2392는 긴 MID 형태인mid:message-id/content-id를 정의하고, 적합 구현이 이를 지원하도록 요구했습니다. 첫 번째 식별자가 메시지를 찾고, 두 번째 식별자가 그 안에서 엔티티를 찾습니다. 짧은cid:참조는 보통 같은 메시지의 다른 본문 파트로 한정되지만, 저장소는 전역 고유성을 더 넓은 검색에 활용할 수도 있습니다.

이것은 전송 프로토콜이 아니라 해석 절차를 이름으로 삼는 URL 스킴입니다. 참조와 MIME 헤더를 어떻게 비교하는지를 말할 뿐, 수신자가 소켓을 열어야 한다고 말하지는 않습니다. 이 의미들을 혼동하면 자족적인 메시지가 불필요한 외부 요청으로 변하거나, 없는 로컬 파트가 마치 네트워크 장애처럼 보이게 만들 수 있습니다.

RFC 2392는 또한 대체 표현 예외를 보존했습니다. 하나의 메시지는 제한된 상황에서 동일한 Content-ID를 가진 여러 파트를 포함할 수 있습니다. URL이 어느 파트를 지칭하는지는 감싸는 엔티티의 규칙이 결정합니다. 따라서 전역적으로 고유한 레이블조차, 그것에 작동적 의미를 부여하는 로컬 구문 트리 없이는 해석될 수 없습니다.

위치는 별개 종류의 주장으로 남았다

집합 문서 작업은RFC 2557로 이어졌고, 이 규격은 1999년에 RFC 2110을 대체했습니다. Content-ID, Content-Location, 그리고 메시지의 경우 Message-ID를 서로 다른 유효한 레이블로 다루었습니다. Content-Location은 절대 URI나 상대 URI를 담을 수 있었지만, 그 URI가 모든 수신자에게 이용 가능해야 하는 것은 아니었습니다. 제한된 도메인 안의 자원을 이름지을 수도 있고, 허구일 수도 있었습니다.

위치 레이블을 검색 영수증으로 착각하는 경우에만 이것이 역설처럼 보입니다. 패키지된 메시지에서 Content-Location은 문서 참조를 내부 파트로 해석하는 데 도움을 줍니다. 수신자가 다시 가져올 수 있다고 약속하지 않으면서, 표현이 개념적으로 유래한 위치를 기술할 수 있습니다.

RFC 2557은 또 하나의 구분을 명시했습니다. MHTML 집합물의 URI는 그 루트의 URI가 아닙니다. 집합물을 검색하면 패키지가 반환됩니다. 루트 URI를 검색하면 루트만 반환될 수 있고, 클라이언트가 의존성을 독립적으로 가져오게 만들 수 있습니다. 두 작업은 시간이 지나면 서로 다른 스냅샷을 노출할 수도 있습니다.

Content-ID가 이 아키텍처의 중심에 앉은 것은 바로 주장하는 바가 적었기 때문입니다. 직렬화 순서, 외부 위치, 검색 시점이 주위에서 바뀌는 동안에도 내부 관계를 안정적으로 유지할 수 있었습니다. 그 가치는 하나의 계층을 좁게 이름지는 데서 왔습니다. 수신자는 여전히 메시지 문맥을 확립하고, 컨테이너를 파싱하고, 허용된 대안을 선택하고, 본문을 디코딩하고, 보안 정책을 적용하며, 렌더링 여부를 결정해야 했습니다.