요약

  • RFC 2774는 필수 요청에M-접두사를 붙여, 확장을 인지하지 못한 서버가 클라이언트가 필수라고 여긴 의미론을 조용히 무시하는 대신 낯선 메서드를 거부하도록 했다.
  • 확장을 지원하는 수신자는 충족되지 않은 확장 정책에 관한 정보와 함께 510을 반환하거나, 모든 필수 선언을 이해하고 준수했음을 확인했다. 이 프레임워크는 훗날 Historic이 되었지만, 명시적 HTTP 확장 레지스트리는 남았다.

성공 응답이 실패를 감출 수 있었다

클라이언트가 법적 또는 운영상 의미가 새 확장에 의존하는PUT을 보낸다고 하자. 업그레이드된 서버는 선언을 읽고 추가 규칙을 적용해 자원을 저장한다. 구버전 서버는 익숙한 메서드를 보고 낯선 필드를 무시한 채 같은 바이트를 그 규칙 없이 저장한다. 두 경우 모두200 OK를 반환할 수 있다. 전송은 양쪽 모두 성공했다. 그러나 발신자가 의도한 의미대로 처리된 요청은 하나뿐이다.

이것은 위험한 종류의 호환성이다. 아무것도 중단되지 않지만, 필수적인 의미론적 조건이 사라진다. 알 수 없는 필드에 대한 통상적인 관용은, 그 알 수 없는 기능이 필수였을 때 조용한 다운그레이드가 된다.

2000년 2월 실험적으로 발표된 RFC 2774는 그 모호함을 불가능하게 만들려 했다. 가장 눈에 띄는 조치는 상태 코드 510이 아니라 변경된 메서드 토큰이었다. 필수GET은M-GET이 되고, 필수PUT은M-PUT이 되었다. 프레임워크를 구현하지 않은 수신자는 알 수 없는 메서드를 보고 거부하게 된다. 더 이상 기본 작업을 수행한 뒤 우연히 그럴듯한 성공을 반환할 수 없었다.

안전 기능으로서의 의도적 비호환성

프로토콜 설계자들은 대개 하위 호환성을 기린다. RFC 2774는 하나의 경계를 인식했다. 호환성이 “이 요구사항을 이해하지 못한다”를 “완료했다”로 바꿔버릴 때, 호환성은 해롭다.M-접두사는 무지를 눈에 보이는 비호환으로 바꿨다.

규격을 따르는 수신자는 정해진 절차에 들어간 뒤에야 접두사를 제거했다. 모든 필수 선언을 식별하고, 해당 메시지에 적용되는 각 확장이 지원되는지 판단하고, 충족할 수 없는 요구가 있으면 510을 반환했다. 그런 다음에야 확장과 기본 HTTP 메서드의 의미론을 처리할 수 있었다. 이 문서는 모든 필수 선언을 이해하고 준수하지 않는 한 서버가 이행을 주장하는 것을 금지했다.

이는 기능 탐색보다 강력했다. 발신자는 서버가 어떤 기능을 일반적으로 아는지 묻는 데 그치지 않았다. 하나의 메시지에 조건을 붙이고, 최종 수신자가 그 실행에서 그 조건을 지키도록 요구했다.

네 가지 선언 경로

이 프레임워크는 확장을 두 축으로 분류했다. 선언은 필수일 수도, 선택일 수도 있었다. 또한 종단 간(end-to-end)으로 원 서버를 목적지로 할 수도 있고, 홉 간(hop-by-hop)으로 프록시처럼 다음 연결 참여자를 목적지로 할 수도 있었다. 그 결과 네 개의 필드가 나왔다.Man,Opt,C-Man,C-Opt다.

이 행렬은 권한을 명시적으로 만들었다. 중개자는 단지 필드를 읽을 수 있다는 이유만으로 종단 간 선언을 소비할 권한이 없었다. 반대로 홉 간 선언은 원 서버가 그것을 소유한 것처럼 가장하지 않고 다음 참여자에 대한 요구를 표현할 수 있었다. HTTP/1.1에서 연결 범위 필드와 그에 딸린 확장 데이터는Connection에 명시되어야 했고, 이로써 종단 간 메타데이터로 전달되는 것이 막혔다.

각 확장은 전 세계적으로 고유한 URI로 식별되었고, 더 좁은 규칙 아래에서는 표준이 정의한 필드 이름으로도 식별되었다. 선언은16같은 숫자 접두사를 할당할 수도 있었다. 그러면16-으로 시작하는 필드가 그 확장 인스턴스에 속했다. 숫자 네임스페이스는 충돌을 피하고, 동일한 확장이 HTTP 필드 이름 공간 전체를 차지하지 않으면서 여러 번 나타날 수 있게 했다.

이 기제는 확장이 무엇을 의미하는지 정의하지 않았다. 누가 정의했는지, 어디에 적용되는지, 의무인지, 어떤 필드가 그에 속하는지를 전달하려 했다.

510은 협상 실패였지, 일반적인 서버 오류가 아니었다

수신자가 필수 선언을 충족할 수 없다면 RFC 2774는510 Not Extended를 요구했다. 7절은 이 조건을 자원의 접근 정책을 충족하지 못한 것으로 설명했다. 응답은 클라이언트가 성공할 수 있는 확장 요청을 발행하기에 충분한 정보를 포함해야 했다.

