💡 csapp (번역본) 930p
11.6.c / 11.7 / 11.9 / 11.11
풀이 및 구현입니다.
Tiny의 출력을 조사해서 여러분이 사용하는 브라우저의 HTTP 버전을 결정하라.
=> HTTP/1.0 or HTTP/1.1
=> 왜 response, request 버전이 다른가,,,?
Tiny를 확장해서 MPG 비디오 파일을 처리하도록 하시오. 실제 브라우저를 사용해서 여러분의 결과를 체크하시오.
else if (strstr(filename, ".mp4"))
strcpy(filetype, "video/mp4");
<html>
<head><title>test</title></head>
<body>
<img align="middle" src="godzilla.gif">
Dave O'Hallaron
<video src="video.mp4" controls loop autoplay width="550"></video>
</body>
</html>
Tiny를 수정해서 정적 컨텐츠를 처리할 때 요청한 파일을 mmap과 r1o_readn 대신에
malloc, rio_readn, rio_writen을 사용해서 연결 식별자에게 복사하도록 하시오.
srcp = (char *) malloc(filesize);
// mmap 대신 malloc 사용
rio_readn(srcfd, srcp, filesize);
free(srcp);
calculate 클릭!
A. 그림 11.27의 CGI adder함수에 대한 HTML 형식을 작성하시오. 이 형식은 사용
자가 함께 더할 두 개의 숫자로 채우는 두 개의 텍스트 상자를 포함해야 한다. 여 러
분의 형식은 GET 메소드를 사용해서 컨텐츠를 요청해야 한다.
B. 실제 브라우저를 사용해서 Tiny로부터 이 형식을 요청하고, 채운 형식을 Tiny에
보내고, adder가 생성한 동적 컨텐츠를 표시하는 방법으로 여러분의 작업을 체크
하라.
if ((buf = getenv("QUERY_STRING")) != NULL) {
p = strchr(buf, '&');
*p = '\0';
// strcpy(arg1, buf);
// strcpy(arg2, p + 1);
// n1 = atoi(arg1); // 첫 번째 인자를 정수로 변환
// n2 = atoi(arg2); // 두 번째 인자를 정수로 변환
/* Homework: 11.10 */
sscanf(buf, "num1=%d", &n1);
sscanf(p + 1, "num2=%d", &n2);
}
<html>
<head><title>test</title></head>
<body>
<img align="middle" src="godzilla.gif">
Dave O'Hallaron
<video src="video.mp4" controls loop autoplay width="550"></video>
<form action="/cgi-bin/adder" method="GET">
<p>Number 1: <input type="text" name="num1"></p>
<p>Number 2: <input type="text" name="num2"></p>
<input type="submit" value="Calculate">
</form>
</body>
</html>
Tiny를 확장해서 HTTP HEAD 메소드를 지원하도록 하라. telnet을 웹 클라이언트로
사용해서 작업 결과를 체크하시오.
/* HTTP 요청의 메서드가 "GET"이 아닌 경우에 501 오류를 클라이언트에게 반환 */
/* Homework 11.11 "HEAD"가 아닌 경우 추가 */
if (strcasecmp(method, "GET") * strcasecmp(method, "HEAD"))
{ // 조건문에서 하나라도 0이면 0
clienterror(fd, method, "501", "Not implemented", "Tiny does not implement this method");
return;
}
void serve_static(int fd, char *filename, int filesize, char *method)
{
int srcfd; // 파일 디스크립터
char *srcp, // 파일 내용을 메모리에 매핑한 포인터
filetype[MAXLINE], // 파일의 MIME 타입
buf[MAXBUF]; // 응답 헤더를 저장할 버퍼
/* 응답 헤더 생성 및 전송 */
get_filetype(filename, filetype); // 파일 타입 결정
sprintf(buf, "HTTP/1.0 200 OK\r\n"); // 응답 라인 작성
// 응답 헤더
sprintf(buf, "%sServer: Tiny Web Server\r\n", buf); // 서버 정보 추가
sprintf(buf, "%sConnections: close\r\n", buf); // 연결 종료 정보 추가
sprintf(buf, "%sContent-length: %d\r\n", buf, filesize); // 컨텐츠 길이 추가
sprintf(buf, "%sContent-type: %s\r\n\r\n", buf, filetype); // 컨텐츠 타입 추가
/* 응답 라인과 헤더를 클라이언트에게 보냄 */
Rio_writen(fd, buf, strlen(buf));
printf("Response headers: \n");
printf("%s", buf);
if (strcasecmp(method, "HEAD") == 0)
return;
/* 응답 바디 전송 */
srcfd = Open(filename, O_RDONLY, 0); // 파일 열기
//srcp = Mmap(0, filesize, PROT_READ, MAP_PRIVATE, srcfd, 0); // 파일을 메모리에 동적할당
/* Homework 11.9 */
srcp = (char *) malloc(filesize); // mmap 대신 malloc 사용
rio_readn(srcfd, srcp, filesize); // rio_readn 사용하기
Close(srcfd); // 파일 닫기
Rio_writen(fd, srcp, filesize); // 클라이언트에게 파일 내용 전송
// Munmap(srcp, filesize); // 메모리 할당 해제
free(srcp); // malloc 사용 => munmap에서 free로 변경
}
/*
* adder.c - a minimal CGI program that adds two numbers together
*/
/* $begin adder */
#include "csapp.h"
int main(void) {
char *buf, *p, *method;
char arg1[MAXLINE], arg2[MAXLINE], content[MAXLINE];
int n1 = 0, n2 = 0;
/* Extract the two arguments */
/* 두 개의 인자 추출 */
if ((buf = getenv("QUERY_STRING")) != NULL) {
p = strchr(buf, '&');
*p = '\0';
strcpy(arg1, buf);
strcpy(arg2, p + 1);
n1 = atoi(arg1); // 첫 번째 인자를 정수로 변환
n2 = atoi(arg2); // 두 번째 인자를 정수로 변환
}
/* Make the response body */
/* 응답 본문 생성 */
sprintf(content, "QUERY_STRING=%s", buf);
sprintf(content, "Welcome to add.com: ");
sprintf(content, "%sTHE Internet addition portal.\r\n<p>", content);
sprintf(content, "%sThe answer is: %d + %d = %d\r\n<p>",
content, n1, n2, n1 + n2);
sprintf(content, "%sThanks for visiting!\r\n", content);
/* Generate the HTTP response */
/* HTTP 응답 생성 */
printf("Connection: close\r\n");
printf("Content-length: %d\r\n", (int) strlen(content));
printf("Content-type: text/html\r\n\r\n");
printf("%s", content); // 생성된 응답 본문 출력
fflush(stdout); // 출력 버퍼를 비워줌
exit(0);
}
/* $end adder */
char *buf, *p, *method;
메서드 추가실행 후
telnet localhost 8000
HEAD / HTTP/1.1
Host: localhost
차례로 입력한다.
실행 후 터미널 분할로 확인하는것이 편리하다!
telnet localhost 8000
서버에게 리소스의 헤더 정보만을 요청
HEAD / HTTP/1.1
Host: localhost