드디어 url이 왜 HTTP 로 시작하는지 이해할 때입니다.
요약 : 이 프로젝트에서 여러분은 스스로 HTTP 서버를 만들어야합니다. HTTP RFC 를 참고해서 구현해야하며 해당 서버를 실제 브라우저를 통해 테스트가 가능할 수 있어야 합니다. HTTP 는 인터넷에서 가장 많이 사용되는 프로토콜 중의 하나로서, 이 HTTP가 가진 신비로운 비밀을 알게 된다면 설령 여러분이 웹개발을 하지 않을 것이라 해도 유용할 것입니다.
Chapter 1 소개
HTTP(Hypertext Transfer Protocol) 는 배포, 협업, 하이퍼미디어 정보전달을 위한 어플리케이션 프로토콜(통신규약) 입니다. HTTP는 하이퍼텍스트 문서에 포함된 하이퍼링크를 통해 다른 문서에 쉽게 접근 할 수 있는 WWW(World Wide Web)을 위한 기본 데이터 통신입니다. 예를들면 우리는 웹브라우저 화면을 마우스 클릭이나 탭하는 것 만으로도 다른 정보로 쉽게 이동이 가능하죠. HTTP는 하이퍼텍스트와 월드와이드웹을 용이하게 사용하기 위해 개발되었습니다. 기본적인 웹브라우저의 기능은 웹페이지를 저장, 처리 그리고 클라이언트에게 전달하는 것입니다. 그리고 여기서 클라이언트와 서버사이의 정보교환은 바로 하이퍼텍스트 프로토콜(HTTP)의 역할입니다.
전달될 페이지로는 주로 HTML이 사용되는데, 이 안에는 기본적인 텍스트 외에도 이미지, CSS 그리고 스크립트를 포함할 수 있습니다.
트래픽이 많은 웹사이트의 경우 하나가 아닌 여러 개의 웹서버를 사용할 수도 있습니다.
사용자 에이전트(주로 웹 브라우저나 웹 크롤러에 해당)는 HTTP를 이용하여 구체적인 자료를 요청(request) 하는 것으로 통신을 시작합니다. 그럼 서버는 응답(response)이 가능한 경우 요청한 자료가 담긴 내용을 전달하거나 불가능한 경우 에러메세지를 전달합니다. 자료는 일반적으로 서버의 부차적인 저장소에 있는 실제파일이지만 반드시 꼭 그렇지만은 않고, 서버가 어떻게 구현되어있느냐에 따라 다릅니다.
HTTP 의 주요한 기능은 내용을 제공하는 것이지만, 클라이언트로 부터 정보를 받는 방법 역시도 전체적인 HTTP 구현에 포함됩니다. 이러한 HTTP의 특성은 파일 업로드는 물론이고, 양식(form) 제출에도 사용됩니다.
Chapter 2 Mandatory part
- 반드시 c++ 로 HTTP 서버를 구현해야 합니다.
- 서버는 반드시 rfc 7230 ~ 7535 (http 1.1) 를 조건적으로 준수해야하며, 헤더의 경우 아래의 것들만 구현해도 됩니다.
헤더 목록 생략...
- 만약 원한다면 모든 헤더를 구현해도 됩니다.
- nginx는 HTTP 1.1과 호환되며 헤더와 응답 동작을 비교하는 데 사용될 수 있습니다.
- 서버와 클라이언트 사이의 IO 통신은 반드시 non-blocking 이어야 하며 1개의 select 를 사용해야합니다. (listen 도 포함)
- Select 는 반드시 read 그리고 write 를 동시에 확인해야 합니다.
- 여러분의 서버는 정지되면 안되고 클라이언트는 만약 필요하다면 적절하게 연결을 끊어야 합니다.
- select 를 지나지 않고 read 와 write 를 쓰면 안됩니다.
- read 와 write 이후에 errno 의 값을 확인하는 건 엄격하게 금지됩니다.
- 서버로 온 request 가 영원히 머물러 있어서는 안 됩니다.
- 만약 에러 페이지가 제공되지 않으면 여러분의 서버는 기본 에러 페이지를 사용해야합니다.
- 여러분의 프로그램은 누수가 없고 충돌이 일어나면 안 됩니다. (모든 초기화가 완료된 경우 메모리가 부족하더라도)
- CGI(php, perl, ruby 등등) 를 제외하고는 fork 를 사용할 수 없습니다.
- "iostream" "string" "vector" "list" "queue" "stack" "map" "algorithm" 을 include 하고 그 안에 있는 모든 것들을 사용할 수 있습니다.
- 여러분의 프로그램은 반드시 매개변수 또는 기본 경로에 있는 설정파일을 사용해야합니다.
퍼랭이
macOS 가 다른 unix OS 와 다르게 구현이 되었기 따문에 저희는 여러분이 fcntl 을 사용할 수 있도록 하겠습니다. 여러분은 반드시 다른 OS 와 비슷한 결과를 갖기 위해서 non-blocking FD 를 사용해야 합니다.
빨갱이
non-blocking FD 를 사용하기 때문에 여러분의 서버가 select 없이 read/recv 또는 write/send 만으로 블로킹이 되지 않을 지도 모릅니다.
다시 한번 말하지만, read/recv 또는 write/send 를 어떤 FD 던간에 select 없이 사용한다면 여러분은 0점을 맞고 그 즉시 평가는 끝나게 될 것입니다.
빨갱이
여러분은 fcntl 을 다음과 같은 형태로만 사용할 수 있습니다 : fcntl(fd, F_SETFL, O_NONBLOCK); 다른 flag 들은 금지입니다.
- 설정파일에서는 다음과 같은 것들이 가능해야합니다.
노랭이
nginx의 "server" 부분을 참고해서 여러분 스스로 설정파일을 만들어야 합니다.
- 각각의 "server" 에 port 와 host 선택
- server_name 을 설정 또는 비설정
- 첫 번째 서버의 host:port 는 해당 host:post 의 기본 설정이 됩니다. (이는 다른 서버에 속하지 않는 request 를 응답하는데 사용됩니다.)
- 기본 에러페이지 설정
- 클라이언트 body size 제한
- 하나 또는 여러 개의 다음과 같은 규칙/설정을 라우트에 적용하기 (라우트에는 정규표현식을 쓰지 않을겁니다.)
- 해당 라우트가 요청 받을 수 있는 HTTP 메소드 목록 정의
- 파일이 검색될 폴더나 파일을 정의 (예를들어 /tmp/www 가 url /kapouet 의 루트로 설정되었다면, url /kapouet/pouic/toto/pouet 은 /tmp/www/pouic/toto/pouet 이 됩니다.)
- directory listing 기능 on 또는 off
- request 가 폴더인 경우 응답할 기본 파일 설정
- CGI가 실행될 특정 파일 확장자 설정 (예 .php)
- CGI가 어떻게 작동되는지 궁금하다면 ? https://en.wikipedia.org/wiki/Common_Gateway_Interface
- 여러분은 CGI 를 직접 호출하지 않기 때문에, 전체 경로를 PATH_INFO 로 사용합니다.
- chunked request 의 경우, 여러분의 서버는 해당 요청을 unchunk 해야할 필요가 있고, CGI는 body 끝에 EOF 를 예상하고 기다린다는 것을 기억하세요.
- CGI의 아웃풋도 같은 방식입니다. 만약 content_length 가 CGI로 부터 리턴되었다면, EOF는 리턴된 데이터의 끝을 의미합니다.
- 여러분의 프로그램은 반드시 다음과 같은 Meta-Variable들을 설정해야합니다.
AUTH_TYPE CONTENT_LENGTH CONTENT_TYPE ... 생략
* 여러분의 프로그램은 요청된 파일을 cgi 의 첫번째 매개변수로 호출해야합니다.
* cgi 는 상대경로를 통한 접근을 위해 반드시 올바른 디렉토리에서 수행되어야 합니다.
* 여러분의 서버는 php-cgi와 작동이 가능해야합니다.
* 라우트를 업로드가 가능하도록 만들고 어디에 저장될지를 설정하세요.
여러분은 평가를 위해 몇몇 설정파일들을 제공해야만 합니다.
퍼랭이
여러분이 어떤 동작에 질문이 생기면 nginx 와 비교를 해봐야 합니다.
예를들면 server_name 이 nginx 에서 어떻게 동작하는지 확인하는 것 처럼...
빨갱이
프로젝트를 시작하기 전에 RFC 를 읽고 telnet과 nginx로 몇가지 테스트를 해보길 권합니다.
빨갱이
우리는 여러분에게 작은 테스터를 제공했습니다. 만약 이 테스터를 통과하지 못하면 평가를 시도하지 마세요.
빨갱이
가장 중요한건 지속력입니다. 여러분의 서버는 절대 죽으면 안됩니다. 이를 위해 서버 부하 테스트가 있을 겁니다.
빨갱이
한 가지 프로그램으로만 테스트하지 말고 python, golang, javascript, rails 등 과 같이 여러분이 직접 손쉽게 작성하고 사용할 수 있는 언어로 테스트를 만드세요. C나 C++로 테스트를 만들 수도 있습니다.
Bonus part
- 만약 Mandatory part 가 완벽하지 않다면 보너스는 꿈도 꾸지 마세요.
- 모든 보너스를 다 할 필요는 없습니다.
- 터미널을 통해 loadable/unloadable 한 플러그인을 만드세요. 다른 압축 시스템이나 charset 컨버터 그리고 기타 등등... 과 같은 것들을 말이에요 (구현한 만큼 추가 보너스있음).
- 여러분의 프로그램은 다음과 같이 정의된 workers 를 가질 수 있습니다.
- 스레드나 프로세스로 된 worker (이를 위해 fork를 사용)
- worker는 각 클라이언트를 위해 생성되지 않아야 하며 반드시 무한한 수의 request 를 처리할 수 있어야 합니다.
- 복수의 worker 들은 의무사항은 아닙니다.
- 여러분은 fork, wait, waitpid, wait3, wait4, dup, dup2, pipe or pthread_create, pthread_detach, pthread_join, pthread_mutex_init, pthread_mutex_destroy, pthread_mutex_lock, pthread_mutex_unlock 를 사용할 수 있습니다.
- 설정 파일에 원하는 만큼 다음의 기능을 추가하세요
- worker 의 개수 설정 (만약 복수의 worker 를 구현한 경우)
- 플러그인 설정 (위에서 본 플러그인과 함께 작동)
- 정규표현식과 함께 동작하는 라우트 만들기
- 다른 http/https 서버를 중개하는 프록시 설정
- php 나 다른 언어를 위한 내부 모듈 사용. 이말은 즉, 해당 언어로 페이지를 생성하기 위해 외부 실행 파일을 호출하지 않음을 의미합니다. (구현한 만큼 추가 보너스 있음)