이 표현은 중요하다. 510은 HTTP 자체가 고장났거나 자원이 존재하지 않는다는 뜻이 아니었다. 이 시도된 작업에 자원이 요구하는 확장 의미론이 빠져 있었다는 뜻이었다. 응답이 누락된 선언을 알려주고 클라이언트가 이를 제공할 수 있다면, 요청을 수정해 다시 보낼 수 있었다. 그렇지 않으면 응답 본문은 사용자나 운영자를 위한 진단 정보 역할을 했다.

이 상태 코드는 경계 사례도 보호했다. 필수 선언이 없는M-메서드는 내부적으로 모순이었고 510을 받아야 했다. 발신자는 무엇이 필수인지 밝히지 않으면서 필수 처리를 요구할 수 없었다.

이행 증명에는 자체 필드가 있었다

거짓 성공을 피하려면 특별한 오류만으로는 부족했다. 성공한 수신자는 이행을 알려야 했다.Ext는 모든 종단 간 필수 선언을 이해하고 준수했음을 확인했고,C-Ext는 홉 간 선언에 대해 같은 일을 했다. 이 필드들은 애플리케이션 데이터를 담지 않았다. 그 가치는 해당 확장 계약이 실행되었다는 진술 자체였다.

그 진술에도 한계가 있었다. 확장이 잘 설계되었는지, 결과 데이터가 올바른지, 원격 당사자가 신뢰할 만한지는 증명하지 못했다. 이는 의미론적 확인을, 상태 코드만으로는 추가 규칙이 적용되었는지 보여줄 수 없는 보통의 응답과 구분했다.

프록시와 캐시가 이 행렬을 비싸게 만들었다

이 프레임워크의 세부 내용은 그것이 견뎌야 했던 환경을 드러낸다. 종단 간 선언은 확장을 구현하지 않은 프록시를 통과할 수 있었다. 홉 간 선언은 올바른 연결에서 멈춰야 했다. HTTP/1.0 중개자는 최신 필드별 캐시 제어를 이해하지 못할 수 있었다. 그렇지 않으면 캐시가 한 확장 선언 아래 생성된 응답을 그 선언이 없는 요청에 재사용할 수 있었다.

따라서 RFC 2774는 이행된 종단 간 요청에Cache-Control: no-cache="Ext"를 짝지었다. HTTP/1.0 프록시 호환성을 위해 이미 만료된Expires값도 규정했다. 접두사가 붙은 확장 데이터에 따라 달라지는 응답은Vary에 특정 접두사 필드와 해당 선언 필드를 모두 명시해야 했다.

이것들은 장식적인 복잡성이 아니었다. 각 규칙은 의미가 제거되거나, 잘못 배치되거나, 재생될 수 있는 경로를 닫았다. 그러나 닫힌 모든 경로는 클라이언트, 원 서버, 프록시, 캐시에 또 하나의 의무를 추가했다. 이 실험은 하나의 범용 프레임워크가 그 모든 역할을 동시에 조정하게 하려 했다.

실험은 답을 보존하지 않고 질문을 보존할 수 있다

RFC 2774는 처음부터 특이한 경고를 담고 있었다. IESG 주석은 이 제안이 원래 Proposed Standard 지위를 추구했지만, 엇갈린 평가와 커뮤니티 합의에 대한 불확실성 때문에 Experimental로 출판되었다고 밝혔다. 이 주석은 설계가 기술적으로 결함이 있다고 선언하지 않았다. 더 많은 연구와 논의가 필요하며, 이 기제를 보편적 청사진으로 취급하지 말라고 경고했다.

2021년 IETF는 RFC 2774와 다른 여러 HTTP 실험을 Historic으로 옮기는 것을 승인했다. 상태 변경 기록은 실험이 종료되었고 광범위한 사용의 증거가 없다고 밝힌다. IANA는 이제 510을Not Extended (OBSOLETED)로 표시하고,Man,Opt,C-Man,C-Opt,Ext,C-Ext를 폐기된 것으로 표시한다.

이 기록은 좁은 결론을 뒷받침한다. 이 범용 프레임워크는 현재의, 광범위한 증거가 있는 HTTP 기제가 되지 못했다. 그것은 아무도 구현하지 않았다는 것을 증명하지 않고, 그 운명의 한 가지 원인을 특정하지 않으며, 모든 설계 우려를 실수로 바꾸지도 않는다.

HTTP가 남긴 것

현재의 HTTP 의미론도 여전히 진화를 전제한다. RFC 9110은 메서드, 상태 코드, 필드 이름, 인증 체계, 캐시 지시문에 대한 지속적인 확장 지점을 명시한다. 이 네임스페이스는 명시적 레지스트리와 검토 정책을 사용한다. 모든 요청을 RFC 2774의 선언 행렬로 감싸지 않고도 새로운 의미론을 할당하고, 문서화하고, 수명 주기 상태를 부여할 수 있다.

살아남은 교훈은 프레임워크보다 작다. 프로토콜은 선택적 새로움과, 그것이 없으면 작업이 무효가 되는 의미론을 구별할 방법이 필요하다. 충돌 저항적인 이름, 명확한 범위, 중개자 규칙, 공개 수명 주기 기록이 필요하다. 무엇보다 성공한 교환을 공유된 이해와 혼동해서는 안 된다.

HTTP 510은 한때 그 구별이 실패하는 지점을 차지하고 있었다. 그것이 폐기된 것은 역사의 일부이지만, 그것이 지목한 문제도 역사의 일부다. 가장 위험한 오해는 성공을 반환하는 오해다.

출처