TIL 11월 22일 2023년

ORCASUIT·2023년 11월 22일
void read_requesthdrs(rio_t *rp)
{
    char buf[MAXLINE];

    Rio_readlineb(rp, buf, MAXLINE);
    while (strcmp(buf, "\r\n"))
    {
        Rio_readlineb(rp, buf, MAXLINE);
        printf("%s", buf);
    }
    return;
}

코드가 무한 루프에 빠지는 문제가 발생했다면, 그 원인은 클라이언트가 잘못된 형식의 HTTP 요청을 보냈을 수도 있고, 서버 측 코드에서 요청을 적절히 처리하지 못했을 수도 있습니다. 크롬과 같은 현대의 웹 브라우저들은 일반적으로 표준에 맞는 정확한 HTTP 요청을 생성합니다. 그러나 이러한 상황에서 발생할 수 있는 몇 가지 문제는 다음과 같습니다:

  1. HTTP 표준 미준수: 클라이언트가 비표준 줄바꿈 문자를 사용하거나, 헤더의 형식이 잘못된 경우 서버가 예상하는 대로 요청의 끝을 인식하지 못할 수 있습니다.
  2. 통신 오류: 네트워크 문제나 데이터 손상으로 인해 서버가 잘못된 요청을 받을 수 있습니다.
  3. 서버 측 코드 오류: 서버 측 코드에서 요청의 끝을 인식하지 못하거나, 버퍼를 적절히 처리하지 않는 등의 문제가 발생할 수 있습니다.

디버깅을 통해 이 문제를 해결하기 위한 접근 방법은 다음과 같습니다:

  • 요청 로깅: 서버 측에서 모든 요청의 내용을 로깅하여, 클라이언트로부터 수신한 정확한 HTTP 요청 내용을 검사합니다.
  • 버퍼 검사: buf 변수가 각 요청 후에 올바르게 초기화되고, Rio_readlineb 함수가 새로운 데이터를 buf에 성공적으로 저장하는지 확인합니다.
  • 헤더 종료 조건 검증: HTTP 요청 헤더의 끝을 나타내는 \r\n 문자열을 올바르게 검사하는지 확인합니다. 만약 클라이언트가 표준과 다른 줄바꿈 문자를 사용한다면, 서버는 이를 처리할 수 있도록 구현되어야 합니다.

이러한 접근 방법을 사용하여 문제의 원인을 파악하고 적절한 수정을 적용하여 서버의 견고성을 향상시킬 수 있습니다.

문제 해결을 위해 여러 단계를 거쳐야 합니다. 먼저, read_requesthdrs 함수에서 잠재적인 무한 루프의 원인을 파악하고, 그 다음으로 클라이언트 (이 경우 크롬)가 서버에 전송하는 HTTP 요청이 표준을 준수하고 있는지 확인합니다. 마지막으로, 서버 측 코드가 이러한 요청을 적절하게 처리할 수 있도록 보장해야 합니다.

1. 무한 루프 문제 해결

서버 코드에 무한 루프 문제를 해결하기 위해, 각 헤더 라인을 읽을 때마다 누적 길이를 검사하고, 최대 헤더 길이를 넘었을 때 오류를 반환하는 로직을 추가합니다:

#define MAX_HEADER_LENGTH 8192 // HTTP 헤더 최대 길이

void read_requesthdrs(rio_t *rp, int fd) {
    char buf[MAXLINE];
    int totalLength = 0; // 누적 헤더 길이 초기화

    Rio_readlineb(rp, buf, MAXLINE);
    while (strcmp(buf, "\r\n")) {
        totalLength += strlen(buf); // 누적 길이 추가
        if (totalLength > MAX_HEADER_LENGTH) {
            clienterror(fd, "Request Header Too Large", "413", "Request Entity Too Large",
                        "Request header fields too large");
            return;
        }
        Rio_readlineb(rp, buf, MAXLINE);
    }
}

2. 클라이언트 요청 검증

크롬

무한 루프 문제와 관련하여, 서버 측 코드가 클라이언트로부터 수신된 HTTP 요청을 올바르게 파싱하고 처리할 수 있도록 수정해야 합니다. 크롬과 같은 웹 브라우저는 표준 HTTP 요청을 보내는 것이 일반적이지만, 네트워크 문제나 클라이언트의 버그로 인해 비정상적인 요청을 보낼 수도 있습니다. 따라서 서버 측 코드는 이러한 상황에 대비해야 합니다.

서버 측 코드 수정:

  1. 요청 헤더 읽기 함수 개선: 요청 헤더를 읽는 동안 누적 헤더 길이를 추적하고, 빈 줄이 나타날 때까지 또는 최대 헤더 길이에 도달할 때까지만 읽도록 합니다.
#define MAX_HEADER_LENGTH 8192 // 예를 들어, 최대 헤더 길이를 8KB로 제한

void read_requesthdrs(rio_t *rp, int fd) {
    char buf[MAXLINE];
    int totalLength = 0;

    // 헤더를 한 줄씩 읽어서 처리
    while (Rio_readlineb(rp, buf, MAXLINE) > 0) { // Rio_readlineb의 반환값을 확인
        totalLength += strlen(buf);
        if (strcmp(buf, "\r\n") == 0) { // 요청 헤더의 끝을 확인
            break;
        }
        if (totalLength > MAX_HEADER_LENGTH) { // 최대 헤더 길이 검사
            clienterror(fd, buf, "413", "Request Entity Too Large",
                        "The request headers are too long.");
            return;
        }
    }
}
  1. 클라이언트 에러 처리 함수: 클라이언트에게 적절한 HTTP 응답 코드와 메시지를 보내는 함수를 구현합니다.
void clienterror(int fd, char *cause, char *errnum, 
                 char *shortmsg, char *longmsg) {
    char buf[MAXLINE], body[MAXBUF];

    // HTTP 응답 메시지 바디를 생성
    sprintf(body, "<html><title>Tiny Error</title>");
    sprintf(body, "%s<body bgcolor=\"ffffff\">\r\n", body);
    sprintf(body, "%s%s: %s\r\n", body, errnum, shortmsg);
    sprintf(body, "%s<p>%s: %s\r\n", body, longmsg, cause);
    sprintf(body, "%s<hr><em>The Tiny Web server</em>\r\n", body);

    // HTTP 응답 메시지를 클라이언트에 전송
    sprintf(buf, "HTTP/1.0 %s %s\r\n", errnum, shortmsg);
    Rio_writen(fd, buf, strlen(buf));
    sprintf(buf, "Content-type: text/html\r\n");
    Rio_writen(fd, buf, strlen(buf));
    sprintf(buf, "Content-length: %d\r\n\r\n", (int)strlen(body));
    Rio_writen(fd, buf, strlen(buf));
    Rio_writen(fd, body, strlen(body));
}

위의 코드는 read_requesthdrs 함수가 요청 헤더의 끝을 인식하지 못하거나 헤더 길이가 최대값을 초과하는 경우 적절한 오류 메시지를 클라이언트에게 전송하도록 합니다. Rio_readlineb 함수의 반환값을 검사하여 함수 호출이 성공적으로 라인을 읽었는지 확인하고, 실패한 경우 오류 처리를 수행합니다.

이러한 변경을 통해 서버는 비정상적인 요청을 받았을 때 무한 루프에 빠지는 대신 적절한 오류 응답을 클라이언트에게 보내고 연결을 종료할 수 있습니다.

0개의 댓글