[WebProxy-Lab] proxy 서버 구현하기 Part.1 - 요구사항 확인 및 설계

크래프톤 정글 8주 차 CSAPP 11장의 웹서버 구현을 진행했다. 그리고 소형 웹서버를 기반으로 프록시 서버를 구현해야 한다. CSAPP 11 장의 내용은 이전 포스트 들을 확인할 수 있다.

2025.05.03 - [크래프톤 정글 (컴퓨터 시스템: CSAPP)/11장 네트워크 프로그래밍] - 컴퓨터 시스템 : CSAPP 11장 정리 - 11.6 종합설계 :소형 웹 서버 Part.1

 

컴퓨터 시스템 : CSAPP 11장 정리 - 11.6 종합설계 :소형 웹 서버 Part.1

11.6절 Putting It Together: The Tiny Web Server이 절에서는 지금까지 배운 내용을 종합하여 작동 가능한 소형 웹 서버 Tiny를 구현한다. 이 서버는 다음을 처리할 수 있다:정적 콘텐츠 (HTML, 이미지 등)동적

www.gowoong.com

2025.05.03 - [크래프톤 정글 (컴퓨터 시스템: CSAPP)/11장 네트워크 프로그래밍] - 컴퓨터 시스템 : CSAPP 11장 정리 - 11.6 종합설계 :소형 웹 서버 Part.2

 

컴퓨터 시스템 : CSAPP 11장 정리 - 11.6 종합설계 :소형 웹 서버 Part.2

지난 포스팅에서 11.6장 Tiny Web Server의 main()과 doit() 함수에 대해 알아봤다.2025.05.03 - [크래프톤 정글 (컴퓨터 시스템: CSAPP)/11장 네트워크 프로그래밍] - 컴퓨터 시스템 : CSAPP 11장 정리 - 11.6 종합설

www.gowoong.com

우선 proxylab.pdf 문서를 확인해 필수적으로 구현해야 하는 내용 놓쳐서는 안 되는 지시사항을 확인하겠다. 


반드시 구현해야 할 주요 기능

1. 기본 동작: Sequential Proxy (Part I)

  • HTTP/1.0 GET 요청만 지원 (POST 등은 선택 사항)
  • 브라우저의 요청을 받아서 서버에 전송하고, 응답을 브라우저로 전달하는 프록시 구현
  • 요청 파싱 시:
    • Host, path 등을 추출하여
    • 요청을 GET /path HTTP/1.0 형식으로 변환 후 서버에 전달
  • 반드시 \r\n 줄 바꿈, 마지막 빈 줄 등 HTTP 형식을 준수해야 함

2. 헤더 처리 (4.2절)

  • 다음 헤더는 무조건 포함해서 서버로 전달해야 함:
    • Host: ...
    • User-Agent: Mozilla/5.0 (X11; Linux x86_64; rv:10.0.3)...
    • Connection: close
    • Proxy-Connection: close
  • 브라우저가 보낸 기타 헤더는 그대로 전달

