Skip to content

Making simple web server that serving static files or excuting CGI

Notifications You must be signed in to change notification settings

dudcks0994/Webserv

Repository files navigation

Webserv

과제목표 : C++98을 이용하여 정적파일 서빙 및 CGI처리가 가능한 웹서버 구현

상세 구현 사항 및 제한사항은 여기

HTTP 리퀘스트 파싱

  • RFC 문서를 읽으면서 기본적인 HTTP 프로토콜에 대해 이해
  • 스타트라인/헤더/바디 각 부분을 파싱해서 정보를 저장
    • 모든 줄이 CR(Carrige return) + LF(Line feed) 로 끝나는지 확인
    • 스타트라인에 들어가야 하는 요소들 유효성 검사, 헤더 유효성 검사 및 중복검사
    • Method에 따라 body의 파싱여부 판단, Content-Encoding의 타입에 따라 chunked 고려
    • 버퍼크기를 1024로 해둠에 따라, 각 리퀘스트의 완성여부와 에러여부 저장

Multiplexing I/O

  • TCP 소켓을 이용하여 클라이언트와 HTTP 프로토콜을 이용해 소통하는데, 여러 클라이언트가 있을 수 있으므로 kqueue를 이용한 Multiplexing 방식으로 구현함
  • kevent 함수를 사용하여 이벤트가 발생해야만 루프를 돌게 해, Non-Blocking 방식으로 errno를 확인하지 않게끔 구현
  • 클라이언트의 연결요청과 리퀘스트, cgi 실행 및 읽기, 리스폰스 보내기 모두 kevent 반복문에서 처리됌
  • 리퀘스트가 chunked일 경우와 리퀘스트가 형식에 맞게 오다 멈출 경우, CGI 처리가 오래걸리거나 리스폰스 보낼때 시간이 오래걸리는 경우 등을 TIMER 이벤트로 kevent 리턴 시 처리 가능

CGI(php)

  • CGI(Common Gateway Interface)에 대한 기본적인 이해와 RFC문서를 통해 구현 필수조건 확인
  • 실행시간이 오래걸리거나 혹은 잘못된 CGI 프로그램으로 무한루프가 일어날 수 있으므로 kevent에 타이머이벤트를 등록
  • 리퀘스트 바디가 있다면 파이프를 통해 CGI프로그램에 전달하고, CGI프로그램의 실행결과를 파이프를 통해 읽어오는 방식으로 구현
  • 파이프의 버퍼사이즈 제한이 있으므로 Read/Write 이벤트를 모두 등록해 Non-Blocking 방식으로 처리
  • cgi실행 처리 확인을 위해 PID도 이벤트에 등록, 이때 한 CGI실행에 파이프 fd 2개와 PID 1개, 결과 string 총 4개가 연관되어 있으므로 STL 맵을 이용해 연결고리를 생성
  • 대용량 데이터의 송수신일 때 복사가 이뤄지면 서버의 속도저하가 일어나므로 최대한 레퍼런스 연산자를 사용하여 복사생성자 호출 방지 및 쓰기용 인덱스 변수 이용
  • 쿼리스트링 및 Method와 PATH_INFO 등 필요한 인자를 환경변수로 직접 만들어 execve 사용시 인자로 넣음
  • 실행 결과에서 리스폰스에 넣어야할 헤더가 있는 경우 파싱해서 헤더를 추가 혹은 변경
  • 프로세스 이벤트가 일어나면 어떠한 식으로든 종료가 된 것이므로 종료코드를 확인 후 Response를 만들고 WRITE 이벤트를 등록

