HTTP 서버 예제
설명할 예제
github: https://github.com/bjtj/tjsamples/tree/master/linux/network/simplehttpserver
- simple-http-server.c
- http-parser.c
- http-parser.h
- single-thread-http-server.c
clone 받기
$ git clone https://github.com/bjtj/tjsamples
HTTP 프로토콜
HTTP 패킷 구조
HTTP 패킷은 요청(request) 와 응답(response) 로 구분되며 요청 및 응답이 동일한 구조를 갖는다.
- HTTP header
- HTTP content (content 는 없을 수도 있음)
HTTP Header 구조
First line\r\n\r\n 로 줄이 구분된다.
Header field\r\n
...
\r\n
줄은 각 의미 단위이다.
Header field 는 이름/값 형태의 묶음으로 여러 개로 확장 가능하다.
header 의 끝은 \r\n 을 하나 더 추가해 표시한다.
예) 요청
GET / HTTP/1.1\r\n
User-Agent: curl/7.35.0\r\n
Host: example.com\r\n
Accept: */*\r\n
\r\n
예) 응답
HTTP/1.1 200 OK\r\n
Accept-Ranges: bytes\r\n
Cache-Control: max-age=604800\r\n
Content-Type: text/html\r\n
Date: Wed, 30 Dec 2015 02:17:52 GMT\r\n
Etag: "359670651+gzip"\r\n
Expires: Wed, 06 Jan 2016 02:17:52 GMT\r\n
Last-Modified: Fri, 09 Aug 2013 23:54:35 GMT\r\n
Server ECS (cpm/F9D5) is not blacklisted\r\n
Server: ECS (cpm/F9D5)\r\n
Vary: Accept-Encoding\r\n
X-Cache: HIT\r\n
x-ec-custom-error: 1\r\n
Content-Length: 1270\r\n
\r\n
<!doctype html>
<html>
<head>
<title>Example Domain</title>
<meta charset="utf-8" />
<meta http-equiv="Content-type" content="text/html; charset=utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<style type="text/css">
body {
single-thread-http-server
(생략)
First line 구조
<의미1> <의미2> <의미3>\r\n3가지 의미가 공백으로 구분되어 있다.
요청과 응답에 따라 의미가 다르다.
요청
- 의미1 : method
- 의미2 : uri
- 의미3 : HTTP 프로토콜 버전
응답
- 의미1 : HTTP 프로토콜 버전
- 의미2 : 숫자 형태의 응답 상태 값
- 의미3 : 문자열 형태의 응답 상태 (공백이 포함될 수 있음)
Header field 구조
<이름>: <값>\r\n예를 들어 Content-Length: 0\r\n 식으로 HTTP content 에 대한 정보 및 여러 통신에 필요한 부가 정보를 header field 로 표현한다.
표준 header fields
참고: https://en.wikipedia.org/wiki/List_of_HTTP_header_fields
- Content-Type : HTTP content 의 형태 (예: 일반 문서는 text/plain, html 문서는 text/html 등으로 표현)
- Content-Length : HTTP content 의 크기 (byte 단위)
HTTP 서버 구현
아래 예제들은 linux 환경에서 구현됨
간단한 예제로 시작
소스 내용은 어떠한 요청이든 아래 응답을 보내고 종료하는 HTTP 서버이다.
HTTP/1.1 200 OK\r\n
Content-Length: 5\r\n
Content-Type: text/plain\r\n
\r\n
Hello
위 상태로는 request 에 적절히 대응하기 어려운 면이 있다.
수정 필요한 부분
- 여러 요청 처리
- 현재 구현은 recv 한번으로 HTTP header 를 모두 받도록 되어 있지만 TCP 통신 특성 상 데이터가 파편화 되어 수신 될 수 있음
- HTTP header 를 먼저 받아 content 처리 방법이 선택되어야 한다.
수정한 소스
- Makefile : $ make single-thread-http-server
- http-parser.c : 헤더 분석
- http-parser.h : 헤더 분석
- single-thread-http-server.c : HTTP 서버 소스
while (1) 으로 무한 루프 돌면서 accept() 및 s_handle_client() 에서 요청 처리
s_handle_client() 에서 1바이트씩 읽어가며 header 부분을 읽도록 수정
HTTP header parse 는 덤으로 구현함
잘보고갑니다!!
답글삭제잘보고가요!
답글삭제