3. 포트 처리

  • proxy 실행 시 포트 번호를 명령줄 인자로 받음
    예: ./proxy 15213
  • URL에 포트가 있을 경우(http://host:8080/...) 해당 포트로 접속해야 함

4. 동시성 처리 (Part II)

  • 여러 클라이언트 요청을 동시에 처리하도록 구현해야 함
  • pthread_create로 각 요청마다 스레드 생성, detached 모드로 실행
  • 스레드 안전한 함수(open_clientfd, open_listenfd 등) 사용

5. 캐시 기능 (Part III)

  • 프록시에서 자주 요청되는 객체를 메모리에 캐싱
  • 다음 제한 조건을 반드시 만족해야 함:
    • 총 캐시 크기 ≤ 1MB (MAX_CACHE_SIZE)
    • 개별 객체 크기 ≤ 100KB (MAX_OBJECT_SIZE)
  • 객체가 최대 크기를 넘으면 캐시 하지 않음
  • 캐시 교체 정책은 LRU(최근 사용 안 한 객체 제거) 유사 정책 사용
  • 캐시 접근은 스레드 안전해야 함:
    • 여러 읽기 스레드는 동시에 접근 가능
    • 쓰기 중에는 읽기/쓰기 모두 차단
    • 단순한 mutex 하나로 전부 막는 것은 허용되지 않음

절대 놓치지 말아야 할 주의사항

 

  • HTTP/1.1 요청 → HTTP/1.0 요청으로 변환해서 서버로 보낼 것
  • 멀티라인 헤더는 처리하지 않아도 되나, 잘못된 요청에도 crash 없이 동작해야 함
  • SIGPIPE 무시: write 중 연결 종료 시 오류처리 (EPIPE, ECONNRESET) 필요
  • 바이너리 데이터 처리 가능하도록 구현 (텍스트 외 이미지 등 포함)
  • driver.sh 실행해서 autograder 점수 확인:
    • Correctness: 40점
    • Concurrency: 15점
    • Caching: 15점

프록시 서버 설계

구현을 진행하기 앞서 먼저 가장 큰 틀에서 프록시 서버를 어떻게 구현할지에 대한 정리를 하려고 한다.

1. 포워드 프록시(Forward Proxy)

우리가 구현해야 할 프록시 서버는 포워드 프록시이다. 평소 리버스 프록시를 주로 사용하던 나로서는 생소한 개념이었다. 

구분 포워드 프록시 리버스 프록시
위치 클라이언트 앞 서버 앞
목적 클라이언트 보호, 접근제어, 익명성 서버 보호, 로드밸런싱, 캐싱
예시 회사 내부에서 외부 웹 접근 통제 Nginx, Apache HTTP Server 앞단

예시:

GET http://www.google.com HTTP/1.0
Host: www.google.com

프록시 동작:

  • 이 요청을 수신한 프록시가 www.google.com에 연결하여 요청을 대신 보내고,
  • 응답을 받은 후 클라이언트에게 전달

프록시 서버에 대한 기본 개념을 가진 상태로 CSAPP 11장에서 배운 내용을 이용해 생각해 보겠다. 11장에서는 소켓 연결을 통한 웹 서버를 구현하는데 클라이언트와 서버가 소켓 연결의 단계를 거쳐서 연결을 수행한다. 하지만 프록시 서버를 구현하는 지금에는 어떻게 클라리언트와 최종 서버와의 연결이 진행될 수 있을까?

그래서 내가 생각한 것은 프록시 서버가 클라이언트 입장에서는 서버가 되고 최종 서버 입장에서는 프록시 서버가 클라이언트와 같이 연결이 된다면 프록시를 구현할 수 있겠다고 생각했다.

2. 필요 함수 설계

큰 틀에서 프록시 서버의 구현 아이디어는 구성했다. 그럼 어떤 함수를 구현해야 할지 생각해 보겠다.

2.1 main 함수

기존 tiny 서버를 기반으로 하면 될 것 같다. main에서 클라이언트와의 연결을 진행하기 위해 프록시 서버를 일종의 서버 호스트로 설정하는 과정을 기존 tiny 서버와 같이 진행하는 것이 좋을 것 같다.

2.2 doit 함수

기존의 tiny 서버에 있던 doit을 이용하되 많은 부분이 변경될 함수 중 하나이다. 먼저 기존 tiny 서버에서 진행하던 정적, 동적 요청에 대한 처리와 관련된 로직을 전부 제거를 해야 할 것 같다. 프록시 서버는 최종 서버가 응답으로 보내는 데이터를 클라리언트에 보내주기만 하면 되니 굳이 파일들을 처리하는 로직이 필요가 없을 것 같다.

그렇다면 어떤 기능들이 이 함수에 포함되어야 할까? 그건 처음 확인한 구현해야 하는 주요 기능에 있다. 아래 내용이 구현해야 하는 기능이었다:

  • 요청 파싱
    • Host, path 등을 추출하여
    • 요청을 GET /path HTTP/1.0 형식으로 변환 후 서버에 전달

요청 헤더에 있는 데이터를 추출하여 그 요청을 목적지 서버에 보내면 되는 것이다. 그러면 기존에 있던 함수를 변경하여 사용하면 될 것 같다.

이 과정에서 목적지 서버와 소켓 연결을 하기 위한 정보를 추출하고 목적지 서버와 open_clientfd() 함수를 사용해 연결을 시도할 예정이다.

이후 목적지 서버로부터 받은 데이터를 클라이언트에 반환하는 작업을 수행할 예정이다.

2.3 요청 분리

사용자 요청을 그대로 서버로 보내면 안 될 수 있다고 생각했다. 그래서 요청 헤더에서 필수적으로 필요한 헤더와 무시해도 되는 헤더 그 외의 나머지 헤더를 분리하여 저장할 수 있는 함수가 될 것이다.

2.4 parser 함수

이 함수에서 수행하게 될 것으로 기대하는 작업은 호스트, 포트, 경로에 대한 것을 추출하는 것이다. 이렇게 분리해서 추출하고 이 정보를 이용해 목적지 서버와 소켓 연결을 시도할 것이다.

2.5 반환 함수

목적지 서버로 부터 받은 응답을 클라이언트에 전달하는 역할을 할 것이다.

2.6 그 외의 함수

요청 에러를 처리하는 clienterror 함수는 기존에 tiny 웹 서버의 그것을 사용할 것이다.


다음 포스팅에서 실제 구현을 진행하겠다.