2020-11-12(Thu)

  1. 학습 날짜 // 2020-11-12(목)

  2. 학습시간 // 9:00~22:00

  3. 학습 범위 및 주제 // error fix

  4. 동료 학습 방법 // sanam, yohai님과 협업함

  5. 학습 목표 // jpg 파일을 보낼 때 발생하는 에러를 잡자.

  6. 상세 학습 내용

BACKLOG에서 TODO로 부상시킨 카드 중 FIX: send jpg 는 문제를 어서 확인하고 해결해보고 싶다고 벼르고 있었던 것이었다. 그냥 머릿속으로 검증했을 때는 분명 문제가 생길 수가 없는데 왜 문제가 생기나 싶었기 때문이다.

다행히 디버그 로그를 잘 심어놓았다보니 생각보다 문제 발생지점을 빠르게 찾을 수 있었다. 바로 jpg 파일을 read하고 buffer에 저장한 데이터를 Response _body로 저장하는 과정에서 문제가 발생하는 것이었다. 쪼개보면 아래 두 가지 가능성이 있다.

  1. read시에 buffer에 잘못된 값이 저장된다.

  2. buffer에서 Response _body로 데이터를 저장할 때 잘못된 값이 저장된다.

1번은 read 시에 binary 모드와 그렇지 않은 모드를 설정하는 경우가 있다고 하여 깊게 조사해보았으나 두 모드를 구분하는 경우는 window OS 환경에서의 접근방법으로 보였다. 그럼 유닉스에서는 어떻게 해야하는가? 인터넷에 많은 예제들은 우리에게 허용된 read 함수 외에 fstream을 활용하는 식이라 참고할 수 없었다. 오잉 그런데 다른 이미지를 read하는 깃헙들을 확인해본 결과 그냥 read를 한다. 2번을 제대로 검증해보자.

2번이 답이었다. jpg 파일에는 '\0' 문자로 끝나는 것이 보장되지 않는다. 즉 '\0' 문자가 중간 중간 있을 수도, 아니면 파일의 끝까지 읽어도 '\0' 문자가 없을 수 있다는 것이다. 그런데 buffer에 저장된 데이터를 Response 객체 안의 std::string _body 로 저장할 때 std::stirng(buf) 생성자로 저장해왔던 것이 화근이었다. 이런식으로 값을 저장하면 buf 안에 있는 '\0' 문자까지의 데이터만 string 객체에 저장되기 때문이다.

std::string(buf, bytes) 로 수정하여, '\0'까지만이 아니라 bytes 길이만큼의 데이터를 저장하도록 하여 해결하였다.

  1. 학습 내용에 대한 개인적인 총평

어떤 문제든, 로그를 바탕으로 논리적으로 차분히 추론하면 문제가 드러나는 것을 실감합니다.

subject의 조건에 맞춰서 select 후 한번의 read만 하는 것을 확실히 보장하기 위하여 대대적인 흐름 개선을 진행하기로 했습니다.

  1. client가 BUFFER_SIZE 보다 큰 데이터를 보내왔을 때 여러번의 select를 거쳐 read하여 Request로 객체로 받아내는 것

  2. Request body가 BUFFER_SIZE 보다 클 때 여러번의 select를 거쳐 write하여 CGI에 body를 보내는 것.

  3. CGI message가 BUFFER_SIZE 보다 클 때 여러번의 select를 거쳐 read하여 Response _body로 만들어내는 것.

  4. Static resource 용량이 BUFFER_SIZE보다 클 때 여러번의 select를 거쳐 read하여 Response _body로 만들어내는 것.

  5. Response _body가 BUFFER_SIZE보다 클 때 여러번의 select를 거쳐 wrtie하여 Client에 send하는 것.

  6. chunked 통신이 유의미하도록 CGI로부터 메세지를 select를 거쳐 read하고 read한 내용을 select를 거쳐 chunked 인코딩하여 client에 send하고, 다시 CGI로부터 메세지를 select를 거쳐 read하고... 하는 과정을 CGI가 종료될 때까지 반복하도록 하는 것.

사실 진짜 이 모든 조건을 완벽히 만족한 웹서버를 구현하신 분은 잘 없는 것 같지만, 팀원들과 '동료에게 당당하게 내보일 수 있는 웹서버를 만들자는 생각'을 공유하고 있어서 구현하는 것이 가능한 것 같습니다. 팀원들이 고맙고 자랑스럽네요. 단순히 프로젝트를 통과하기 위한 코드를 만든 것은 그럴 수 있다쳐도, 기초적인 subject 요구사항을 지키지않고 또 기초적인 crash protect 처리도 없이 과제를 구현했는데 불구하고 정당한 평가를 억울하게 생각하고 되려 평가자를 적대하는.. 신비로운 팀과는 다른 인성이라 감사할 따름입니다.

다음 학습 계획

  • Transfer-Encoding 헤더 구현

Last updated