FastCGI 사양 (번역 중)
Sun, Dec 17 2023 02:49:59번역: 김호동 <hodong@nimfsoft.art>
이 글은 https://fastcgi-archives.github.io/FastCGI_Specification.html 을 번역한 글입니다.
FastCGI 사양은 Open Market, Inc.의 지적 재산입니다.
설명: 이 사양의 좁은 목표는 응용 프로그램 관점에서 FastCGI 응용 프로그램과 FastCGI를 지원하는 웹 서버 간의 인터페이스를 지정하는 것입니다.
Open Market, Inc.
문서 버전: 1.0 1996년 4월 29일
저작권 © 1996 Open Market, Inc. 245 First Street, Cambridge, MA 02142 U.S.A.
- 1. 소개
- 2. 초기 프로세스 상태
- 3. Protocol Basics
- 4. 관리 레코드 유형
- 5. 응용 프로그램 레코드 유형
- 6. 역할
- 7. 에러
- 8. Types and Constants
- 9. 참고 문헌
- A. 표: 레코드 유형의 속성
- B. 전형적인 프로토콜 메시지 흐름
1. 소개
FastCGI는 웹 서버 API의 불이익 없이 모든 인터넷 응용 프로그램에 고성능을 제공하는 CGI에 대한 개방형 확장입니다.
이 사양의 좁은 목표는 응용 프로그램 관점에서 FastCGI 응용 프로그램과 FastCGI를 지원하는 웹 서버 간의 인터페이스를 지정하는 것입니다. FastCGI와 관련된 많은 웹 서버 기능(예: 응용 프로그램 관리 기능)은 웹 서버 인터페이스에 대한 응용 프로그램과 관련이 없으므로 여기에 설명되어 있지 않습니다.
이 사양은 유닉스(보다 정확하게는 버클리 소켓을 지원하는 POSIX 시스템)용입니다. 사양의 대부분은 간단한 통신 프로토콜이며 이는 바이트 순서와 독립적이며 다른 시스템으로 확장될 것입니다.
우리는 FastCGI를 CGI/1.1의 기존 Unix 구현과 비교하여 소개하겠습니다. FastCGI는 수명이 긴 응용 프로그램 프로세스, 즉 응용 프로그램 서버를 지원하도록 설계되었습니다. 이는 응용 프로그램 프로세스를 구성하고 이를 사용하여 하나의 요청에 응답하고 종료하는 CGI/1.1의 기존 Unix 구현과 비교할 때 큰 차이점입니다.
FastCGI 프로세스의 초기 상태는 CGI/1.1 프로세스의 초기 상태보다 더 스파르타적입니다. 왜냐하면 FastCGI 프로세스는 어떤 것과도 연결된 삶을 시작하지 않기 때문입니다. 그것은 기존의 열린 파일 stdin
, stdout
, stderr
이 없으며 환경 변수를 통해 많은 정보를 받지 않습니다. FastCGI 프로세스의 초기 상태의 핵심 부분은 웹 서버로부터의 연결을 받아들이는 청취 소켓입니다.
FastCGI 프로세스가 청취 소켓에서 연결을 수락한 후 프로세스는 간단한 프로토콜을 실행하여 데이터를 받고 보냅니다. 프로토콜은 두 가지 목적으로 사용됩니다. 첫째, 프로토콜은 여러 개의 독립적인 FastCGI 요청 간의 단일 전송 연결을 다중화합니다. 이는 이벤트 주도 또는 다중 스레드 프로그래밍 기술을 사용하여 동시 요청을 처리할 수 있는 응용 프로그램을 지원합니다. 둘째, 각 요청 내에서 프로토콜은 각 방향으로 여러 개의 독립적인 데이터 스트림을 제공합니다. 예를 들어, 이렇게 하면 CGI/1.1에서처럼 별도의 파이프를 필요로 하기보다는, stdout
및 stderr
데이터는 모두 응용 프로그램에서 웹 서버로 단일 전송 연결을 통해 전달됩니다.
FastCGI 응용 프로그램은 잘 정의된 몇 가지 역할 중 하나를 수행합니다. 가장 친숙한 역할은 응답자 역할로, 응용 프로그램이 HTTP 요청과 관련된 모든 정보를 수신하고 HTTP 응답을 생성합니다; 이것이 CGI/1.1 프로그램이 수행하는 역할입니다. A second role is Authorizer, in which the application receives all the information associated with an HTTP request and generates an authorized/unauthorized decision. A third role is Filter, in which the application receives all the information associated with an HTTP request, plus an extra stream of data from a file stored on the Web server, and generates a “filtered” version of the data stream as an HTTP response. 프레임워크는 확장 가능하므로 나중에 더 많은 FastCGI를 정의할 수 있습니다.
이 사양의 나머지 부분에서는 혼동을 일으키지 않는 한 “FastCGI 응용 프로그램”, “응용 프로그램 프로세스” 또는 “응용 프로그램 서버”라는 용어를 “응용 프로그램”으로 축약합니다.
2. 초기 프로세스 상태
2.1 인수 목록
기본적으로 웹 서버는 실행 파일 경로 이름의 마지막 구성 요소로 간주되는 응용 프로그램 이름인 단일 요소를 포함하는 인수 목록을 만듭니다. 웹 서버는 다른 응용 프로그램 이름을 지정하거나 보다 정교한 인수 목록을 지정하는 방법을 제공할 수 있습니다.
Note that the file executed by the Web server might be an interpreter file (a text file that starts with the characters #!
), in which case the application’s argument list is constructed as described in the execve
manpage.
2.2 파일 설명자
웹 서버는 응용 프로그램이 실행을 시작할 때 단일 파일 설명자 FCGI_LISTENSOCK_FILENO
를 열어 둡니다. 이 설명자는 웹 서버에서 생성된 청취 소켓을 참조합니다.
FCGI_LISTENSOCK_FILENO
는 STDIN_FILENO
와 같습니다. 표준 설명자 STDOUT_FILENO
및 STDERR_FILENO
는 응용 프로그램이 실행을 시작할 때 닫힙니다. 응용 프로그램이 CGI 또는 FastCGI를 사용하여 호출되었는지 여부를 결정하는 신뢰할 수 있는 방법은 getpeername(FCGI_LISTENSOCK_FILENO)
을 호출하는 것이며, 이 호출은 FastCGI 응용 프로그램에 대해 ENOTCONN
으로 설정된 errno
와 함께 -1을 반환합니다.
신뢰할 수 있는 전송인 유닉스 스트림 파이프 (AF_UNIX
) 또는 TCP/IP (AF_INET
)에 대한 웹 서버의 선택은 FCGI_LISTENSOCK_FILENO
소켓의 내부 상태에 내재되어 있습니다.
2.3 Environment variables
The Web server may use environment variables to pass parameters to the application. This specification defines one such variable, FCGI_WEB_SERVER_ADDRS
; we expect more to be defined as the specification evolves. The Web server may provide a way to bind other environment variables, such as the PATH
variable.
2.4 Other state
The Web server may provide a way to specify other components of an application’s initial process state, such as the priority, user ID, group ID, root directory, and working directory of the process.
3. Protocol Basics
3.1 Notation
We use C language notation to define protocol message formats. All structure elements are defined in terms of the unsigned char
type, and are arranged so that an ISO C compiler lays them out in the obvious manner, with no padding. The first byte defined in the structure is transmitted first, the second byte second, etc.
We use two conventions to abbreviate our definitions.
First, when two adjacent structure components are named identically except for the suffixes “B1
” and “B0
,” it means that the two components may be viewed as a single number, computed as B1<<8 + B0
. The name of this single number is the name of the components, minus the suffixes. This convention generalizes in an obvious way to handle numbers represented in more than two bytes.
Second, we extend C struct
s to allow the form
struct {
unsigned char mumbleLengthB1;
unsigned char mumbleLengthB0;
... /* other stuff */
unsigned char mumbleData[mumbleLength];
};
meaning a structure of varying length, where the length of a component is determined by the values of the indicated earlier component or components.
3.2 전송 연결 수락
FastCGI 응용 프로그램은 파일 설명자 FCGI_LISTENSOCK_FILENO
가 참조하는 소켓에서 accept()
를 호출하여 새 전송 연결을 수락합니다. If the accept()
succeeds, and the FCGI_WEB_SERVER_ADDRS
environment variable is bound, the application application immediately performs the following special processing:
-
FCGI_WEB_SERVER_ADDRS
: The value is a list of valid IP addresses for the Web server.If
FCGI_WEB_SERVER_ADDRS
was bound, the application checks the peer IP address of the new connection for membership in the list. If the check fails (including the possibility that the connection didn’t use TCP/IP transport), the application responds by closing the connection.FCGI_WEB_SERVER_ADDRS
is expressed as a comma-separated list of IP addresses. Each IP address is written as four decimal numbers in the range [0..255] separated by decimal points. So one legal binding for this variable isFCGI_WEB_SERVER_ADDRS=199.170.183.28,199.170.183.71
.
An application may accept several concurrent transport connections, but it need not do so.
3.3 Records
응용 프로그램은 간단한 프로토콜을 사용하여 웹 서버의 요청을 실행합니다. 프로토콜의 세부 사항은 응용 프로그램의 역할에 따라 다르지만, 대략적으로 말하면 웹 서버가 먼저 매개 변수 및 기타 데이터를 응용 프로그램에 보낸 다음, 응용 프로그램이 결과 데이터를 웹 서버로 보내고, 마지막으로 응용 프로그램이 요청이 완료되었다는 표시를 웹 서버에 보냅니다.
전송 연결을 통해 흐르는 모든 데이터는 FastCGI 레코드로 전달됩니다. FastCGI 레코드는 두 가지 작업을 수행합니다. 첫째, 레코드는 여러 개의 독립적인 FastCGI 요청 간의 전송 연결을 다중화합니다. 이 다중화는 이벤트 주도 또는 다중 스레드 프로그래밍 기술을 사용하여 동시 요청을 처리할 수 있는 응용 프로그램을 지원합니다. 둘째, 레코드는 단일 요청 내에서 각 방향으로 여러 개의 독립적인 데이터 스트림을 제공합니다. 예를 들어, 이러한 방식으로 stdout
및 stderr
데이터는 별도의 연결을 필요로 하기 보다는, 응용 프로그램에서 웹 서버로 단일 전송 연결을 통해 전달될 수 있습니다.
typedef struct {
unsigned char version;
unsigned char type;
unsigned char requestIdB1;
unsigned char requestIdB0;
unsigned char contentLengthB1;
unsigned char contentLengthB0;
unsigned char paddingLength;
unsigned char reserved;
unsigned char contentData[contentLength];
unsigned char paddingData[paddingLength];
} FCGI_Record;
A FastCGI record consists of a fixed-length prefix followed by a variable number of content and padding bytes. A record contains seven components:
version
: Identifies the FastCGI protocol version. This specification documentsFCGI_VERSION_1
.type
: Identifies the FastCGI record type, i.e. the general function that the record performs. Specific record types and their functions are detailed in later sections.requestId
: Identifies the FastCGI request to which the record belongs.contentLength
: The number of bytes in thecontentData
component of the record.paddingLength
: The number of bytes in thepaddingData
component of the record.contentData
: Between 0 and 65535 bytes of data, interpreted according to the record type.paddingData
: Between 0 and 255 bytes of data, which are ignored.
We use a relaxed C struct
initializer syntax to specify constant FastCGI records. We omit the version
component, ignore padding, and treat requestId
as a number. Thus {FCGI_END_REQUEST, 1, {FCGI_REQUEST_COMPLETE,0}}
is a record with type == FCGI_END_REQUEST
, requestId == 1
, and contentData == {FCGI_REQUEST_COMPLETE,0}
.
Padding
The protocol allows senders to pad the records they send, and requires receivers to interpret the paddingLength
and skip the paddingData
. Padding allows senders to keep data aligned for more efficient processing. Experience with the X window system protocols shows the performance benefit of such alignment.
우리는 8바이트 배수가 되는 경계에 레코드를 배치할 것을 권고합니다. FCGI_Record
의 고정 길이 부분은 8바이트입니다.
Managing Request IDs
The Web server re-uses FastCGI request IDs; the application keeps track of the current state of each request ID on a given transport connection. A request ID R
becomes active when the application receives a record {FCGI_BEGIN_REQUEST, R, ...}
and becomes inactive when the application sends a record {FCGI_END_REQUEST, R, ...}
to the Web server.
While a request ID R
is inactive, the application ignores records with requestId == R
, except for FCGI_BEGIN_REQUEST
records as just described.
The Web server attempts to keep FastCGI request IDs small. That way the application can keep track of request ID states using a short array rather than a long array or a hash table. An application also has the option of accepting only one request at a time. In this case the application simply checks incoming requestId
values against the current request ID.
레코드 유형의 유형
FastCGI 레코드 유형을 분류하는 데는 두 가지 유용한 방법이 있습니다.
The first distinction is between management records and application records. A management record contains information that is not specific to any Web server request, such as information about the protocol capabilities of the application. An application record contains information about a particular request, identified by the requestId
component.
Management records have a requestId
value of zero, also called the null request ID. Application records have a nonzero requestId
.
두 번째 차이점은 별개와 스트림 레코드 사이에 있습니다. 별개 레코드는 그 자체로 의미 있는 데이터 단위를 포함합니다. 스트림 레코드는 스트림의 일부, 즉 스트림 유형의 0개 이상의 비어 있지 않은 레코드(length != 0
)와 스트림 형식의 빈 레코드(length == 0
)가 뒤따르는 일련의 레코드입니다. 스트림 레코드의 contentData
구성 요소는 연결될 때 바이트 순서열를 형성합니다; 이 바이트 순서는 스트림의 값입니다. 따라서 스트림의 값은 바이트 순서열가 얼마나 많은 레코드를 포함하는지 또는 그것의 바이트들이 비어 있지 않은 레코드 간에 어떻게 분할되는지와 무관합니다.
이 두 분류는 독립적입니다. 이 버전의 FastCGI 프로토콜에 정의된 레코드 유형 중 모든 관리 레코드 유형은 별개 레코드 유형이며, 거의 모든 응용 프로그램 레코드 유형은 스트림 레코드 유형입니다. 그러나 세 가지 응용 프로그램 레코드 유형은 별개이며, 프로토콜의 일부 이후 버전에서 스트림인 관리 레코드 유형을 정의하는 것을 막는 것은 없습니다.
3.4 이름-값 쌍
많은 역할에서 FastCGI 응용 프로그램은 다양한 수의 가변 길이 값을 읽고 써야 합니다. 따라서 이름-값 쌍을 인코딩하기 위한 표준 형식을 채택하는 것이 유용합니다.
FastCGI는 이름의 길이, 값의 길이, 이름, 값의 순서로 이름-값 쌍을 전송합니다. 127바이트 이하의 길이는 1바이트로 인코딩되는 반면, 더 긴 길이는 항상 4바이트로 인코딩됩니다:
typedef struct {
unsigned char nameLengthB0; /* nameLengthB0 >> 7 == 0 */
unsigned char valueLengthB0; /* valueLengthB0 >> 7 == 0 */
unsigned char nameData[nameLength];
unsigned char valueData[valueLength];
} FCGI_NameValuePair11;
typedef struct {
unsigned char nameLengthB0; /* nameLengthB0 >> 7 == 0 */
unsigned char valueLengthB3; /* valueLengthB3 >> 7 == 1 */
unsigned char valueLengthB2;
unsigned char valueLengthB1;
unsigned char valueLengthB0;
unsigned char nameData[nameLength];
unsigned char valueData[valueLength
((B3 & 0x7f) << 24) + (B2 << 16) + (B1 << 8) + B0];
} FCGI_NameValuePair14;
typedef struct {
unsigned char nameLengthB3; /* nameLengthB3 >> 7 == 1 */
unsigned char nameLengthB2;
unsigned char nameLengthB1;
unsigned char nameLengthB0;
unsigned char valueLengthB0; /* valueLengthB0 >> 7 == 0 */
unsigned char nameData[nameLength
((B3 & 0x7f) << 24) + (B2 << 16) + (B1 << 8) + B0];
unsigned char valueData[valueLength];
} FCGI_NameValuePair41;
typedef struct {
unsigned char nameLengthB3; /* nameLengthB3 >> 7 == 1 */
unsigned char nameLengthB2;
unsigned char nameLengthB1;
unsigned char nameLengthB0;
unsigned char valueLengthB3; /* valueLengthB3 >> 7 == 1 */
unsigned char valueLengthB2;
unsigned char valueLengthB1;
unsigned char valueLengthB0;
unsigned char nameData[nameLength
((B3 & 0x7f) << 24) + (B2 << 16) + (B1 << 8) + B0];
unsigned char valueData[valueLength
((B3 & 0x7f) << 24) + (B2 << 16) + (B1 << 8) + B0];
} FCGI_NameValuePair44;
길이의 첫 번째 바이트의 상위 비트는 길이의 인코딩을 나타냅니다. 상위 0은 1바이트 인코딩을 의미하고, 1은 4바이트 인코딩을 의미합니다.
이 이름-값 쌍 형식을 사용하면 송신자는 추가 인코딩 없이 이진 값을 전송할 수 있으며, 수신자는 큰 값에 대해서도 즉시 정확한 양의 저장 공간을 할당할 수 있습니다.
3.5 전송 연결 닫기
웹 서버는 전송 연결의 수명을 제어합니다. 웹 서버는 활성화된 요청이 없을 때 연결을 닫을 수 있습니다. 또는 웹 서버가 응용 프로그램에 닫기 권한을 위임할 수 있습니다(FCGI_BEGIN_REQUEST
을 보세요). 이 경우 응용 프로그램은 지정된 요청이 끝나면 연결을 닫습니다.
이러한 유연성은 다양한 응용 프로그램 스타일을 수용합니다. 간단한 응용 프로그램은 한 번에 하나의 요청을 처리하고 각 요청에 대해 새로운 전송 연결을 수락합니다. 보다 복잡한 응용 프로그램은 하나 이상의 전송 연결을 통해 동시 요청을 처리하고 오랜 기간 동안 전송 연결을 열어 둡니다.
간단한 응용 프로그램은 응답 쓰기를 마쳤을 때 전송 연결을 닫아 성능을 크게 향상시킵니다. 웹 서버는 오래 지속되는 연결에 대한 연결 수명을 제어할 필요가 있습니다.
응용 프로그램이 연결을 닫거나 연결이 닫힌 것을 발견하면 응용 프로그램은 새로운 연결을 시작합니다.
4. 관리 레코드 유형
4.1 FCGI_GET_VALUES
, FCGI_GET_VALUES_RESULT
웹 서버는 응용 프로그램 내의 특정 변수를 질의할 수 있습니다. 서버는 일반적으로 시스템 구성의 특정 측면을 자동화하기 위해 응용 프로그램 시작 시 질의를 수행합니다.
응용 프로그램은 질의를 {FCGI_GET_VALUES, 0, ...}
레코드로 수신합니다. FCGI_GET_VALUES
레코드의 contentData
부분에는 값이 비어 있는 일련의 이름-값 쌍이 포함되어 있습니다.
응용 프로그램은 제공된 값과 함께 {FCGI_GET_VALUES_RESULT, 0, ...}
레코드를 전송하여 응답합니다. 응용 프로그램이 질의에 포함된 변수 이름을 이해하지 못하는 경우 응답에서 해당 이름을 생략합니다.
FCGI_GET_VALUES
는 개방형 변수 집합을 허용하도록 설계되었습니다. 초기 집합은 서버가 응용 프로그램 및 연결 관리를 수행하는 데 도움이 되는 정보를 제공합니다:
FCGI_MAX_CONNS
: 이 응용 프로그램이 허용할 최대 동시 전송 연결 수(예:"1"
또는"10"
)입니다.FCGI_MAX_REQS
: 이 응용 프로그램이 수락할 최대 동시 요청 수(예:"1"
또는"50"
)입니다.FCGI_MPXS_CONNS
: 이 응용 프로그램이 연결을 다중화(즉, 각 연결을 통해 동시 요청을 처리)하지 않으면"0"
, 그렇지 않으면"1"
입니다.
응용 프로그램은 언제든지 FCGI_GET_VALUES
레코드를 수신할 수 있습니다. 응용 프로그램의 응답에는 응용 프로그램 자체는 관련되지 않고 FastCGI 라이브러리만 관련되어야 합니다.
4.2 FCGI_UNKNOWN_TYPE
The set of management record types is likely to grow in future versions of this protocol. To provide for this evolution, the protocol includes the FCGI_UNKNOWN_TYPE
management record. When an application receives a management record whose type T
it does not understand, the application responds with {FCGI_UNKNOWN_TYPE, 0, {T}}
.
The contentData
component of a FCGI_UNKNOWN_TYPE
record has the form:
typedef struct {
unsigned char type;
unsigned char reserved[7];
} FCGI_UnknownTypeBody;
The type
component is the type of the unrecognized management record.
5. 응용 프로그램 레코드 유형
5.1 FCGI_BEGIN_REQUEST
웹 서버는 요청을 시작하기 위해 FCGI_BEGIN_REQUEST
레코드를 전송합니다.
FCGI_BEGIN_REQUEST
레코드의 contentData
구성 요소 형식은 다음과 같습니다:
typedef struct {
unsigned char roleB1;
unsigned char roleB0;
unsigned char flags;
unsigned char reserved[5];
} FCGI_BeginRequestBody;
role
구성요소는 응용 프로그램이 수행할 것으로 웹 서버가 예상하는 역할을 설정합니다. 현재 정의된 역할은 다음과 같습니다:
FCGI_RESPONDER
FCGI_AUTHORIZER
FCGI_FILTER
역할은 아래 섹션 6에 자세히 설명되어 있습니다.
flags
구성 요소에는 연결 종료를 제어하는 비트가 포함되어 있습니다.:
flags & FCGI_KEEP_CONN
: 0이면 응용 프로그램은 이 요청에 응답한 후 연결을 닫습니다. 0이 아니면 응용 프로그램은 이 요청에 응답한 후 연결을 닫지 않습니다; 웹 서버는 연결에 대한 책임을 집니다.
5.2 이름-값 쌍 스트림: FCGI_PARAMS
FCGI_PARAMS
웹 서버에서 응용 프로그램으로 이름-값 쌍을 보내는 데 사용되는 스트림 레코드 유형입니다. 이름-값 쌍은 지정된 순서 없이 차례로 스트림으로 전송됩니다.
5.3 바이트 스트림: FCGI_STDIN
, FCGI_DATA
, FCGI_STDOUT
, FCGI_STDERR
FCGI_STDIN
FCGI_STDIN
은 웹 서버에서 응용 프로그램으로 임의의 데이터를 보내는 데 사용되는 스트림 레코드 유형입니다. FCGI_DATA
는 응용 프로그램에 추가 데이터를 보내는 데 사용되는 두 번째 스트림 레코드 유형입니다.
FCGI_STDOUT
과 FCGI_STDERR
은 응용 프로그램에서 웹 서버로 각각 임의의 데이터와 오류 데이터를 보내기 위한 스트림 레코드 유형입니다.
5.4 FCGI_ABORT_REQUEST
The Web server sends a FCGI_ABORT_REQUEST
record to abort a request. After receiving {FCGI_ABORT_REQUEST, R}
, the application responds as soon as possible with {FCGI_END_REQUEST, R, {FCGI_REQUEST_COMPLETE, appStatus}}
. This is truly a response from the application, not a low-level acknowledgement from the FastCGI library.
A Web server aborts a FastCGI request when an HTTP client closes its transport connection while the FastCGI request is running on behalf of that client. The situation may seem unlikely; most FastCGI requests will have short response times, with the Web server providing output buffering if the client is slow. But the FastCGI application may be delayed communicating with another system, or performing a server push.
웹 서버가 전송 연결을 통해 요청을 다중화하고 있지 않은 경우 웹 서버는 요청의 전송 연결을 닫아 요청을 중단할 수 있습니다. 그러나 다중화된 요청의 경우 전송 연결을 닫으면 연결에 있는 모든 요청이 중단되는 불행한 결과가 발생합니다.
5.5 FCGI_END_REQUEST
응용 프로그램이 요청을 처리했거나 응용 프로그램이 요청을 거부했기 때문에 응용 프로그램은 요청을 종료하기 위해 FCGI_END_REQUEST
레코드를 보냅니다.
FCGI_END_REQUEST
레코드의 contentData
구성 요소의 형식은 다음과 같습니다:
typedef struct {
unsigned char appStatusB3;
unsigned char appStatusB2;
unsigned char appStatusB1;
unsigned char appStatusB0;
unsigned char protocolStatus;
unsigned char reserved[3];
} FCGI_EndRequestBody;
appStatus
구성 요소는 응용 프로그램 수준의 상태 코드입니다. 각 역할은 appStatus
의 사용법을 문서화합니다.
protocolStatus
구성요소는 프로토콜 수준의 상태 코드입니다; 가능한 protocolStatus
값은 다음과 같습니다:
FCGI_REQUEST_COMPLETE
: 요청의 정상 종료.FCGI_CANT_MPX_CONN
: 새로운 요청 거부. 이는 웹 서버가 연결당 한 번에 하나의 요청을 처리하도록 설계된 응용 프로그램에 하나의 연결을 통해 동시 요청을 보낼 때 발생합니다.FCGI_OVERLOADED
: 새로운 요청 거부. 이는 응용 프로그램에 일부 리소스(예: 데이터베이스 연결)가 부족할 때 발생합니다.FCGI_UNKNOWN_ROLE
: 새 요청을 거부합니다. 이는 웹 서버가 응용프로그램에 알 수 없는 역할을 지정한 경우에 발생합니다.
6. 역할
6.1 역할 프로토콜
역할 프로토콜에는 응용 프로그램 레코드 유형이 있는 레코드만 포함됩니다. 기본적으로 스트림을 사용하여 모든 데이터를 전송합니다.
프로토콜을 신뢰할 수 있게 만들고 응용 프로그래밍을 단순화하기 위해 역할 프로토콜은 거의 순차적인 마샬링을 사용하도록 설계되었습니다. 엄격하게 순차적인 마샬링을 사용하는 프로토콜에서 응용 프로그램은 첫 번째 입력을 받은 다음 두 번째 입력 등을 모두 받을 때까지 받습니다. 마찬가지로 응용 프로그램은 첫 번째 출력을 보낸 다음 두 번째 출력 등을 모두 보낼 때까지 보냅니다. 입력은 서로 인터리브되지 않으며 출력은 서로 인터리브되지 않습니다.
CGI 프로그램은 타이밍 제한 없이 stdout
과 stderr
모두에 쓸 수 있기 때문에 순차적인 마샬링 규칙은 일부 FastCGI 역할에 대해 너무 제한적입니다. 따라서 FCGI_STDOUT
과 FCGI_STDERR
을 모두 사용하는 역할 프로토콜은 이들 두 스트림이 인터리브될 수 있도록 허용합니다.
모든 역할 프로토콜은 기존 응용 프로그래밍에서 단지 stderr
이 사용되는 방식으로, 즉 응용 프로그램 수준의 오류를 이해할 수 있는 방식으로 보고하기 위해, FCGI_STDERR
스트림을 사용합니다. FCGI_STDERR
스트림 사용은 항상 선택 사항입니다. 응용 프로그램은 보고할 오류가 없으면 FCGI_STDERR
레코드를 보내지 않거나 길이가 0인 FCGI_STDERR
레코드 1개를 보냅니다.
역할 프로토콜이 FCGI_STDERR
이외의 스트림 전송을 요구할 때 스트림이 비어 있더라도 스트림 유형의 레코드가 적어도 1개는 항상 전송됩니다.
다시 말하지만, 신뢰할 수 있는 프로토콜과 단순화된 응용 프로그래밍을 위해 역할 프로토콜은 거의 요청-응답이 되도록 설계되었습니다. 진정한 요청-응답 프로토콜에서 응용 프로그램은 첫 번째 출력 레코드를 보내기 전에 모든 입력 레코드를 받습니다. 요청-응답 프로토콜은 파이프라이닝을 허용하지 않습니다.
요청-응답 규칙은 일부 FastCGI 역할에 대해 너무 제한적입니다; 결국, CGI 프로그램은 stdout
을 쓰기 시작하기 전에 stdin
을 모두 읽도록 제한되지 않습니다. 따라서 일부 역할 프로토콜은 이러한 특정 가능성을 허용합니다. 먼저 응용 프로그램은 최종 스트림 입력을 제외한 모든 입력을 받습니다. 응용 프로그램이 최종 스트림 입력을 받기 시작하면 출력 쓰기를 시작할 수 있습니다.
역할 프로토콜이 FCGI_PARAMS
를 사용하여 CGI 프로그램이 환경 변수에서 얻는 값과 같은 텍스트 값을 전송할 때 값의 길이에는 종료 널 바이트가 포함되지 않으며 값 자체에는 널 바이트가 포함되지 않습니다. Environ(7)
형식 이름-값 쌍을 제공해야 하는 응용 프로그램은 이름과 값 사이에 등호를 삽입하고 값 뒤에 널 바이트를 추가해야 합니다.
역할 프로토콜은 CGI의 구문 분석되지 않은 헤더 기능을 지원하지 않습니다. FastCGI 응용 프로그램은 Status
및 Location
CGI 헤더를 사용하여 응답 상태를 설정합니다.
6.2 응답자
응답자 FastCGI 응용 프로그램은 CGI/1.1 프로그램과 동일한 목적을 가지고 있습니다: HTTP 요청과 관련된 모든 정보를 수신하고 HTTP 응답을 생성합니다.
CGI/1.1의 각 요소가 응답자에 의해 어떻게 에뮬레이션되는지 설명하는 것으로 충분합니다:
- 응답자 응용 프로그램은
FCGI_PARAMS
를 통해 웹 서버로부터 CGI/1.1 환경 변수를 받습니다. - 다음으로 응답자 응용 프로그램은
FCGI_STDIN
을 통해 웹 서버로부터 CGI/1.1stdin
데이터를 받습니다. 응용 프로그램은 스트림 끝 표시를 받기 전에 이 스트림에서 많아야CONTENT_LENGTH
바이트를 받습니다. (HTTP 클라이언트가 이를 제공하지 못하는 경우(예: 클라이언트 충돌)에만 응용 프로그램은CONTENT_LENGTH
바이트 미만을 받습니다.) - 응답자 응용 프로그램은
FCGI_STDOUT
을 통해 CGI/1.1stdout
데이터를 웹 서버로 보내고,FCGI_STDERR
을 통해 CGI/1.1stderr
데이터를 보냅니다. 응용 프로그램은 이를 하나씩 차례로 보내는 것이 아니라 동시에 보냅니다. 응용 프로그램은FCGI_STDOUT
및FCGI_STDERR
쓰기를 시작하기 전에FCGI_PARAMS
읽기가 완료될 때까지 기다려야 하지만 이 두 스트림 쓰기를 시작하기 전에FCGI_STDIN
읽기를 완료할 필요는 없습니다. - 응답자 응용 프로그램은
stdout
및stderr
데이터를 모두 보낸 후FCGI_END_REQUEST
레코드를 보냅니다. 응용 프로그램은protocolStatus
구성 요소를FCGI_REQUEST_COMPLETE
로 설정하고appStatus
구성 요소를exit
시스템 호출을 통해 CGI 프로그램이 반환했을 상태 코드로 설정합니다.
업데이트를 수행하는 응답자(예: POST
메서드 구현)는 FCGI_STDIN
에서 받은 바이트 수를 CONTENT_LENGTH
와 비교하고 두 숫자가 같지 않으면 업데이트를 중단해야 합니다.
6.3 Authorizer
An Authorizer FastCGI application receives all the information associated with an HTTP request and generates an authorized/unauthorized decision. In case of an authorized decision the Authorizer can also associate name-value pairs with the HTTP request; when giving an unauthorized decision the Authorizer sends a complete response to the HTTP client.
Since CGI/1.1 defines a perfectly good way to represent the information associated with an HTTP request, Authorizers use the same representation:
- The Authorizer application receives HTTP request information from the Web server on the
FCGI_PARAMS
stream, in the same format as a Responder. The Web server does not sendCONTENT_LENGTH
,PATH_INFO
,PATH_TRANSLATED
, andSCRIPT_NAME
headers. -
The Authorizer application sends
stdout
andstderr
data in the same manner as a Responder. The CGI/1.1 response status specifies the disposition of the request. If the application sends status 200 (OK), the Web server allows access. Depending upon its configuration the Web server may proceed with other access checks, including requests to other Authorizers.An Authorizer application’s 200 response may include headers whose names are prefixed with
Variable-
. These headers communicate name-value pairs from the application to the Web server. For instance, the response headerVariable-AUTH_METHOD: database lookup
transmits the value
"database lookup"
with nameAUTH-METHOD
. The server associates such name-value pairs with the HTTP request and includes them in subsequent CGI or FastCGI requests performed in processing the HTTP request. When the application gives a 200 response, the server ignores response headers whose names aren’t prefixed withVariable-
prefix, and ignores any response content.For Authorizer response status values other than “200” (OK), the Web server denies access and sends the response status, headers, and content back to the HTTP client.
6.4 Filter
A Filter FastCGI application receives all the information associated with an HTTP request, plus an extra stream of data from a file stored on the Web server, and generates a “filtered” version of the data stream as an HTTP response.
A Filter is similar in functionality to a Responder that takes a data file as a parameter. The difference is that with a Filter, both the data file and the Filter itself can be access controlled using the Web server’s access control mechanisms, while a Responder that takes the name of a data file as a parameter must perform its own access control checks on the data file.
The steps taken by a Filter are similar to those of a Responder. The server presents the Filter with environment variables first, then standard input (normally form POST
data), finally the data file input:
- Like a Responder, the Filter application receives name-value pairs from the Web server over
FCGI_PARAMS
. Filter applications receive two Filter-specific variables:FCGI_DATA_LAST_MOD
andFCGI_DATA_LENGTH
. - Next the Filter application receives CGI/1.1
stdin
data from the Web server overFCGI_STDIN
. The application receives at mostCONTENT_LENGTH
bytes from this stream before receiving the end-of-stream indication. (The application receives less thanCONTENT_LENGTH
bytes only if the HTTP client fails to provide them, e.g. because the client crashed.) - Next the Filter application receives the file data from the Web server over
FCGI_DATA
. This file’s last modification time (expressed as an integer number of seconds since the epoch January 1, 1970 UTC) isFCGI_DATA_LAST_MOD
; the application may consult this variable and respond from a cache without reading the file data. The application reads at mostFCGI_DATA_LENGTH
bytes from this stream before receiving the end-of-stream indication. - The Filter application sends CGI/1.1
stdout
data to the Web server overFCGI_STDOUT
, and CGI/1.1stderr
data overFCGI_STDERR
. The application sends these concurrently, not one after the other. The application must wait to finish readingFCGI_STDIN
before it begins writingFCGI_STDOUT
andFCGI_STDERR
, but it needn’t finish reading fromFCGI_DATA
before it begins writing these two streams. - After sending all its
stdout
andstderr
data, the application sends aFCGI_END_REQUEST
record. The application sets theprotocolStatus
component toFCGI_REQUEST_COMPLETE
and theappStatus
component to the status code that a similar CGI program would have returned via theexit
system call.
A Filter should compare the number of bytes received on FCGI_STDIN
with CONTENT_LENGTH
and on FCGI_DATA
with FCGI_DATA_LENGTH
. If the numbers don’t match and the Filter is a query, the Filter response should provide an indication that data is missing. If the numbers don’t match and the Filter is an update, the Filter should abort the update.
7. Errors
A FastCGI application exits with zero status to indicate that it terminated on purpose, e.g. in order to perform a crude form of garbage collection. A FastCGI application that exits with nonzero status is assumed to have crashed. How a Web server or other application manager responds to applications that exit with zero or nonzero status is outside the scope of this specification.
A Web server can request that a FastCGI application exit by sending it SIGTERM
. If the application ignores SIGTERM
the Web server can resort to SIGKILL
.
FastCGI applications report application-level errors with the FCGI_STDERR
stream and the appStatus
component of the FCGI_END_REQUEST
record. In many cases an error will be reported directly to the user via the FCGI_STDOUT
stream.
On Unix, applications report lower-level errors, including FastCGI protocol errors and syntax errors in FastCGI environment variables, to syslog
. Depending upon the severity of the error, the application may either continue or exit with nonzero status.
8. Types and Constants
/*
* Listening socket file number
*/
#define FCGI_LISTENSOCK_FILENO 0
typedef struct {
unsigned char version;
unsigned char type;
unsigned char requestIdB1;
unsigned char requestIdB0;
unsigned char contentLengthB1;
unsigned char contentLengthB0;
unsigned char paddingLength;
unsigned char reserved;
} FCGI_Header;
/*
* Number of bytes in a FCGI_Header. Future versions of the protocol
* will not reduce this number.
*/
#define FCGI_HEADER_LEN 8
/*
* Value for version component of FCGI_Header
*/
#define FCGI_VERSION_1 1
/*
* Values for type component of FCGI_Header
*/
#define FCGI_BEGIN_REQUEST 1
#define FCGI_ABORT_REQUEST 2
#define FCGI_END_REQUEST 3
#define FCGI_PARAMS 4
#define FCGI_STDIN 5
#define FCGI_STDOUT 6
#define FCGI_STDERR 7
#define FCGI_DATA 8
#define FCGI_GET_VALUES 9
#define FCGI_GET_VALUES_RESULT 10
#define FCGI_UNKNOWN_TYPE 11
#define FCGI_MAXTYPE (FCGI_UNKNOWN_TYPE)
/*
* FCGI_Header의 requestId 구성 요소에 대한 값
*/
#define FCGI_NULL_REQUEST_ID 0
typedef struct {
unsigned char roleB1;
unsigned char roleB0;
unsigned char flags;
unsigned char reserved[5];
} FCGI_BeginRequestBody;
typedef struct {
FCGI_Header header;
FCGI_BeginRequestBody body;
} FCGI_BeginRequestRecord;
/*
* FCGI_BeginRequestBody의 flags 구성 요소에 대한 마스크
*/
#define FCGI_KEEP_CONN 1
/*
* FCGI_BeginRequestBody의 역할 구성 요소에 대한 값
*/
#define FCGI_RESPONDER 1
#define FCGI_AUTHORIZER 2
#define FCGI_FILTER 3
typedef struct {
unsigned char appStatusB3;
unsigned char appStatusB2;
unsigned char appStatusB1;
unsigned char appStatusB0;
unsigned char protocolStatus;
unsigned char reserved[3];
} FCGI_EndRequestBody;
typedef struct {
FCGI_Header header;
FCGI_EndRequestBody body;
} FCGI_EndRequestRecord;
/*
* FCGI_EndRequestBody의 protocolStatus 구성 요소에 대한 값
*/
#define FCGI_REQUEST_COMPLETE 0
#define FCGI_CANT_MPX_CONN 1
#define FCGI_OVERLOADED 2
#define FCGI_UNKNOWN_ROLE 3
/*
* FCGI_GET_VALUES / FCGI_GET_VALUES_RESULT records에 대한 변수 이름
*/
#define FCGI_MAX_CONNS "FCGI_MAX_CONNS"
#define FCGI_MAX_REQS "FCGI_MAX_REQS"
#define FCGI_MPXS_CONNS "FCGI_MPXS_CONNS"
typedef struct {
unsigned char type;
unsigned char reserved[7];
} FCGI_UnknownTypeBody;
typedef struct {
FCGI_Header header;
FCGI_UnknownTypeBody body;
} FCGI_UnknownTypeRecord;
9. 참고 문헌
A. 표: 레코드 유형의 속성
다음 차트는 모든 레코드 유형을 나열하며 각 레코드의 속성을 나타냅니다:
WS->App
: 이 유형의 레코드는 웹 서버에서만 응용 프로그램으로 보낼 수 있습니다. 다른 유형의 레코드는 응용 프로그램에서만 웹 서버로 보낼 수 있습니다.관리
: 이 유형의 레코드에는 웹 서버 요청에 국한되지 않은 정보가 포함되어 있으며 null 요청 ID를 사용합니다. 다른 유형의 레코드에는 요청별 정보가 포함되어 있으며 null 요청 ID를 사용할 수 없습니다.스트림
: 이 유형의 레코드는 스트림을 형성하며, 빈contentData
가 있는 레코드로 종료됩니다. 다른 유형의 레코드들은 별개입니다; 각각은 의미 있는 데이터 단위를 전달합니다.
WS->App 관리 스트림
FCGI_GET_VALUES x x
FCGI_GET_VALUES_RESULT x
FCGI_UNKNOWN_TYPE x
FCGI_BEGIN_REQUEST x
FCGI_ABORT_REQUEST x
FCGI_END_REQUEST
FCGI_PARAMS x x
FCGI_STDIN x x
FCGI_DATA x x
FCGI_STDOUT x
FCGI_STDERR x
B. 전형적인 프로토콜 메시지 흐름
예시에 대한 추가적인 표기 규칙:
- 스트림 레코드 (
FCGI_PARAMS
,FCGI_STDIN
,FCGI_STDOUT
및FCGI_STDERR
)의contentData
는 문자열로 표현됩니다." ... "
로 끝나는 문자열은 표시하기에 너무 길어서 접두사만 표시됩니다. - 웹 서버로 보낸 메시지는 웹 서버로부터 받은 메시지에 맞춰 들여쓰기됩니다.
- 메시지는 응용 프로그램에서 경험한 시간 순서대로 표시됩니다.
1. stdin
에 대한 데이터가 없는 간단한 요청과 성공적인 응답::
{FCGI_BEGIN_REQUEST, 1, {FCGI_RESPONDER, 0}}
{FCGI_PARAMS, 1, "\013\002SERVER_PORT80\013\016SERVER_ADDR199.170.183.42 ... "}
{FCGI_PARAMS, 1, ""}
{FCGI_STDIN, 1, ""}
{FCGI_STDOUT, 1, "Content-type: text/html\r\n\r\n<html>\n<head> ... "}
{FCGI_STDOUT, 1, ""}
{FCGI_END_REQUEST, 1, {0, FCGI_REQUEST_COMPLETE}}
2. 예시 1과 유사하지만 이번에는 stdin
에 대한 데이터가 있습니다. 웹 서버는 이전보다 더 많은 FCGI_PARAMS
레코드를 사용하여 매개변수를 전송하도록 선택합니다:
{FCGI_BEGIN_REQUEST, 1, {FCGI_RESPONDER, 0}}
{FCGI_PARAMS, 1, "\013\002SERVER_PORT80\013\016SER"}
{FCGI_PARAMS, 1, "VER_ADDR199.170.183.42 ... "}
{FCGI_PARAMS, 1, ""}
{FCGI_STDIN, 1, "quantity=100&item=3047936"}
{FCGI_STDIN, 1, ""}
{FCGI_STDOUT, 1, "Content-type: text/html\r\n\r\n<html>\n<head> ... "}
{FCGI_STDOUT, 1, ""}
{FCGI_END_REQUEST, 1, {0, FCGI_REQUEST_COMPLETE}}
3. Similar to example 1, but this time the application detects an error. The application logs a message to stderr
, returns a page to the client, and returns non-zero exit status to the Web server. The application chooses to send the page using more FCGI_STDOUT
records:
{FCGI_BEGIN_REQUEST, 1, {FCGI_RESPONDER, 0}}
{FCGI_PARAMS, 1, "\013\002SERVER_PORT80\013\016SERVER_ADDR199.170.183.42 ... "}
{FCGI_PARAMS, 1, ""}
{FCGI_STDIN, 1, ""}
{FCGI_STDOUT, 1, "Content-type: text/html\r\n\r\n<ht"}
{FCGI_STDERR, 1, "config error: missing SI_UID\n"}
{FCGI_STDOUT, 1, "ml>\n<head> ... "}
{FCGI_STDOUT, 1, ""}
{FCGI_STDERR, 1, ""}
{FCGI_END_REQUEST, 1, {938, FCGI_REQUEST_COMPLETE}}
4. 예시 1의 두 개의 인스턴스가 단일 연결로 다중화되었습니다. 첫 번째 요청이 두 번째 요청보다 더 까다로워, 응용 프로그램은 순서에 관계없이 요청을 완료합니다:
{FCGI_BEGIN_REQUEST, 1, {FCGI_RESPONDER, FCGI_KEEP_CONN}}
{FCGI_PARAMS, 1, "\013\002SERVER_PORT80\013\016SERVER_ADDR199.170.183.42 ... "}
{FCGI_PARAMS, 1, ""}
{FCGI_BEGIN_REQUEST, 2, {FCGI_RESPONDER, FCGI_KEEP_CONN}}
{FCGI_PARAMS, 2, "\013\002SERVER_PORT80\013\016SERVER_ADDR199.170.183.42 ... "}
{FCGI_STDIN, 1, ""}
{FCGI_STDOUT, 1, "Content-type: text/html\r\n\r\n"}
{FCGI_PARAMS, 2, ""}
{FCGI_STDIN, 2, ""}
{FCGI_STDOUT, 2, "Content-type: text/html\r\n\r\n<html>\n<head> ... "}
{FCGI_STDOUT, 2, ""}
{FCGI_END_REQUEST, 2, {0, FCGI_REQUEST_COMPLETE}}
{FCGI_STDOUT, 1, "<html>\n<head> ... "}
{FCGI_STDOUT, 1, ""}
{FCGI_END_REQUEST, 1, {0, FCGI_REQUEST_COMPLETE}}
© 1995, 1996 Open Market, Inc. / Mark R. Brown