티스토리 뷰
WebDAV
WebDAV는 HTTP 1.1 프로토콜의 확장 프로토콜이다.
DAV는 Distributed Authoring and Versiong의 약자로, HTTP보다 세부적인 웹 기반의 자원 관리와 관련된 표준이다.
아래의 예시처럼 HTTP에서는 볼 수 없는 특별한 메서드들이 존재한다.
- LOCK / UNLOCK: 자원에 대한 락 취득 / 해제
- MKCOL: 디렉터리 생성
- MOVE / COPY: 자원 이동 / 복사
- PROPFIND / PROPPATCH: 자원에 정의된 프로퍼티 조회 / 수정
WebDAV의 장점
- HTTP 1.1과 호환되므로 익숙한 HTTP 관련 구현 기술들을 그대로 사용 가능
- 보통 구현 기술들이 웹 서버와 같은 포트(80, 443)를 사용하여 웹 서버에 적용한 보안 등의 인프라를 그대로 적용 가능
- 특정 자원에 대한 잠금이 가능하여 여러 사용자에 대한 동시 접근 관리 가능
익숙한 HTTP로 서버 자원을 세밀하게 관리하는 게 목적에 맞게 사용이 간단하다.
예를 들어 서버에서 자원의 위치를 변경하는 MOVE 메서드는 curl 명령에 단순히 HTTP Method만 수정하고 요청하면 된다.
# /old/file.txt를 /new/file.txt로 옮기는 예시
curl -X MOVE --header "Destination: https://www.test.com/new/file.txt" https://www.test.com/old/file.txt
구현 기술
Microsoft Office나 오픈소스인 Libere Office 등 문서에 대한 동시 편집 기능이 필요한 기술에 기능이 구현되어 있으며, Apache Web Server, NGINX나 시놀로지 NAS 등 웹 요청을 통해 파일을 관리하는 기술들에도 구현이 존재한다.
NGINX의 ngx_http_dav_module
이 글의 목적인 NGINX에서의 WebDAV 관련 기능을 확인해보자.
NGINX 공식 이미지에는 이미 Web DAV 모듈이 존재
글 작성 시점의 NGINX 최신 안정화 버전인 1.26.2에는 이미 Web DAV 구현 모듈인 ngx_http_dav_module이 포함되어 있다.
적절히 NGINX 설정 파일을 활성화하기만 하면 WebDAV 기능을 사용할 수 있다.
만약 공식 이미지를 통한 컨테이너가 아닌 직접 바이너리를 설치하는 경우, 바이너리에 ngx_http_dav_module이 포함되었는지 확인해야 하며 없다면 바이너리를 직접 빌드해야 한다.
사용 방법
예시로, 설정 파일인 /etc/nginx/nginx.conf 또는 /etc/nginx/conf.d/*. conf의 server 블록을 아래와 같이 정의해야 한다.
server {
listen 80;
listen [::]:80;
server_name localhost;
location ~ "/storage/([0-9a-zA-Z-.]*)$" {
dav_methods PUT DELETE MKCOL COPY MOVE;
client_body_temp_path /storage/tmp/;
alias /local/$1;
create_full_put_path on;
dav_access group:rw all:r;
}
}
설정에 대한 설명은 아래와 같다
- location: 정규식을 사용하여 HTTP URL이 /storage 하위인 경우 매칭
- dav_methods: WebDAV의 메서드 중 허용할 메서드를 선언. (default: off => 모듈이 내장되어 있으나 기본 미사용되는 이유)
- client_body_temp_path: 전송 중 임시 파일이 잔류할 위치. 이 위치에 임시 파일이 생성된 이후 옮기는 방식으로 동작.
- alias: 실제 자원이 관리될 로컬 파일시스템 경로로 치환. URL이 /storage/text.txt 라면 바디의 내용이 /local/text.txt에 저장됨
- create_full_put_path: URL과 동일한 폴더 구조를 자동 생성할지 여부. (default: off)
- dav_access: 자원 생성 시 초기 부여되는 파일 권한. 위의 경우 그룹 권한으로는 읽기 / 쓰기, 전체로는 읽기 권한 부여
위의 설정으로 띄운 NGINX에 curl을 사용해 아래처럼 요청을 보내면 /local 하위에 123이란 내용의 text.txt가 생성된다.
curl -X PUT -d "123\n" http://localhost/storage/text.txt
유의사항
1. PUT으로 파일 업로드 시 Content-Type을 Plain Text로 지정해야 한다.
특별한 웹앱 서버처럼 동작하는 방식이 아니다 보니 Content-Type을 다르게 지정하는 경우 정상 저장 응답이 오나 실제 저장된 파일에 불필요한 데이터가 추가되는 경우가 존재했다.
일반적인 웹앱처럼 multipart/form-data로 하나의 HTTP 요청으로 여러 파일들을 한 번에 저장하는 동작 등이 불가능한 것도 단점.
2. 가장 눈여겨보았던 LOCK 관련 메서드나 자원의 프로퍼티 관리 관련 메서드는 지원하지 않는다.
WebDAV 프로토콜의 DA(Distributed Authoring)을 위한 핵심 기능이라 생각해서 아쉬움에 찾아보니
애초에 WebDAV 표준인 RFC 2518, 4918에서 LOCK 등 일부 메서드에 대한 지원까지는 강제하지 않고 있었다.
NGINX는 많은 사용자에 대한 빠른 정적 콘텐츠 서빙을 목표로 하는데, 스펙에 맞게 파일 별 S락, X락이나 자원의 프로퍼티들을 관리하려면 이 모듈을 위한 영속성 데이터를 관리해야 하므로 지원 범위를 제한한 것으로 보인다.
참고로 Apache의 WebDAV 모듈은 Lock과 관련한 고급 기능도 제공하는데, 이 기능을 위해 간단한 key-value 기반의 파일 DB(SDBM)를 설정해야 한다. 혹여 제대로 쓰려면 Apache 한계와 SDBM 관련 모듈을 원하는 DB로 커스텀할 수 있는지 등을 모두 고려해야 할 듯.
NGINX 쪽에서는 비공식 모듈인 nginx-dav-ext-module에서 프로퍼티, Lock 관련 기능을 지원하긴 한다.
단순히 리스트로 정보를 관리해 락 점유 여부를 확인할 때 O(n)이 소요된다 하니.. 조금이라도 규모 있는 환경에서는 쓰면 안 되겠다.
https://github.com/arut/nginx-dav-ext-module
아쉽게도 내장된 WebDAV 모듈은 이미 NGINX로 정적 파일 서빙을 하던 서버에 설정만 조금 바꿔서 정말 간단한 업로드 기능을 구현하는 정도로밖에 못 쓸 듯 하다.
결국 PUT 동작 방식으로 인해 파일 덮어쓰는 것을 방지하는 등의 로직을 커스텀하거나, Lock 기능이 본격적으로 필요하다면 별도의 솔루션 사용이나 웹앱 개발이 불가피해 보인다.
조금 더 찾아보고자 한다면 아래의 WebDAV 구현체 소개를 모아둔 프로젝트가 있으니 참고하면 좋다.
https://github.com/fstanis/awesome-webdav?tab=readme-ov-file
Reference
https://www.ietf.org/rfc/rfc2518.txt?number=2518
https://datatracker.ietf.org/doc/html/rfc4918
https://nginx.org/en/docs/http/ngx_http_dav_module.html
'Web' 카테고리의 다른 글
[Web] PRG 패턴 (Post-Redirect-Get) (0) | 2022.10.05 |
---|
- Total
- Today
- Yesterday
- GitHub Discussion 템플릿
- RandomPort
- stubbing
- 스프링
- 람다식
- Jenkins 예약 배포
- 우테코
- GitHub Discussion Template
- invokedynamic
- Fromtail
- java switch case
- Java
- logback-spring.xml
- springboottest
- Payload 암호화
- 생성자 주입
- Spring 테스트
- JPA JSON
- JPA
- Spring Boot Monitoring
- MySQL
- 자바
- 함수형 인터페이스
- 우테코 5기
- multiplebagsfetchexception
- GitHub Discussion
- 우테코 프리코스
- Spring
- 의존성 주입
- MySQL 이벤트 스케줄
일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
1 | ||||||
2 | 3 | 4 | 5 | 6 | 7 | 8 |
9 | 10 | 11 | 12 | 13 | 14 | 15 |
16 | 17 | 18 | 19 | 20 | 21 | 22 |
23 | 24 | 25 | 26 | 27 | 28 |