multipart
Http Multipart
Multipart는 HTTP를 통해 File을 SERVER로 전송하기 위해 사용되는 Content-type이다.
일반적으로 HTTP Request는 Body에 클라이언트가 전송하려고 하는 데이터를 넣을 수 있다. 그리고 Body에 들어가는 데이터의 타입을 HTTP Header에 명시해 줌으로써 서버가 타입에 따라 알맞게 처리하게 한다. 이 Body의 타입을 명시하는 Header가 Content-type이다.
Content-Type필드에는 엔티티본문의 MIME타입을 기술한다.
-MIME타입
HTTP가 웹에서 전송되는 객체 각각에 붙이는 데이터 포맷 라벨로써 Multipurpose Internet Mail Extensions의 약자이다. 이는 원래 각기 다른 전자메일 시스템 사이에서 메시지가 오갈 때 겪는 문제점을 해결하기 위해 설계되었다. 이는 이메일에서 워낙 잘 동작했기 때문에 HTTP에서도 멀티미디어 콘텐츠를 기술하고 라벨을 붙이기 위해 채택되었다. 웹 서버는 모든 HTTP 객체 데이터에 MIME 타입을 붙인다. 웹 브라우저는 서버로부터 객체를 돌려받을 때, 다룰 수 있는 객체인지 MIME 타입을 통해 확인한다
그런데 보통 HTTP Request의 Body는 한 종류의 타입이 대부분이고, 그래서 Content-type도 타입을 하나만 명시할 수 있다.
(예를 들어 text이면 text/plain, xml이면 text/xml, jpg이미지면 image/jpeg 등등
Message
[Header 부분]
POST (서버의 URI) HTTP/1.1¶ Accept-Language: ko¶ Content-Type: multipart/form-data; boundary=(일종의 예약어)¶ Host: (서버의 IP:PORT)¶ Content-Length: (Body Size)¶ Connection: Keep-Alive¶
¶
[Body 부분]
–** (헤더에서 정한 예약어)**¶
Content-Disposition: form-data; name="(서버에서 받을 이름)"; filename="(보낼 파일 이름)"¶
content-Type: application/octet-stream¶ // 바이너리 파일을 보낼 경우에만 추가한다.
[보낼 데이터 부분]
//보낼 데이터 어쩌고 저쩌고
¶
[데이터 의 끝을 표시]
–** (헤더에서 정한 예약어)**¶
multipart/form-data로 데이터를 보낼때의 request header와 body는 위와 같이 이뤄져 있으며 눈여겨 봐야 할 부분은 Content-Type이다..
Content-Type에 multipart/form-data로 지정이 되어 있어야 서버에서 정상적으로 데이터를 처리할 수 있으며 boundary 에 지정되어 있는 문자열을 이용하여 전송되는 파일 데이터의 구분자 로 사용되는 것을 확인할 수 있다.
boundary의 문자열 중 마지막의 ——WebKitFormBoundaryQGvWeNAiOE4g2VM5– 값은 다른 값들과 다르게 마지막에 – 가 붙은 것을 확인할 수 있는데 이는 body의 끝을 알리는 의미이다.
Multipart/form-data / Multipart/byteranges
- Multipart/form-data
브라우저에서 서버로 HTML Form의 내용을 전송 시 사용 할 수 있다. 멀티파트 문서 형식으로써, 경계('?' (이중대시)로 시작되는 문자열)로 구분되는 다른 파트들로 구성된다.
각 파트는 그 자체로 개체이며 자신만의 HTTP 헤더를 가지는데 파일 업로드 필드를 위한 헤더로는 Content-Disposition, 그리고 가장 일반적인 것 중하나인 Content-Type이 있다. (Content-Length는 경계선이 구분자로 사용되므로 무시해도 된다
\<form action="http://localhost:8000/"method="post"enctype="multipart/form-data"\>
\<input type="text"name="myTextField"\>
\<input type="checkbox"name="myCheckBox"\>Check\</input\>
\<input type="file"name="myFile"\>
\<button\>Send the file\</button\>
\</form\>
HTML form 태그
POST / HTTP/1.1
Host: localhost:8000
User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10.9; rv:50.0) Gecko/20100101 Firefox/50.0
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8
Accept-Language: en-US,en;q=0.5
Accept-Encoding: gzip, deflate
Connection: keep-alive
Upgrade-Insecure-Requests: 1
Content-Type: multipart/form-data; boundary=—————————8721656041911415653955004498
Content-Length: 465
—————————–8721656041911415653955004498
Content-Disposition: form-data; name="myTextField"
Test
—————————–8721656041911415653955004498
Content-Disposition: form-data; name="myCheckBox"
on
—————————–8721656041911415653955004498
Content-Disposition: form-data; name="myFile"; filename="test.txt"
Content-Type: text/plain
Simple file.
—————————–8721656041911415653955004498–
HTTP Form은 다음과 같이 메시지를 전송한다.
범위 요청
HTTP는 클라이언트가 문서의 일부분이나 특정 범위만 요청할 수 있도록 할 수 있다.
이게 필요한 이유에 대해 설명하자면, HTTP를 통해서 용량이 큰 파일을 다운받고 있는데, 네트워크 문제로 연결이 끊겼다고 생각해보자.
그렇다면 보통의 생각으론 다시 연결을 시도하고 처음부터 대용량의 파일을 처음부터 받아야 할 것이다.
그런데 범위 요청을 이용하면 HTTP Client는 받다가 실패한 엔터티를 일부나 범위로 요청하여서 다운로드가 중단된 시점에서부터 다시 시작할 수 있다. (오리진 서버에서 객체를 처음 요청했을 때와 범위 요청을 했을 때 사이에 아무 변경이 없었다면)
예시
GET /bigfile.html HTTP/1.1
Host: www.joes-hardware.com
Range: bytes=4000-
User-Agent: Mozilla/4.61 [en] (WinNT; I)
…
이 예제에선, 클라이언트가 처음 4,000바이트 이후의 부분을 요청하고 있다. (몇바이트까지인지는 언급하지 않는데, 클라이언트가 문서의 크기가 정확히 얼마인지를 모르기 떄문이다.)
서버는 클라이언트에게 자신의 범위를 받아들일 수 있는지 응답에 Accept-Range 헤더를 포함시키는 방법으로 알려줄 수 있다. 이 헤더의 값은 측정의 단위로 주로 바이트이다.
HTTP/1.1 200 OK
Date: Fri, 05 Nov 1999 22:35:15 GMT
Server: Apache/1.2.4
Accept-Ranges: bytes
…
또한 Range 헤더는 P2P 파일 공유 클라이언트가 멀티미디어 파일의 다른 부분을 여러 다른 피어로부터 동시에 다운로드 받을 때도 널리 사용된다.
범위 요청은 객체의 특정 인스턴스를 클라이언트와 서버 사이에서 교환하는 것이기 때문에, 인스턴스 조작의 일종이라는 것에 주의해야 한다. 이는 클라이언트의 범위 요청은 오직 클라이언트와 서버가 같은 버전의 문서를 갖고 있을 때만 의미가 있음을 의미한다.
- Multipart/byteranges(멀티파트 범위 응답)
브라우저로 회신하는 부분적인 응답 전송의 컨텍스트 내에서 사용된다.
HTTP 메시지가 복수영역의 내용을 포함하는 경우, 이는 "multipart/byteranges" 객체에 담겨 전송된다. 이 미대어 타입은 MIME 경계로 구분된 두 개 이상의 부분을 포함하며, 각각은 자신의 Content-Type과 Content-Range 필드를 가진다.
206 Partial Content 상태코드가 전송된 경우, MIME 타입은 문서가 각각의 요청된 범위들 중 하나인 몇 가지 파트들로 구성되어 있음을 알려주기 위해 사용된다. 다른 멀티파트 타입처럼, Contetn-Type은 경계선 문자열을 정의하기 위해 boundary 디렉티브를 사용한다. 각각의 다른 파트들은 문서의 실제 타입을 가진 Content-Type 헤더와 그들이 나타내는 범위를 가진 Content-Range를 지니고 있다.
HTTP/1.1 206 Partial Content
Accept-Ranges: bytes
Content-Type: multipart/byteranges; boundary=3d6b6a416f9b5
Content-Length: 385
–3d6b6a416f9b5
Content-Type: text/html
Content-Range: bytes 100-200/1270
eta http-equiv="Content-type" content="text/html; charset=utf-8" /\>
\<meta name="vieport" content
–3d6b6a416f9b5
Content-Type: text/html
Content-Range: bytes 300-400/1270
-color: #f0f0f2;
margin: 0;
padding: 0;
font-family: "Open Sans", "Helvetica
–3d6b6a416f9b5–
my blog post
HTTP Multipart
Multipart는 HTTP를 통해 File을 SERVER로 전송하기 위해 사용되는 Content-type입니다.
간단하게 HTTP(request와 response 둘 다)는 4개로 나눌 수 있습니다.
- Request line
- HTTP Header
- Empty line
- Message body
여기서 Message body에 들어가는 데이터 타입을 HTTP Header에 명시해줄 수 있는데 명시할 수 있도록 해주는 필드가 바로 Content-type입니다. 그리고 바로 이 Content-type 필드에 MIME 타입을 기술해줄 수 있는데 여러 MIME 타입 중 하나가 바로 Multipart입니다.
MIME(Multipurpose Internet Mail Extensions)
MIME의 유래와 정의
-
기본적으로 E-mail(전자우편) 전송 프로토콜인 SMTP는 7비트 ASCII 문자만을 지원합니다. 그러나 ASCII 문자는 영어밖에 표현할 수 없기에 영어 이외의 언어로 쓰인 E-mail은 제대로 전송될 수 없었습니다. 이를 위해 탄생한 것이 MIME입니다.
-
MIME은 ASCII가 아닌 문자 인코딩을 이용해 영어가 아닌 다른 언어로 된 E-mail을 보낼 수 있는 방식을 정의합니다. 또한 그림, 음악, 영화 같은 8비트짜리 이진 파일을 전자 우편으로 보낼 수 있도록 합니다. 즉, e-mail을 위한 인터넷 표준 포맷인 것입니다.
-
MIME 타입은 본래 E-Mail을 위해 정의된 것이지만, HTTP, SIP와 같은 인터넷 프로토콜에서 함께 사용하고 있습니다.
-
MIME은 메세지의 종류를 나타내는 Content-type, 메세지 인코딩 방식을 나타내는 content-transfer-encoding과 같은 추가적인 E-mail 헤더를 정의합니다.
-
메세지를 MIME 형식으로 변환하는 것은 E-mail 프로그램이나 서버 상에서 자동으로 이루어집니다.
-
MIME은 확장가능합니다. MIME 표준은 새로운 Content-type과 또 다른 MIME 속성 값을 등록할 수 있는 방법을 정의하고 있습니다.
MIME의 구조
-
MIME 헤더
-
MIME-Version
-
MIME-Version: 1.0
-
해당 메세지가 MIME 형식임을 나타냅니다.
-
-
Content-Type
-
Content-Type: text/plain
-
HTTP Message body에 들어가는 데이터 타입과 서브 타입을 나타냅니다.
-
multipart 타입을 통해 MIME은 트리 구조의 메세지 형식을 정의할 수 있습니다.
-
어떤 것이 첨부된 텍스트(multipart/mixed)
-
텍스트와 HTML과 같이 다른 포맷을 함께 보낸 메세지(multipart/alternative) 등등…
-
-
-
-
Encoded-Word
- RFC 2822의 정의에 따르면, 메세지 헤더와 그 값은 항상 ASCII 문자를 사용해야 합니다. ASCII가 아닌 헤더 값은 encoded-word 문법에 따라 인코딩해야 합니다.
-
Multipart 메세지
-
서로 붙어있는 여러 개의 메세지를 포함하여 하나의 복합 메세지로 보내집니다.
-
MIME multipart 메세지는 “Content-type:” 헤더에 boundary 파라미터를 포함합니다.
-
boundary는 메세지 파트를 구분하는 역할을 하며, 메세지의 시작과 끝 부분에도 나타납니다
-
첫 번째 boundary 전에 나오는 내용은 MIME을 지원하지 않는 클라이언트를 위해 제공됩니다.
-
boundary를 선택하는 것은 클라이언트의 몫입니다. 보통 무작위의 문자를 선택해서 메세지의 본문과 충돌을 피합니다.
-
-
멀티파트 폼 제출
-
HTTP form을 채워서 제출하면, 가변 길이 텍스트 필드와 업로드 될 객체는 각각 멀티파트 본문을 구성하는 하나의 파트가 되어 보내집니다. 멀티파트 본문은 여러 다른 종류와 길이의 값으로 채워진 form을 허용합니다.
-
multipart/form-data : 사용자가 양식을 작성한 결과 값의 집합을 번들로 만드는데 사용됩니다.
-
-
Ex)
<form action="http://server.com/cgi/handle"
enctype="multipart/form-data"
method="post">
<p>
What is your name? <input type="text" name="submit-name"><br>
What files are you sending? <input type="file" name="files"><br>
<input type="submit" value="Send">
<input type="reset">
</form>
- 사용자가 텍스트 필드에 “Sally”라고 입력하고, “essayfile.txt”를 선택했다면 user agent는 아래와 같은 데이터를 돌려보낼 것입니다.
Content-Type: multipart/form-data; boundary=AaB03x
--AaB03x
Content-Disposition: form-data; name="submit-name"
Sally
--AaB03x
Content-Disposition: form-data; name="files"; filename="essayfile.txt" Content-Type: text/plain
...contents of _essayfile.txt_...
--AaB03x--
- 마지막 boundary에는 마지막에 –가 붙습니다.
- 사용자가 두번째 파일로 “imagefile.gif”를 선택했다면 user agent는 그 부분을 아래와 같이 생성할 것입니다.
Content-Type: multipart/form-data; boundary=AaB03x
--AaB03x
Content-Disposition: form-data; name="submit-name"
Sally
--AaB03x
Content-Disposition: form-data; name="files"
Content-Type: **multipart/mixed**; boundary=BbC04y
--BbC04y
Content-Disposition: file; filename="essayfile.txt" Content-Type: text/plain
...contents of essayfile.txt...
--BbC04y
Content-Disposition: file; filename="imagefile.gif" Content-Type: image/gif
Content-Transfer-Encoding: binary
...contents of imagefile.gif...
--BbC04y--
--AaB03x--