- one processor, one thread
- I/O multiplexing by kqueue
- using CGI script by Python to make Dynamic Web Page
- HTTP 1.1 protocol: GET method, POST method, DELETE method, redirect, connection: keep-alive, connectoin: close, transfer-encoding: chunked and etc
- I/O Multiplexing을 통해 여러 소켓과 파일 fd(file descriptor)를 동시에 관리할 수 있습니다.
- kqueue()는 이벤트 감지 시에, 내부적으로 O(1)의 시간복잡도로 동작하여 select()에 비해 성능이 좋아, kqueue()를 사용했습니다.
- 단일 프로세스에서 여러 I/O 작업을 동시에 처리할 수 있어, 리소스를 효율적으로 사용할 수 있습니다.
- non-blocking이므로 I/O 작업 중 발생하는 대기시간을 최소화하여 응답속도를 높일 수 있습니다.
- HTTP 1.1 규약에 따라 keep-alive를 지원하기 위해 kqueue에 Timer 이벤트를 등록하여 일정 시간 이상 client의 요청이 오지 않았을 때만 연결을 끊습니다.
- HTTP 요청 헤더의 connection: close인 경우에는 Timer 이벤트를 등록하지 않고 HTTP 응답을 보내고 곧바로 연결을 끊습니다.
- 클라이언트 소켓으로부터 HTTP 요청이 들어온 경우,
HttpRequestHandler::handle함수에서 처리합니다. - 소켓으로부터 요청을 읽어들여 각 소켓 당 마련된 버퍼에 저장하고, keep-alive에 의해 버퍼에 여러 개의 요청이 쌓여 있을 수 있음을 전제하여 처리합니다.
HttpRequestFactory::create함수에서 하나의 HTTP 요청에 대응하는 하나의 HttpRequest 객체를 생성합니다.- 요청 메시지를 파싱하고, chunked 요청인지 또는 일반 요청인지 파악하여 서로 다른 처리 로직이 구성됩니다. HttpRequest 객체를 만들어 바로 반환하는 일반 요청과 달리, chunked 요청은 본문이 여러 번에 걸쳐 들어올 수 있음을 고려합니다.
- 요청 메시지를 파싱하는 도중, 요청이 유효하지 않음을 발견하면 예외를 던져 클라이언트에게 오류 응답을 합니다.
- 만들어진 유효한 HttpRequest 객체는 Send 쪽으로 전달됩니다.
- 전달 받은 request객체와 설정파일(conf)를 통해 client의 요청에 맞는 자원을 검색 및 반환합니다.
- 요청한 파일이 정적 파일인 경우, response body에 담아 반환하고 동적 파일인 경우, 적합한 CGI script를 실행하여 결과를 반환합니다.
- I/O multiplexing을 위해 socket fd와 fd에 kqueue에 등록하고, 이벤트가 발생했을 때 non-blocking으로 I/O 작업을 진행합니다.
동적 파일을 생성하거나, 요청 데이터를 서버에 전달하려고 할 때 CGI script를 사용합니다. CGI 규약을 지켜 작성된 파일로 이번 프로젝트에서는 query string을 포함한 GET 요청, POST 요청, DELETE 요청을 처리하기 위한 용도로 작성되었습니다.
make 명령어를 통해 makefile을 실행하여 C, C++ 소스코드를 컴파일합니다.
make
GET, POST, DELETE, Redirect, 상태 코드, HTTP KEEP-ALIVE 등을 테스트 할 수 있습니다.
터미널을 통해 웹서버를 실행합니다.
./webserv ./server/config/test.conf
웹서버를 실행한 후에 tester 프로그램을 실행하여 웹서버에게 Request를 보내고 Response를 받습니다.
./tester http://localhost:80
siege -b를 통해 웹서버의 부하 테스트를 진행합니다.
터미널을 통해 웹서버를 실행합니다.
./webserv ./server/config/test.conf
웹서버를 실행한 후에 siege -b을 통해 부하 테스트를 진행합니다.
siege -b http://localhost
다음은 C^로 부하 테스트를 종료했을 때의 결과 사진입니다.
터미널을 통해 웹서버 실행합니다.
./webserv
Chrome 주소창에 주소 입력하여 static/html/upload.html과 favicon.ico를 응답으로 보냅니다.
localhost:80/upload
다음은 localhost:80/upload에 접속했을 때, 서빙된 정적 파일입니다.
./server/config/default.conf에 정의된 request body의 최대 크기를 초과하지 않는 파일을 웹서버로 전송합니다. CGI script를 통해 웹서버에 업로드 됩니다.
다음은 업로드 된 파일을 GET요청으로 확인한 결과입니다.