배운 점

  • TCP/IP 소켓 통신에 대한 이해
    • 컴퓨터들끼리 네트워크상에서 소켓을 사용하여 통신하는 방법에 대한 이해
    • 시스템마다 바이트순서가 다른데, 네트워크 상에서는 모두 빅엔디안으로 쓰기에, 이를 바꿔주는 함수가 존재
    • seige를 사용하여 단시간에 많은 연결로 서버부하 테스트 진행시, 어느순간부터 모든연결이 안되는 현상이 발생
      • TCP 소켓 연결 종료시, 원래는 남아있던 데이터를 전송하는데 이로인해 소켓연결이 완전히 닫히지않는 문제가 발생하여 so_linger 구조체로 즉시 데이터를 버리게 처리
    • 테스트 후 껏다가 다시켰을때 같은 포트로 열면 bind error가 발생
      • 소켓의 연결종료를 하더라도, 서로 종료를 확인하고 주고받으며 만약 데이터를 다 보내지 못했을 경우 이를 마저 보내고 종료하도록 되어있음
      • 부하테스터기인 siege를 빠른속도로 실행시, siege에서 비정상 연결종료를 했을 때 아직 커널단에서 관리중인 포트가 있어서 테스터기가 중단됌(4way handshaking이 커널단에서 완전히 끝나지 않은상태)
      • 마찬가지로 서버도 위의 과정을 거쳐야 하므로 시간이 지나서 실행하지 않으면 해당 포트가 사용불가
      • reuseaddr 옵션을 사용해 close()호출 이후 커널단에서 관리중인 포트를 재사용가능하게 처리 / so_linger옵션을 사용하여 클라이언트와의 연결 종료시 즉시 데이터를 버리게끔 처리
  • HTTP 프로토콜에 대한 이해
    • RFC문서(https://datatracker.ietf.org/doc/html/rfc7230)를 통해 프로토콜 이해 및 문법 확인
    • 특정 브라우저로만 접속이 가능하다던가, 브라우저로만 다운로드가 가능하거나, 다운로드 가속기같이 분할 고속다운로드가 가능하거나 막는것이 어떻게 되어있을지 예상가능
    • 템플릿으로 테스트할 때, pending상태의 파일들일 자주 떴는데 Content-Length를 보내주지 않으면 브라우저가 해당 컨텐츠가 어디까지인지를 모름 -> 여러 헤더들이 하는 역할에 대해 이해
  • Multiplexing I/O 모델
    • 서버는 여러 클라이언트(소켓fd)와 소통해야하는데, 멀티프로세스나 멀티쓰레드 방식 사용시 부하가 크고 느리며 컨텍스트 스위칭 비용으로 인해 입출력을 묶어서 관리하는 멀티플렉싱 방식으로 구현
    • Non-Blocking fd를 사용하여 이벤트가 있을때에만 kevent가 리턴되어
  • CGI 지원
    • CGI RFC문서(https://datatracker.ietf.org/doc/html/rfc3875)를 통해 CGI프로그램의 실행방법과 환경변수에 대한 이해
    • 대용량 데이터를 CGI로 파이프를 통해 송신 및 수신하는 과정에서 Blocking/Non-Blocking 차이에 따라 파이프가 broken되거나 대기가 걸리는 문제가 생김
    • 파이프의 버퍼사이즈가 정해져있는데, CGI프로그램 전부가 입력을 전부 받고 출력을 전부 보내는것이 보장되어 있지 않아 생기는 문제로 CGI실행 시에 pid와 읽기용 파이프fd, 쓰기용 파이프fd 모두 이벤트에 등록해 쓰기와 읽기를 바로바로 하게 해 해결
  • 클라이언트 리퀘스트 파싱
    • 스타트라인과 헤더, 바디로 구성되어있고 각각은 CRLF, 헤더와 바디의 구분은 CRLF 두개로 구분되어있어서 CRLF 두개연속을 찾아서 리퀘스트의 구분 혹은 바디 구분이 가능하나 그렇게 하면, 만약 스타트라인-헤더까지의 길이가 한번 읽는 버퍼사이즈보다 클 경우 그 다음 데이터를 읽을때 다시 한번 처음부터 읽어야 하거나 애초에 잘못된 리퀘스트 구조일 경우 오버헤드 발생
    • 모든 라인의 구분이 CRLF이므로 CRLF를 기준으로 한줄씩 읽어서 파싱 및 저장하는 구조로 구현
  • 타임아웃 처리
    • 클라이언트 연결 후 데이터가 오지 않거나, 리퀘스트가 chunk방식 전송일 때 데이터가 오지 않거나, cgi실행이 오래걸릴 때를 대비해 각각의 경우에 모두 TIMER이벤트를 등록
    • 무한루프 CGI를 크롬에서 여러개 탭으로 실행 후, 한두개만 꺼도 나머지가 전부 hang걸리는 현상 -> 기존 코드는 리퀘스트 파싱 및 cgi실행 이후 같은 fd로부터 클라이언트의 write로 인해 read이벤트가 발생할 경우 타이머를 갱신시키는 방식이였는데 크롬은 일정시간 리스폰스가 오지 않을 경우 같은 내용으로 리퀘스트를 요청함
    • 타이머 갱신은 리퀘스트가 완성된 시점에서는 더이상 read를 하지도 않고 타이머이벤트를 새로 등록하지도 않게 하여 하나의 처리당 타이머가 하나가 되도록 수정
    • 보낸 리스폰스를 읽지 않는 클라이언트가 있다면 이는 결국 메모리 누수와 마찬가지이므로 리스폰스의 write이벤트도 타이머를 등록해서 처리해야 함

About

Making simple web server that serving static files or excuting CGI

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published