├── .gitignore
├── FastCGI.groupproj
├── LICENSE
├── NGINX
├── NGINX.FCGIApplication.pas
├── NGINX.FCGIConstants.pas
├── NGINX.FCGIRecord.pas
├── NGINX.FCGIRequest.pas
├── NGINX.FCGIResponse.pas
├── NGINX.FCGIStream.pas
├── NGINX.FastCGI.dpr
├── NGINX.FastCGI.dproj
├── NGINX.FastCGI.res
├── NGINX.WebModule.pas
└── ServerConst1.pas
└── README.md
/.gitignore:
--------------------------------------------------------------------------------
1 | # Uncomment these types if you want even more clean repository. But be careful.
2 | # It can make harm to an existing project source. Read explanations below.
3 | #
4 | # Resource files are binaries containing manifest, project icon and version info.
5 | # They can not be viewed as text or compared by diff-tools. Consider replacing them with .rc files.
6 | #*.res
7 | #
8 | # Type library file (binary). In old Delphi versions it should be stored.
9 | # Since Delphi 2009 it is produced from .ridl file and can safely be ignored.
10 | #*.tlb
11 | #
12 | # Diagram Portfolio file. Used by the diagram editor up to Delphi 7.
13 | # Uncomment this if you are not using diagrams or use newer Delphi version.
14 | #*.ddp
15 | #
16 | # Visual LiveBindings file. Added in Delphi XE2.
17 | # Uncomment this if you are not using LiveBindings Designer.
18 | #*.vlb
19 | #
20 | # Deployment Manager configuration file for your project. Added in Delphi XE2.
21 | # Uncomment this if it is not mobile development and you do not use remote debug feature.
22 | #*.deployproj
23 | #
24 | # C++ object files produced when C/C++ Output file generation is configured.
25 | # Uncomment this if you are not using external objects (zlib library for example).
26 | #*.obj
27 | #
28 |
29 | # Delphi compiler-generated binaries (safe to delete)
30 | *.exe
31 | *.dll
32 | *.bpl
33 | *.bpi
34 | *.dcp
35 | *.so
36 | *.apk
37 | *.drc
38 | *.map
39 | *.dres
40 | *.rsm
41 | *.tds
42 | *.dcu
43 | *.lib
44 | *.a
45 | *.o
46 | *.ocx
47 |
48 | # Delphi autogenerated files (duplicated info)
49 | *.cfg
50 | *.hpp
51 | *Resource.rc
52 |
53 | # Delphi local files (user-specific info)
54 | *.local
55 | *.identcache
56 | *.projdata
57 | *.tvsconfig
58 | *.dsk
59 |
60 | # Delphi history and backups
61 | __history/
62 | __recovery/
63 | *.~*
64 |
65 | # Castalia statistics file (since XE7 Castalia is distributed with Delphi)
66 | *.stat
67 |
68 | # Boss dependency manager vendor folder https://github.com/HashLoad/boss
69 | modules/
70 |
--------------------------------------------------------------------------------
/FastCGI.groupproj:
--------------------------------------------------------------------------------
1 |
2 |
3 | {C0C5E5EC-B9E0-40D7-A567-96FBE60BB5F7}
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 | Default.Personality.12
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 2020 kylixfans
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
22 |
--------------------------------------------------------------------------------
/NGINX/NGINX.FCGIApplication.pas:
--------------------------------------------------------------------------------
1 | unit NGINX.FCGIApplication;
2 |
3 | ///
4 | /// Main FastCGI listener class.
5 | ///
6 | ///
7 | ///
8 | /// This class manages a connection to a webserver by listening on a given port on localhost and receiving FastCGI
9 | /// requests by webserver nginx.
10 | ///
11 | /// In FastCGI terms, this class implements the responder role. Refer to section 6.2 of the FastCGI specification
12 | /// for details.
13 | ///
14 | /// Use to get notified of received requests. You can call to
15 | /// enter an infinite loopand let the app handle everything.
16 | /// Alternatively, if you want to control the execution flow by yourself, call to start
17 | /// accepting connections. Then repeatedly call to handle incoming requests.
18 | ///
19 | /// If you want to manage the socket connection details by yourself, or for testing purposes,
20 | /// you can also call instead of any of the above methods.
21 | ///
22 | /// See the below example to learn how to accept requests.
23 | /// For more detailed information, have a look at the class.
24 | ///
25 | /// If you need to fiddle with the FastCGI packets itself, see the class and read the
26 | /// [FastCGI specification](http://www.fastcgi.com/devkit/doc/fcgi-spec.html).
27 | ///
28 |
29 | interface
30 |
31 | uses
32 | System.SysUtils, System.Generics.Collections, System.Classes,
33 | NGINX.FCGIRequest, NGINX.FCGIStream, NGINX.FCGIRecord,
34 | NGINX.FCGIConstants,
35 | IdBaseComponent, IdComponent, IdCustomTCPServer, IdSocksServer, IdTCPServer,
36 | IdContext, IdGlobal, NGINX.FCGIResponse;
37 |
38 | const
39 | _Timeout = 5000;
40 |
41 | type
42 | TFCGIRequestIncoming = procedure(const sender: TObject;
43 | const Request: TFCGIRequest) of object;
44 | TFCGIRequestReceived = procedure(const sender: TObject;
45 | const Request: TFCGIRequest; Response: TFCGIResponse) of object;
46 |
47 | {$M+}
48 |
49 | TFCGIApplication = class
50 | private
51 | FOnRequestReceived: TFCGIRequestReceived;
52 | FOnRequestIncoming: TFCGIRequestIncoming;
53 | FTimeout: Integer;
54 | FListeningSocket: TIdTCPServer;
55 | ///
56 | /// A dictionary of all open TFCGIRequest, indexed by the FastCGI request id.
57 | ///
58 | Requests: TDictionary;
59 | FDefaultPort: Integer;
60 | function GetConnected: Boolean;
61 | procedure SetTimeout(const Value: Integer);
62 | function GetTimeout: Integer;
63 | procedure StopListening;
64 | procedure FCGIExecute(AContext: TIdContext);
65 | procedure SetDefaultPort(const Value: Integer);
66 | procedure SetActive(const Value: Boolean);
67 | function GetVersion: string;
68 | protected
69 | property ListeningSocket: TIdTCPServer read FListeningSocket;
70 | published
71 | property Active: Boolean read GetConnected write SetActive;
72 | property Timeout: Integer read GetTimeout write SetTimeout;
73 | property DefaultPort: Integer read FDefaultPort write SetDefaultPort;
74 | property Version: string read GetVersion;
75 | ///
76 | /// Will be called when a request has been fully received.
77 | ///
78 | property OnRequestReceived: TFCGIRequestReceived read FOnRequestReceived
79 | write FOnRequestReceived;
80 | ///
81 | /// Will be called when a new request is incoming, before it has been fully received.
82 | ///
83 | property OnRequestIncoming: TFCGIRequestIncoming read FOnRequestIncoming
84 | write FOnRequestIncoming;
85 | public
86 | constructor Create;
87 | destructor Destory;
88 | procedure Run(port: Integer);
89 | end;
90 |
91 | implementation
92 |
93 | { TFCGIApplication }
94 |
95 | function TFCGIApplication.GetConnected: Boolean;
96 | begin
97 | Result := FListeningSocket.Active;
98 | end;
99 |
100 | ///
101 | /// The read/write timeouts in miliseconds for the listening socket, the connections, and the streams.
102 | ///
103 | /// Zero or -1 mean infinite timeout.
104 | function TFCGIApplication.GetTimeout: Integer;
105 | begin
106 | if FTimeout = 0 then
107 | begin
108 | FTimeout := _Timeout;
109 | end;
110 | Result := FTimeout;
111 | end;
112 |
113 | function TFCGIApplication.GetVersion: string;
114 | begin
115 | Result := FListeningSocket.Version;
116 | end;
117 |
118 | ///
119 | /// Starts listening for connections on the given port.
120 | ///
121 | ///
122 | /// Will only accept connections from localhost.
123 | ///
124 | procedure TFCGIApplication.Run(port: Integer);
125 | begin
126 | FListeningSocket.DefaultPort := port;
127 | FListeningSocket.Active := True;
128 | end;
129 |
130 | constructor TFCGIApplication.Create;
131 | begin
132 | Requests := TDictionary.Create;
133 | FListeningSocket := TIdTCPServer.Create(nil);
134 | FListeningSocket.OnExecute := FCGIExecute;
135 | end;
136 |
137 | destructor TFCGIApplication.Destory;
138 | begin
139 | StopListening;
140 | Requests.Free;
141 | FListeningSocket.Free;
142 | end;
143 |
144 | ///
145 | /// Tries to read and handle a from inputStream and writes responses to outputStream.
146 | ///
147 | procedure TFCGIApplication.FCGIExecute(AContext: TIdContext);
148 | var
149 | req: TFCGIRequest;
150 | Response: TFCGIResponse;
151 | r: TFCGIRecord;
152 | role: Integer;
153 | flags: Byte;
154 | keepAlive: Boolean;
155 | ValuesResultStream: TFCGIStream;
156 | begin
157 | with AContext.Connection do
158 | begin
159 | IOHandler.ReadTimeout := GetTimeout;
160 | // if not IOHandler.Readable(0) then
161 | // begin
162 | // Exit;
163 | // end;
164 | r := TFCGIRecord.Create(IOHandler);
165 | end;
166 | try
167 | r.ReadRecord;
168 | if r.RecordType = TRecordType.BeginRequest then
169 | begin
170 | if Requests.ContainsKey(r.RequestId) then
171 | begin
172 | Requests.Remove(r.RequestId);
173 | end;
174 | BeginRequestData(r.ContentData, role, flags);
175 | if (flags and FCGI_KEEP_CONN) <> 0 then
176 | keepAlive := True
177 | else
178 | keepAlive := False;
179 |
180 | req := TFCGIRequest.Create(r.RequestId, AContext.Connection.IOHandler,
181 | keepAlive);
182 | Requests.Add(r.RequestId, req);
183 | if Assigned(FOnRequestIncoming) then
184 | FOnRequestIncoming(Self, req);
185 | end
186 | else if (r.RecordType = TRecordType.AbortRequest) or
187 | (r.RecordType = TRecordType.EndRequest) then
188 | begin
189 | Requests.Remove(r.RequestId);
190 | end
191 | else if r.RecordType = TRecordType.GetValues then
192 | begin
193 | ValuesResultStream := TFCGIStream.Create(0);
194 | try
195 | ValuesResultStream.ValuesResult(1, 1, False);
196 | ValuesResultStream.stream.Position := 0;
197 | AContext.Connection.IOHandler.Write(ValuesResultStream.stream,
198 | ValuesResultStream.StreamLength);
199 | AContext.Connection.IOHandler.Close;
200 | finally
201 | ValuesResultStream.Free;
202 | end;
203 | end
204 | else
205 | begin
206 | if Requests.ContainsKey(r.RequestId) then
207 | begin
208 | req := Requests[r.RequestId];
209 | if req.HandleRecord(r) then
210 | begin
211 | if Assigned(FOnRequestReceived) then
212 | begin
213 | Response := TFCGIResponse.Create(r.RequestId,
214 | AContext.Connection.IOHandler);
215 | try
216 | FOnRequestReceived(Self, req, Response);
217 | if not Response.IsClose then
218 | begin
219 | Response.Flush;
220 | end;
221 | finally
222 | Response.Free;
223 | end;
224 | end;
225 | with AContext.Connection do
226 | begin
227 | IOHandler.Close;
228 | if not req.keepAlive then
229 | begin
230 | AContext.Connection.Disconnect;
231 | end;
232 | end;
233 | Requests.Remove(r.RequestId);
234 | end;
235 | end;
236 | end;
237 | finally
238 | r.Free;
239 | end;
240 | end;
241 |
242 | ///
243 | /// True iff this application is currently connected to a webserver.
244 | ///
245 | procedure TFCGIApplication.SetActive(const Value: Boolean);
246 | begin
247 | FListeningSocket.Active := Value;
248 | end;
249 |
250 | procedure TFCGIApplication.SetDefaultPort(const Value: Integer);
251 | begin
252 | FDefaultPort := Value;
253 | FListeningSocket.DefaultPort := FDefaultPort;
254 | end;
255 |
256 | procedure TFCGIApplication.SetTimeout(const Value: Integer);
257 | begin
258 | FTimeout := Value;
259 | end;
260 |
261 | ///
262 | /// Stops listening for incoming connections.
263 | ///
264 | procedure TFCGIApplication.StopListening;
265 | begin
266 | if FListeningSocket <> nil then
267 | begin
268 | FListeningSocket.Active := False;
269 | end;
270 | end;
271 |
272 | end.
273 |
--------------------------------------------------------------------------------
/NGINX/NGINX.FCGIConstants.pas:
--------------------------------------------------------------------------------
1 | unit NGINX.FCGIConstants;
2 |
3 | ///
4 | /// Constants defined in the FastCGI spec.
5 | ///
6 |
7 | interface
8 |
9 | const
10 | ///
11 | /// Listening socket file number
12 | ///
13 | FCGI_LISTENSOCK_FILENO = 0;
14 |
15 | ///
16 | /// Number of bytes in a FCGI_Header.
17 | /// Future versions of the protocol will not reduce this number.
18 | ///
19 | FCGI_HEADER_LEN = 8;
20 |
21 | ///
22 | /// Value for version component of FCGI_Header
23 | ///
24 | FCGI_VERSION_1 = 1;
25 |
26 | ///
27 | /// Values for type component of FCGI_Header
28 | ///
29 | FCGI_BEGIN_REQUEST = 1;
30 | ///
31 | /// Values for type component of FCGI_Header
32 | ///
33 | FCGI_ABORT_REQUEST = 2;
34 | ///
35 | /// Values for type component of FCGI_Header
36 | ///
37 | FCGI_END_REQUEST = 3;
38 | ///
39 | /// Values for type component of FCGI_Header
40 | ///
41 | FCGI_PARAMS = 4;
42 | ///
43 | /// Values for type component of FCGI_Header
44 | ///
45 | FCGI_STDIN = 5;
46 | ///
47 | /// Values for type component of FCGI_Header
48 | ///
49 | FCGI_STDOUT = 6;
50 | ///
51 | /// Values for type component of FCGI_Header
52 | ///
53 | FCGI_STDERR = 7;
54 | ///
55 | /// Values for type component of FCGI_Header
56 | ///
57 | FCGI_DATA = 8;
58 | ///
59 | /// Values for type component of FCGI_Header
60 | ///
61 | FCGI_GET_VALUES = 9;
62 | ///
63 | /// Values for type component of FCGI_Header
64 | ///
65 | FCGI_GET_VALUES_RESULT = 10;
66 | ///
67 | /// Values for type component of FCGI_Header
68 | ///
69 | FCGI_UNKNOWN_TYPE = 11;
70 | ///
71 | /// Values for type component of FCGI_Header
72 | ///
73 | FCGI_MAXTYPE = FCGI_UNKNOWN_TYPE;
74 |
75 | ///
76 | /// Value for requestId component of FCGI_Header
77 | ///
78 | FCGI_NULL_REQUEST_ID = 0;
79 |
80 | ///
81 | /// Mask for flags component of FCGI_BeginRequestBody
82 | ///
83 | FCGI_KEEP_CONN = 1;
84 |
85 | ///
86 | /// Values for role component of FCGI_BeginRequestBody
87 | ///
88 | FCGI_RESPONDER = 1;
89 | ///
90 | /// Values for role component of FCGI_BeginRequestBody
91 | ///
92 | FCGI_AUTHORIZER = 2;
93 | ///
94 | /// Values for role component of FCGI_BeginRequestBody
95 | ///
96 | FCGI_FILTER = 3;
97 |
98 | ///
99 | /// Values for protocolStatus component of FCGI_EndRequestBody
100 | ///
101 | FCGI_REQUEST_COMPLETE = 0;
102 | ///
103 | /// Values for protocolStatus component of FCGI_EndRequestBody
104 | ///
105 | FCGI_CANT_MPX_CONN = 1;
106 | ///
107 | /// Values for protocolStatus component of FCGI_EndRequestBody
108 | ///
109 | FCGI_OVERLOADED = 2;
110 | ///
111 | /// Values for protocolStatus component of FCGI_EndRequestBody
112 | ///
113 | FCGI_UNKNOWN_ROLE = 3;
114 |
115 | ///
116 | /// Variable names for FCGI_GET_VALUES / FCGI_GET_VALUES_RESULT records
117 | ///
118 | FCGI_MAX_CONNS = 'FCGI_MAX_CONNS';
119 | ///
120 | /// Variable names for FCGI_GET_VALUES / FCGI_GET_VALUES_RESULT records
121 | ///
122 | FCGI_MAX_REQS = 'FCGI_MAX_REQS';
123 | ///
124 | /// Variable names for FCGI_GET_VALUES / FCGI_GET_VALUES_RESULT records
125 | ///
126 | FCGI_MPXS_CONNS = 'FCGI_MPXS_CONNS';
127 |
128 | implementation
129 |
130 | end.
131 |
--------------------------------------------------------------------------------
/NGINX/NGINX.FCGIRecord.pas:
--------------------------------------------------------------------------------
1 | unit NGINX.FCGIRecord;
2 |
3 | ///
4 | /// A FastCGI Record.
5 | ///
6 | ///
7 | /// See section 3.3 of the FastCGI Specification for details.
8 | ///
9 | ///
10 | interface
11 |
12 | uses
13 | System.SysUtils, System.Classes, NGINX.FCGIConstants, IdIOHandler, IdGlobal,
14 | System.Generics.Collections, System.StrUtils;
15 |
16 | type
17 | ///
18 | /// Record types, used in the 'type' field of Record.
19 | ///
20 | ///
21 | /// Described in the FastCGI Specification section 8.
22 | ///
23 | TRecordType = (BeginRequest = FCGI_BEGIN_REQUEST, AbortRequest, EndRequest,
24 | Params, Stdin, Stdout, Stderr, Data, GetValues, GetValuesResult,
25 | UnknownType = FCGI_UNKNOWN_TYPE, MaxType = FCGI_MAXTYPE);
26 | ///
27 | /// Protocol status used for requests.
28 | /// Described in the FastCGI Specification section 8.
29 | ///
30 | TProtocolStatus = (RequestComplete = FCGI_REQUEST_COMPLETE,
31 | CantMpxConn = FCGI_CANT_MPX_CONN, Overloaded = FCGI_OVERLOADED,
32 | UnknownRole = FCGI_UNKNOWN_ROLE);
33 |
34 | {$M+}
35 |
36 | TFCGIRecord = class
37 | private
38 | FIO: TIdIOHandler;
39 | FVersion: Byte;
40 | FRecordType: TRecordType;
41 | FRequestId: Integer;
42 | FContentLength: Integer;
43 | FContentData: TMemoryStream;
44 | procedure ReadBytes(len: Integer);
45 | function ReadInt16: UInt16;
46 | function ReadByte: Byte;
47 | procedure ReadContent(len: Integer);
48 | published
49 | ///
50 | /// The version byte. Should always equal .
51 | ///
52 | property Version: Byte read FVersion;
53 | ///
54 | /// The of this record.
55 | ///
56 | property RecordType: TRecordType read FRecordType;
57 | ///
58 | /// The request id associated with this record.
59 | ///
60 | property RequestId: Integer read FRequestId;
61 | ///
62 | /// The length of .
63 | ///
64 | property ContentLength: Integer read FContentLength;
65 | ///
66 | /// The data contained in this record.
67 | ///
68 | property ContentData: TMemoryStream read FContentData;
69 | public
70 | constructor Create(io: TIdIOHandler);
71 | procedure ReadRecord;
72 | end;
73 |
74 | implementation
75 |
76 | { TFCGIRecord }
77 |
78 | constructor TFCGIRecord.Create(io: TIdIOHandler);
79 | begin
80 | FIO := io;
81 | end;
82 |
83 | ///
84 | /// Reads a single byte from the given stream.
85 | ///
86 | function TFCGIRecord.ReadByte: Byte;
87 | begin
88 | Result := FIO.ReadByte;
89 | end;
90 |
91 | procedure TFCGIRecord.ReadBytes(len: Integer);
92 | var
93 | buf: TIdBytes;
94 | begin
95 | SetLength(buf, len);
96 | FIO.ReadBytes(buf, len);
97 | end;
98 |
99 | procedure TFCGIRecord.ReadContent(len: Integer);
100 | begin
101 | FContentData := TMemoryStream.Create;
102 | FIO.ReadStream(FContentData, len);
103 | end;
104 |
105 | ///
106 | /// Reads a 16-bit integer from the given stream.
107 | ///
108 | function TFCGIRecord.ReadInt16: UInt16;
109 | var
110 | h, l: Byte;
111 | begin
112 | h := ReadByte;
113 | l := ReadByte;
114 | Result := h * 256 + l;
115 | end;
116 |
117 | ///
118 | /// Reads a single Record from the given stream.
119 | ///
120 | ///
121 | /// Returns the retreived record or null if no record could be read.
122 | /// Will block if a partial record is on the stream, until the full record has arrived or a timeout occurs.
123 | ///
124 | procedure TFCGIRecord.ReadRecord;
125 | var
126 | paddingLength: Byte;
127 | begin
128 | FVersion := ReadByte;
129 | if FVersion <> FCGI_VERSION_1 then
130 | begin
131 | raise Exception.Create
132 | ('Invalid version number in FastCGI record header. Possibly corrupted data.');
133 | end;
134 | case ReadByte of
135 | 1:
136 | FRecordType := BeginRequest;
137 | 2:
138 | FRecordType := AbortRequest;
139 | 3:
140 | FRecordType := EndRequest;
141 | 4:
142 | FRecordType := Params;
143 | 5:
144 | FRecordType := Stdin;
145 | 6:
146 | FRecordType := Stdout;
147 | 7:
148 | FRecordType := Stderr;
149 | 8:
150 | FRecordType := Data;
151 | 9:
152 | FRecordType := GetValues;
153 | 10:
154 | FRecordType := GetValuesResult;
155 | 11:
156 | FRecordType := UnknownType;
157 | 12:
158 | FRecordType := MaxType;
159 | end;
160 | FRequestId := ReadInt16;
161 | FContentLength := ReadInt16;
162 |
163 | paddingLength := ReadByte;
164 | ReadByte;
165 |
166 | if FContentLength > 0 then
167 | begin
168 | ReadContent(FContentLength);
169 | end;
170 | if paddingLength > 0 then
171 | begin
172 | ReadBytes(paddingLength);
173 | end;
174 | end;
175 |
176 | end.
177 |
--------------------------------------------------------------------------------
/NGINX/NGINX.FCGIRequest.pas:
--------------------------------------------------------------------------------
1 | unit NGINX.FCGIRequest;
2 |
3 | ///
4 | /// A FastCGI request.
5 | ///
6 | ///
7 | /// A request usually corresponds to a HTTP request that has been received by the webserver (see the [FastCGI specification](http://www.fastcgi.com/devkit/doc/fcgi-spec.html) for details).
8 | ///
9 | interface
10 |
11 | uses
12 | System.SysUtils, System.Classes, NGINX.FCGIRecord, IdIOHandler,
13 | System.Generics.Collections, NGINX.FCGIStream;
14 |
15 | type
16 | {$M+}
17 | TFCGIRequest = class
18 | private
19 | FRequestId: Integer;
20 | FIO: TIdIOHandler;
21 | FKeepAlive: Boolean;
22 | FIsOpen: Boolean;
23 | ///
24 | /// Incoming parameter records are stored here, until the parameter stream is closed by the webserver by sending an empty param record.
25 | ///
26 | FParamStream: TMemoryStream;
27 | FParameters: TDictionary;
28 | FRequestBodyStream: TMemoryStream;
29 | procedure Param_ReadNameValuePairs;
30 | protected
31 | published
32 | ///
33 | /// The id for this request, issued by the webserver
34 | ///
35 | property RequestId: Integer read FRequestId;
36 | ///
37 | /// True iff the webserver set the KeepAlive flag for this request
38 | ///
39 | ///
40 | /// This indicates that the socket used for this request should be left open.
41 | /// This is used internally by .
42 | ///
43 | property KeepAlive: Boolean read FKeepAlive;
44 | ///
45 | /// The FastCGI parameters received by the webserver, in raw byte arrays.
46 | ///
47 | property Parameters: TDictionary read FParameters;
48 | ///
49 | /// A stream providing the request body.
50 | ///
51 | ///
52 | /// For POST requests, this will contain the POST variables. For GET requests, this will be empty.
53 | ///
54 | property RequestBody: TMemoryStream read FRequestBodyStream;
55 | public
56 | constructor Create(RequestId: Integer; responseHandler: TIdIOHandler;
57 | KeepAlive: Boolean);
58 | function HandleRecord(r: TFCGIRecord): Boolean;
59 | end;
60 |
61 | implementation
62 |
63 | { TFCGIRequest }
64 |
65 | ///
66 | /// Creates a new request. Usually, you don't need to call this.
67 | ///
68 | /// Records are created by when a new request has been received.
69 | constructor TFCGIRequest.Create(RequestId: Integer;
70 | responseHandler: TIdIOHandler; KeepAlive: Boolean);
71 | begin
72 | FRequestId := RequestId;
73 | FIO := responseHandler;
74 | FKeepAlive := KeepAlive;
75 | FIsOpen := true;
76 | FParameters := TDictionary.Create;
77 | FRequestBodyStream := TMemoryStream.Create;
78 | end;
79 |
80 | ///
81 | /// Used internally. Feeds a TFCGIRecord to this request for processing.
82 | ///
83 | /// The record to feed.
84 | /// Returns true iff the request is completely received.
85 | function TFCGIRequest.HandleRecord(r: TFCGIRecord): Boolean;
86 | var
87 | oldPos: Integer;
88 | begin
89 | Result := false;
90 | case r.RecordType of
91 | TRecordType.Params:
92 | begin
93 | if not Assigned(FParamStream) then
94 | FParamStream := TMemoryStream.Create;
95 | if r.ContentLength = 0 then
96 | begin
97 | // An empty parameter record specifies that all parameters have been transmitted
98 | FParamStream.Position := 0;
99 | Param_ReadNameValuePairs;
100 | end
101 | else
102 | begin
103 | // If the params are not yet finished, write the contents to the ParamStream.
104 | r.ContentData.Position := 0;
105 | FParamStream.CopyFrom(r.ContentData, r.ContentLength);
106 | end;
107 | end;
108 | TRecordType.Stdin:
109 | begin
110 | if r.ContentLength = 0 then
111 | begin
112 | // Finished requests are indicated by an empty stdin record
113 | Result := true;
114 | end
115 | else
116 | begin
117 | oldPos := FRequestBodyStream.Position;
118 | FRequestBodyStream.Seek(0, TSeekOrigin.soEnd);
119 | r.ContentData.Position := 0;
120 | FRequestBodyStream.CopyFrom(r.ContentData, r.ContentLength);
121 | FRequestBodyStream.Position := oldPos;
122 | end;
123 | end;
124 | end;
125 | end;
126 |
127 | ///
128 | /// Tries to read a dictionary of name-value pairs from the given stream
129 | ///
130 | ///
131 | /// This method does not make any attempt to make sure whether this record actually contains a set of name-value pairs.
132 | /// It will return nonsense or throw an EndOfStreamException if the record content does not contain valid name-value pairs.
133 | ///
134 | procedure TFCGIRequest.Param_ReadNameValuePairs;
135 | ///
136 | /// Reads a length from the given stream, which is encoded in one or four bytes.
137 | ///
138 | ///
139 | /// See section 3.4 of the FastCGI specification for details.
140 | ///
141 | function ReadVarLength: UInt16;
142 | var
143 | firstByte: Byte;
144 | b0, b1, b2: Byte;
145 | begin
146 | FParamStream.Read(firstByte, 1);
147 | if firstByte <= 127 then
148 | begin
149 | Result := firstByte;
150 | end
151 | else
152 | begin
153 | FParamStream.Read(b2, 1);
154 | FParamStream.Read(b1, 1);
155 | FParamStream.Read(b0, 1);
156 | Result := UInt16((16777216 * ($7F and firstByte) + 65536 * b2 + 256 *
157 | b1 + b0));
158 | end;
159 | end;
160 |
161 | var
162 | nameLength: UInt16;
163 | valueLength: UInt16;
164 | name: TBytes;
165 | Value: TBytes;
166 | n: string;
167 | begin
168 | if not Assigned(FParameters) then
169 | FParameters := TDictionary.Create;
170 | while FParamStream.Position < FParamStream.Size do
171 | begin
172 | nameLength := ReadVarLength;
173 | valueLength := ReadVarLength;
174 | // x32 does not allow objects larger than 2GB
175 | // We do not make the effort to workaround this,
176 | // but simply throw an error if we encounter sizes beyond this limit.
177 | if (nameLength >= Integer.MaxValue) or (valueLength >= Integer.MaxValue)
178 | then
179 | begin
180 | raise Exception.Create('Cannot process values larger than 2GB.');
181 | end;
182 | SetLength(name, nameLength);
183 | FParamStream.Read(name, nameLength);
184 | n := TEncoding.ASCII.GetString(name);
185 | SetLength(Value, valueLength);
186 | FParamStream.Read(Value, valueLength);
187 |
188 | if FParameters.ContainsKey(n) then
189 | FParameters[n] := Value
190 | else
191 | FParameters.Add(n, Value);
192 | end;
193 | end;
194 |
195 | end.
196 |
--------------------------------------------------------------------------------
/NGINX/NGINX.FCGIResponse.pas:
--------------------------------------------------------------------------------
1 | unit NGINX.FCGIResponse;
2 |
3 | ///
4 | /// A FastCGI response.
5 | ///
6 | ///
7 | /// You will probably want to use or its helper methods to output a response and then call . Use to be notified of new requests.
8 | ///
9 | /// Remember to call when you wrote the complete response.
10 | ///
11 | ///
12 | interface
13 |
14 | uses
15 | System.SysUtils, System.Classes, NGINX.FCGIRecord, IdIOHandler,
16 | System.Generics.Collections, NGINX.FCGIStream;
17 |
18 | type
19 | {$M+}
20 | TFCGIResponse = class
21 | private
22 | FRequestId: Integer;
23 | FIO: TIdIOHandler;
24 | FIsClose: Boolean;
25 | FHeader: TDictionary;
26 | FHttpStatusCode: Integer;
27 | FHttpVersion: string;
28 | FContent: string;
29 | FCharset: string;
30 | FContentType: string;
31 | procedure SendContent;
32 | procedure SetContent(const Value: string);
33 | procedure SetHeader(const Value: TDictionary);
34 | procedure SetHttpStatusCode(const Value: Integer);
35 | procedure SetHttpVersion(const Value: string);
36 | procedure SetCharset(const Value: string);
37 | procedure SetContentType(const Value: string);
38 | protected
39 | published
40 | property HttpVersion: string read FHttpVersion write SetHttpVersion;
41 | property HttpStatusCode: Integer read FHttpStatusCode
42 | write SetHttpStatusCode;
43 | property Header: TDictionary read FHeader write SetHeader;
44 | property Content: string read FContent write SetContent;
45 | property IsClose: Boolean read FIsClose;
46 | property ContentType: string read FContentType write SetContentType;
47 | property Charset: string read FCharset write SetCharset;
48 | public
49 | constructor Create(requestId: Integer; responseHandler: TIdIOHandler);
50 | procedure Send(const data: TBytes); overload;
51 | procedure Send(const data: TStream); overload;
52 | procedure Send(const data: string); overload;
53 | procedure SendRaw(const rawdata: TBytes);
54 | procedure Flush;
55 | end;
56 |
57 | implementation
58 |
59 | { TFCGIResponse }
60 |
61 | constructor TFCGIResponse.Create(requestId: Integer;
62 | responseHandler: TIdIOHandler);
63 | begin
64 | FRequestId := requestId;
65 | FIO := responseHandler;
66 | FHttpVersion := 'HTTP/1.1';
67 | FHttpStatusCode := 200;
68 | FHeader := TDictionary.Create;
69 | ContentType := 'text/html';
70 | Charset := 'utf-8';
71 |
72 | FHeader.Add('X-Powered-By', 'MVCXE.NGINX.FCGI');
73 | FIsClose := false;
74 | end;
75 |
76 | procedure TFCGIResponse.Flush;
77 | begin
78 | if not FIsClose then
79 | SendContent;
80 | FIsClose := true;
81 | FIO.Close;
82 | end;
83 |
84 | procedure TFCGIResponse.Send(const data: TStream);
85 | var
86 | s: string;
87 | item: TPair;
88 | bs: TBytesStream;
89 | begin
90 | s := FHttpVersion + ' ' + IntToStr(FHttpStatusCode) + ' OK'#10;
91 | for item in FHeader do
92 | begin
93 | s := s + item.Key + ':' + item.Value + #10;
94 | end;
95 | s := s + #10;
96 | bs := TBytesStream.Create(TEncoding.Default.GetBytes(s));
97 | bs.Write(data, data.Size);
98 | SendRaw(bs.Bytes);
99 | end;
100 |
101 | ///
102 | /// Appends data to the response body.
103 | ///
104 | ///
105 | /// The given data will be sent immediately to the webserver as a single stdout record.
106 | ///
107 | /// The data to append.
108 | procedure TFCGIResponse.Send(const data: TBytes);
109 | var
110 | s: string;
111 | item: TPair;
112 | bs: TBytesStream;
113 | begin
114 | s := FHttpVersion + ' ' + IntToStr(FHttpStatusCode) + ' OK'#10;
115 | for item in FHeader do
116 | begin
117 | s := s + item.Key + ':' + item.Value + #10;
118 | end;
119 | s := s + #10;
120 | bs := TBytesStream.Create(TEncoding.Default.GetBytes(s));
121 | bs.Write(data, Length(data));
122 | SendRaw(bs.Bytes);
123 | end;
124 |
125 | ///
126 | /// Appends an ASCII string to the response body.
127 | ///
128 | ///
129 | /// This is a helper function, it converts the given string to ASCII bytes and feeds it to .
130 | ///
131 | /// The string to append, encoded in Charset.
132 | procedure TFCGIResponse.Send(const data: string);
133 | var
134 | s: string;
135 | item: TPair;
136 | begin
137 | s := FHttpVersion + ' ' + IntToStr(FHttpStatusCode) + ' OK'#10;
138 | for item in FHeader do
139 | begin
140 | s := s + item.Key + ':' + item.Value + #10;
141 | end;
142 | s := s + #10 + data;
143 | // todo: Encoding
144 | if SameText(FCharset, 'utf8') or SameText(FCharset, 'utf-8') then
145 | begin
146 | SendRaw(TEncoding.UTF8.GetBytes(s));
147 | end
148 | else
149 | begin
150 | SendRaw(TEncoding.Default.GetBytes(s));
151 | end;
152 | end;
153 |
154 | procedure TFCGIResponse.SendContent;
155 | begin
156 | Send(Content);
157 | end;
158 |
159 | ///
160 | /// Used internally. Writes the record to the given stream. Used for sending records to the webserver.
161 | ///
162 | procedure TFCGIResponse.SendRaw(const rawdata: TBytes);
163 | var
164 | remainingLength: Integer;
165 | response: TFCGIStream;
166 | buf64kb: TBytes;
167 | offset: Integer;
168 | begin
169 | response := TFCGIStream.Create(FRequestId);
170 | try
171 | remainingLength := Length(rawdata);
172 | if remainingLength <= 65535 then
173 | begin
174 | response.response(rawdata);
175 | response.stream.Position := 0;
176 | FIO.Write(response.stream, response.StreamLength);
177 | end
178 | else
179 | begin
180 | SetLength(buf64kb, 65535);
181 | offset := 0;
182 | while remainingLength > 65535 do
183 | begin
184 | buf64kb := Copy(rawdata, offset, 65535);
185 | response.response(buf64kb);
186 | response.stream.Position := 0;
187 | FIO.Write(response.stream, response.StreamLength);
188 | offset := offset + 65535;
189 | remainingLength := remainingLength - 65535;
190 | end;
191 | SetLength(buf64kb, remainingLength);
192 | buf64kb := Copy(rawdata, offset, remainingLength);
193 | response.response(buf64kb);
194 | response.stream.Position := 0;
195 | FIO.Write(response.stream, response.StreamLength);
196 | SetLength(buf64kb, 0);
197 | end;
198 | // 0
199 | SetLength(buf64kb, 0);
200 | response.response(buf64kb);
201 | response.stream.Position := 0;
202 | FIO.Write(response.stream, response.StreamLength);
203 | response.EndRequest;
204 | response.stream.Position := 0;
205 | FIO.Write(response.stream, response.StreamLength);
206 | FIsClose := true;
207 | finally
208 | response.Free;
209 | end;
210 | end;
211 |
212 | procedure TFCGIResponse.SetCharset(const Value: string);
213 | var
214 | s: string;
215 | begin
216 | FCharset := Value;
217 | if FCharset <> '' then
218 | begin
219 | s := '; charset=' + FCharset;
220 | if FHeader.ContainsKey('Content-Type') then
221 | FHeader['Content-Type'] := FContentType + s
222 | else
223 | FHeader.Add('Content-Type', FContentType + s);
224 | end;
225 | end;
226 |
227 | procedure TFCGIResponse.SetContentType(const Value: string);
228 | var
229 | s: string;
230 | begin
231 | FContentType := Value;
232 | if FCharset <> '' then
233 | begin
234 | s := '; charset=' + FCharset;
235 | end;
236 | if FHeader.ContainsKey('Content-Type') then
237 | FHeader['Content-Type'] := FContentType + s
238 | else
239 | FHeader.Add('Content-Type', FContentType + s);
240 | end;
241 |
242 | procedure TFCGIResponse.SetContent(const Value: string);
243 | begin
244 | FContent := Value;
245 | end;
246 |
247 | procedure TFCGIResponse.SetHeader(const Value: TDictionary);
248 | begin
249 | FHeader := Value;
250 | end;
251 |
252 | procedure TFCGIResponse.SetHttpStatusCode(const Value: Integer);
253 | begin
254 | FHttpStatusCode := Value;
255 | end;
256 |
257 | procedure TFCGIResponse.SetHttpVersion(const Value: string);
258 | begin
259 | FHttpVersion := Value;
260 | end;
261 |
262 | end.
263 |
--------------------------------------------------------------------------------
/NGINX/NGINX.FCGIStream.pas:
--------------------------------------------------------------------------------
1 | unit NGINX.FCGIStream;
2 |
3 | ///
4 | /// The stream where responses to this request should be written to.
5 | /// Only write FastCGI records here, not the raw response body. Use for sending response data.
6 | ///
7 |
8 | interface
9 |
10 | uses
11 | System.SysUtils, System.Classes, NGINX.FCGIConstants, NGINX.FCGIRecord,
12 | System.Generics.Collections, System.StrUtils;
13 |
14 | type
15 | {$M+}
16 | TFCGIStream = class
17 | private
18 | FRequestId: Integer;
19 | FVersion: Integer;
20 | Fstream: TBytesStream;
21 | FContentLength: Integer;
22 | FStreamLength: Integer;
23 | FRecordType: TRecordType;
24 | procedure WriteInt16(v: UInt16);
25 | procedure CreateResponse(data: TBytes);
26 | published
27 | property StreamLength: Integer read FStreamLength;
28 | property stream: TBytesStream read Fstream write Fstream;
29 | public
30 | constructor Create(requestId: Integer);
31 | procedure Response(data: TBytes);
32 | procedure EndRequest;
33 | procedure ValuesResult(maxConnections: Integer; maxRequests: Integer;
34 | multiplexing: Boolean);
35 | end;
36 |
37 | procedure BeginRequestData(stream: TStream; var role: Integer; var flags: Byte);
38 |
39 | implementation
40 |
41 | procedure BeginRequestData(stream: TStream; var role: Integer; var flags: Byte);
42 | var
43 | h, l: Byte;
44 | begin
45 | stream.Position := 0;
46 | // ReadInt16
47 | // stream.Read(h, 1);
48 | // stream.Read(l, 1);
49 | // role := h * 256 + l;
50 | stream.Read(role, 1);
51 | // ReadByte
52 | stream.Read(flags, 1);
53 | end;
54 |
55 | { TFCGIStream }
56 |
57 | constructor TFCGIStream.Create(requestId: Integer);
58 | begin
59 | FRequestId := requestId;
60 | FVersion := FCGI_VERSION_1;
61 | Fstream := TBytesStream.Create;
62 | end;
63 |
64 | ///
65 | /// Writes this record to the given stream.
66 | ///
67 | /// Returns the number of bytes written.
68 | procedure TFCGIStream.CreateResponse(data: TBytes);
69 | var
70 | b: Byte;
71 | begin
72 | if FContentLength > 65535 then
73 | begin
74 | raise Exception.Create('Cannot send a record with more that 65535 bytes.');
75 | end;
76 | Fstream.Clear;
77 | Fstream.Write(FVersion, 1);
78 |
79 | Fstream.Write(FRecordType, 1);
80 | WriteInt16(FRequestId);
81 | WriteInt16(FContentLength);
82 | // No padding
83 | b := 0;
84 | Fstream.Write(b, 1);
85 | // Reserved byte
86 | Fstream.Write(b, 1);
87 | if FContentLength > 0 then
88 | begin
89 | Fstream.Write(data, FContentLength);
90 | end;
91 | FStreamLength := FCGI_HEADER_LEN + FContentLength;
92 | end;
93 |
94 | ///
95 | /// Creates a EndRequest record with the given request id
96 | ///
97 | procedure TFCGIStream.EndRequest;
98 | var
99 | content: TBytes;
100 | begin
101 | FContentLength := 8;
102 | SetLength(content, FContentLength);
103 | content[0] := 0;
104 | content[1] := 0;
105 | content[2] := 0;
106 | content[3] := 0;
107 |
108 | // protocolStatus
109 | content[4] := Byte(TProtocolStatus.RequestComplete);
110 |
111 | // reserved bytes
112 | content[5] := 0;
113 | content[6] := 0;
114 | content[7] := 0;
115 | FRecordType := TRecordType.EndRequest;
116 | CreateResponse(content);
117 | end;
118 |
119 | ///
120 | /// Creates a GetValuesResult record from the given config values.
121 | ///
122 | procedure TFCGIStream.ValuesResult(maxConnections, maxRequests: Integer;
123 | multiplexing: Boolean);
124 | var
125 | nameValuePairs: TDictionary;
126 |
127 | vstream: TBytesStream;
128 | nameValuePair: TPair;
129 | name: string;
130 | nameBuf, value: TBytes;
131 | ///
132 | /// Writes a length from the given stream, which is encoded in one or four bytes.
133 | ///
134 | ///
135 | /// See section 3.4 of the FastCGI specification for details.
136 | ///
137 | procedure WriteVarLength(len: UInt32);
138 | var
139 | b: Byte;
140 | begin
141 | if len <= 127 then
142 | stream.Write(Byte(len), 1)
143 | else
144 | begin
145 | b := Byte($80 or len div 16777216);
146 | stream.Write(b, 1);
147 | b := Byte(len div 65536);
148 | stream.Write(b, 1);
149 | b := Byte(len div 256);
150 | stream.Write(b, 1);
151 | stream.Write(Byte(len), 1);
152 | end;
153 | end;
154 |
155 | begin
156 | nameValuePairs := TDictionary.Create();
157 | try
158 | nameValuePairs.Add(FCGI_MAX_CONNS,
159 | TEncoding.ASCII.GetBytes(IntToStr(maxConnections)));
160 | nameValuePairs.Add(FCGI_MAX_REQS,
161 | TEncoding.ASCII.GetBytes(IntToStr(maxRequests)));
162 | nameValuePairs.Add(FCGI_MPXS_CONNS,
163 | TEncoding.ASCII.GetBytes(IfThen(multiplexing, '1', '0')));
164 | FRecordType := TRecordType.GetValuesResult;
165 |
166 | vstream := TBytesStream.Create;
167 | try
168 | for nameValuePair in nameValuePairs do
169 | begin
170 | name := nameValuePair.Key;
171 | nameBuf := TEncoding.ASCII.GetBytes(name);
172 | value := nameValuePair.value;
173 | WriteVarLength(Length(nameBuf));
174 | WriteVarLength(Length(value));
175 | stream.Write(nameBuf, 0, Length(nameBuf));
176 | stream.Write(value, 0, Length(value));
177 | end;
178 | FContentLength := stream.Size;
179 | CreateResponse(stream.Bytes);
180 | finally
181 | vstream.Free;
182 | end;
183 | finally
184 | nameValuePairs.Free;
185 | end;
186 | end;
187 |
188 | ///
189 | /// Creates a Stdout record from the given data and request id
190 | ///
191 | procedure TFCGIStream.Response(data: TBytes);
192 | begin
193 | FContentLength := Length(data);
194 | FRecordType := TRecordType.Stdout;
195 | CreateResponse(data);
196 | end;
197 |
198 | ///
199 | /// Writes a 16-bit integer to the given stream.
200 | ///
201 | procedure TFCGIStream.WriteInt16(v: UInt16);
202 | var
203 | b1, b2: Byte;
204 | begin
205 | b1 := Byte(v div 256);
206 | b2 := Byte(v);
207 | Fstream.Write(b1, 1);
208 | Fstream.Write(b2, 1);
209 | end;
210 |
211 | end.
212 |
--------------------------------------------------------------------------------
/NGINX/NGINX.FastCGI.dpr:
--------------------------------------------------------------------------------
1 | program NGINX.FastCGI;
2 |
3 | {$APPTYPE CONSOLE}
4 | {$R *.res}
5 |
6 | uses
7 | System.SysUtils,
8 | System.Types,
9 | IPPeerServer,
10 | IPPeerAPI,
11 | NGINX.FCGIApplication in 'NGINX.FCGIApplication.pas',
12 | NGINX.FCGIRequest in 'NGINX.FCGIRequest.pas',
13 | NGINX.FCGIStream in 'NGINX.FCGIStream.pas',
14 | NGINX.FCGIRecord in 'NGINX.FCGIRecord.pas',
15 | NGINX.FCGIConstants in 'NGINX.FCGIConstants.pas',
16 | NGINX.FCGIResponse in 'NGINX.FCGIResponse.pas',
17 | ServerConst1 in 'ServerConst1.pas',
18 | NGINX.WebModule in 'NGINX.WebModule.pas';
19 |
20 | function BindPort(APort: Integer): Boolean;
21 | var
22 | LTestServer: IIPTestServer;
23 | begin
24 | Result := True;
25 | try
26 | LTestServer := PeerFactory.CreatePeer('', IIPTestServer) as IIPTestServer;
27 | LTestServer.TestOpenPort(APort, nil);
28 | except
29 | Result := False;
30 | end;
31 | end;
32 |
33 | function CheckPort(APort: Integer): Integer;
34 | begin
35 | if BindPort(APort) then
36 | Result := APort
37 | else
38 | Result := 0;
39 | end;
40 |
41 | procedure SetPort(const AServer: TFCGIApplication; APort: String);
42 | begin
43 | if not AServer.Active then
44 | begin
45 | APort := APort.Replace(cCommandSetPort, '').Trim;
46 | if CheckPort(APort.ToInteger) > 0 then
47 | begin
48 | AServer.DefaultPort := APort.ToInteger;
49 | Writeln(Format(sPortSet, [APort]));
50 | end
51 | else
52 | Writeln(Format(sPortInUse, [APort]));
53 | end
54 | else
55 | Writeln(sServerRunning);
56 | Write(cArrow);
57 | end;
58 |
59 | procedure StartServer(const AServer: TFCGIApplication);
60 | begin
61 | if not AServer.Active then
62 | begin
63 | if CheckPort(AServer.DefaultPort) > 0 then
64 | begin
65 | Writeln(Format(sStartingServer, [AServer.DefaultPort]));
66 | AServer.Active := True;
67 | end
68 | else
69 | Writeln(Format(sPortInUse, [AServer.DefaultPort.ToString]));
70 | end
71 | else
72 | Writeln(sServerRunning);
73 | Write(cArrow);
74 | end;
75 |
76 | procedure WriteStatus(const AServer: TFCGIApplication);
77 | begin
78 | Writeln(sIndyVersion + AServer.Version);
79 | Writeln(sActive + AServer.Active.ToString(TUseBoolStrs.True));
80 | Writeln(sPort + AServer.DefaultPort.ToString);
81 | Write(cArrow);
82 | end;
83 |
84 | procedure StopServer(const AServer: TFCGIApplication);
85 | begin
86 | if AServer.Active then
87 | begin
88 | Writeln(sStoppingServer);
89 | AServer.Active := False;
90 | Writeln(sServerStopped);
91 | end
92 | else
93 | Writeln(sServerNotRunning);
94 | Write(cArrow);
95 | end;
96 |
97 | procedure WriteCommands;
98 | begin
99 | Writeln(sCommands);
100 | Write(cArrow);
101 | end;
102 |
103 | procedure RunServer(APort: Integer);
104 | var
105 | LServer: TFCGIApplication;
106 | LResponse: string;
107 | begin
108 | WriteCommands;
109 | LServer := TFCGIApplication.Create;
110 | try
111 | LServer.DefaultPort := APort;
112 | LServer.OnRequestIncoming := WebModule.FCGIRequestIncoming;
113 | LServer.OnRequestReceived := WebModule.FCGIRequestReceived;
114 | while True do
115 | begin
116 | Readln(LResponse);
117 | LResponse := LowerCase(LResponse);
118 | if LResponse.StartsWith(cCommandSetPort) then
119 | SetPort(LServer, LResponse)
120 | else if sametext(LResponse, cCommandStart) then
121 | StartServer(LServer)
122 | else if sametext(LResponse, cCommandStatus) then
123 | WriteStatus(LServer)
124 | else if sametext(LResponse, cCommandStop) then
125 | StopServer(LServer)
126 | else if sametext(LResponse, cCommandHelp) then
127 | WriteCommands
128 | else if sametext(LResponse, cCommandExit) then
129 | if LServer.Active then
130 | begin
131 | StopServer(LServer);
132 | break
133 | end
134 | else
135 | break
136 | else
137 | begin
138 | Writeln(sInvalidCommand);
139 | Write(cArrow);
140 | end;
141 | end;
142 | finally
143 | LServer.Free;
144 | end;
145 | end;
146 |
147 | begin
148 | try
149 | { TODO -oUser -cConsole Main : Insert code here }
150 | WebModule := TWebModule.Create;
151 | RunServer(8044);
152 | { app := TFCGIApplication.Create;
153 | try
154 | app.Run(8044);
155 | app.OnRequestIncoming := m.AppRequestIncoming;
156 | app.OnRequestReceived := m.AppRequestReceived;
157 | ReadLn;
158 | finally
159 | app.Free;
160 | end; }
161 | except
162 | on E: Exception do
163 | Writeln(E.ClassName, ': ', E.Message);
164 | end;
165 |
166 | end.
167 |
--------------------------------------------------------------------------------
/NGINX/NGINX.FastCGI.dproj:
--------------------------------------------------------------------------------
1 |
2 |
3 | {8E51664B-16C8-437F-923B-60D771751C97}
4 | 18.8
5 | None
6 | NGINX.FastCGI.dpr
7 | True
8 | Debug
9 | Win32
10 | 1
11 | Console
12 |
13 |
14 | true
15 |
16 |
17 | true
18 | Base
19 | true
20 |
21 |
22 | true
23 | Base
24 | true
25 |
26 |
27 | true
28 | Base
29 | true
30 |
31 |
32 | true
33 | Base
34 | true
35 |
36 |
37 | true
38 | Base
39 | true
40 |
41 |
42 | true
43 | Base
44 | true
45 |
46 |
47 | true
48 | Cfg_1
49 | true
50 | true
51 |
52 |
53 | true
54 | Base
55 | true
56 |
57 |
58 | .\$(Platform)\$(Config)
59 | .\$(Platform)\$(Config)
60 | false
61 | false
62 | false
63 | false
64 | false
65 | System;Xml;Data;Datasnap;Web;Soap;$(DCC_Namespace)
66 | NGINX_FastCGI
67 |
68 |
69 | RESTComponents;DataSnapServerMidas;emsclientfiredac;DataSnapFireDAC;FireDACADSDriver;DatasnapConnectorsFreePascal;FireDACMSSQLDriver;inetdb;emsedge;FireDACIBDriver;dbexpress;IndyCore;dsnap;DataSnapCommon;emsclient;FireDACCommon;RESTBackendComponents;DataSnapConnectors;soapserver;bindengine;CloudService;FireDACOracleDriver;FireDACMySQLDriver;FireDACCommonODBC;FireDACCommonDriver;DataSnapClient;inet;IndySystem;FireDACDb2Driver;FireDACInfxDriver;FireDAC;emshosting;FireDACSqliteDriver;FireDACPgDriver;FireDACASADriver;FireDACTDataDriver;soaprtl;DbxCommonDriver;DataSnapServer;xmlrtl;DataSnapNativeClient;soapmidas;rtl;emsserverresource;DbxClientDriver;CustomIPTransport;bindcomp;dbxcds;FireDACODBCDriver;DataSnapIndy10ServerTransport;dsnapxml;dbrtl;FireDACMongoDBDriver;IndyProtocols;$(DCC_UsePackage)
70 |
71 |
72 | DBXSqliteDriver;RESTComponents;DataSnapServerMidas;DBXInterBaseDriver;emsclientfiredac;DataSnapFireDAC;tethering;FireDACMSSQLDriver;bindcompfmx;DBXOracleDriver;inetdb;FmxTeeUI;FireDACIBDriver;fmx;fmxdae;FireDACDBXDriver;dbexpress;IndyCore;dsnap;DataSnapCommon;emsclient;FireDACCommon;RESTBackendComponents;soapserver;bindengine;DBXMySQLDriver;CloudService;FireDACOracleDriver;FireDACMySQLDriver;DBXFirebirdDriver;FireDACCommonODBC;FireDACCommonDriver;DataSnapClient;inet;bindcompdbx;IndyIPCommon;IndyIPServer;IndySystem;fmxFireDAC;FireDAC;FireDACSqliteDriver;FireDACPgDriver;ibmonitor;FireDACASADriver;FireDACTDataDriver;FMXTee;soaprtl;DbxCommonDriver;ibxpress;DataSnapServer;xmlrtl;DataSnapNativeClient;ibxbindings;fmxobj;FireDACDSDriver;soapmidas;rtl;DbxClientDriver;DBXSybaseASADriver;CustomIPTransport;bindcomp;DBXInformixDriver;IndyIPClient;dbxcds;FireDACODBCDriver;DataSnapIndy10ServerTransport;DataSnapProviderClient;dsnapxml;dbrtl;FireDACMongoDBDriver;IndyProtocols;inetdbxpress;fmxase;$(DCC_UsePackage)
73 | true
74 |
75 |
76 | DBXSqliteDriver;RESTComponents;DataSnapServerMidas;DBXInterBaseDriver;emsclientfiredac;DataSnapFireDAC;tethering;FireDACMSSQLDriver;bindcompfmx;DBXOracleDriver;inetdb;FmxTeeUI;FireDACIBDriver;fmx;fmxdae;FireDACDBXDriver;dbexpress;IndyCore;dsnap;DataSnapCommon;emsclient;FireDACCommon;RESTBackendComponents;soapserver;bindengine;DBXMySQLDriver;CloudService;FireDACOracleDriver;FireDACMySQLDriver;DBXFirebirdDriver;FireDACCommonODBC;FireDACCommonDriver;DataSnapClient;inet;bindcompdbx;IndyIPCommon;IndyIPServer;IndySystem;fmxFireDAC;FireDAC;FireDACSqliteDriver;FireDACPgDriver;ibmonitor;FireDACASADriver;FireDACTDataDriver;FMXTee;soaprtl;DbxCommonDriver;ibxpress;DataSnapServer;xmlrtl;DataSnapNativeClient;ibxbindings;fmxobj;FireDACDSDriver;soapmidas;rtl;DbxClientDriver;DBXSybaseASADriver;CustomIPTransport;bindcomp;DBXInformixDriver;IndyIPClient;dbxcds;FireDACODBCDriver;DataSnapIndy10ServerTransport;DataSnapProviderClient;dsnapxml;dbrtl;FireDACMongoDBDriver;IndyProtocols;inetdbxpress;fmxase;$(DCC_UsePackage)
77 | true
78 |
79 |
80 | DBXSqliteDriver;RESTComponents;DataSnapServerMidas;DBXDb2Driver;DBXInterBaseDriver;vclactnband;vclFireDAC;emsclientfiredac;DataSnapFireDAC;tethering;svnui;FireDACADSDriver;DBXMSSQLDriver;DatasnapConnectorsFreePascal;FireDACMSSQLDriver;vcltouch;vcldb;bindcompfmx;svn;DBXOracleDriver;inetdb;FmxTeeUI;emsedge;FireDACIBDriver;fmx;fmxdae;vclib;FireDACDBXDriver;dbexpress;IndyCore;vclx;dsnap;DataSnapCommon;emsclient;FireDACCommon;RESTBackendComponents;DataSnapConnectors;VCLRESTComponents;soapserver;vclie;bindengine;DBXMySQLDriver;CloudService;FireDACOracleDriver;FireDACMySQLDriver;DBXFirebirdDriver;FireDACCommonODBC;FireDACCommonDriver;DataSnapClient;inet;bindcompdbx;IndyIPCommon;vcl;DBXSybaseASEDriver;IndyIPServer;IndySystem;FireDACDb2Driver;dsnapcon;FireDACMSAccDriver;FireDACInfxDriver;fmxFireDAC;vclimg;TeeDB;FireDAC;emshosting;FireDACSqliteDriver;FireDACPgDriver;ibmonitor;FireDACASADriver;DBXOdbcDriver;FireDACTDataDriver;FMXTee;soaprtl;DbxCommonDriver;ibxpress;Tee;DataSnapServer;xmlrtl;DataSnapNativeClient;ibxbindings;fmxobj;FireDACDSDriver;soapmidas;rtl;emsserverresource;DbxClientDriver;vclwinx;DBXSybaseASADriver;CustomIPTransport;vcldsnap;bindcomp;appanalytics;DBXInformixDriver;IndyIPClient;bindcompvcl;TeeUI;dbxcds;VclSmp;adortl;FireDACODBCDriver;DataSnapIndy10ServerTransport;DataSnapProviderClient;dsnapxml;dbrtl;FireDACMongoDBDriver;IndyProtocols;inetdbxpress;fmxase;$(DCC_UsePackage)
81 | Winapi;System.Win;Data.Win;Datasnap.Win;Web.Win;Soap.Win;Xml.Win;Bde;$(DCC_Namespace)
82 | Debug
83 | CompanyName=;FileDescription=$(MSBuildProjectName);FileVersion=1.0.0.0;InternalName=;LegalCopyright=;LegalTrademarks=;OriginalFilename=;ProgramID=com.embarcadero.$(MSBuildProjectName);ProductName=$(MSBuildProjectName);ProductVersion=1.0.0.0;Comments=
84 | 1033
85 | true
86 | $(BDS)\bin\Artwork\Windows\UWP\delphi_UwpDefault_44.png
87 | $(BDS)\bin\Artwork\Windows\UWP\delphi_UwpDefault_150.png
88 |
89 |
90 | DBXSqliteDriver;RESTComponents;DataSnapServerMidas;DBXDb2Driver;DBXInterBaseDriver;vclactnband;vclFireDAC;emsclientfiredac;DataSnapFireDAC;tethering;FireDACADSDriver;DBXMSSQLDriver;DatasnapConnectorsFreePascal;FireDACMSSQLDriver;vcltouch;vcldb;bindcompfmx;DBXOracleDriver;inetdb;FmxTeeUI;emsedge;FireDACIBDriver;fmx;fmxdae;vclib;FireDACDBXDriver;dbexpress;IndyCore;vclx;dsnap;DataSnapCommon;emsclient;FireDACCommon;RESTBackendComponents;DataSnapConnectors;VCLRESTComponents;soapserver;vclie;bindengine;DBXMySQLDriver;CloudService;FireDACOracleDriver;FireDACMySQLDriver;DBXFirebirdDriver;FireDACCommonODBC;FireDACCommonDriver;DataSnapClient;inet;bindcompdbx;IndyIPCommon;vcl;DBXSybaseASEDriver;IndyIPServer;IndySystem;FireDACDb2Driver;dsnapcon;FireDACMSAccDriver;FireDACInfxDriver;fmxFireDAC;vclimg;TeeDB;FireDAC;emshosting;FireDACSqliteDriver;FireDACPgDriver;ibmonitor;FireDACASADriver;DBXOdbcDriver;FireDACTDataDriver;FMXTee;soaprtl;DbxCommonDriver;ibxpress;Tee;DataSnapServer;xmlrtl;DataSnapNativeClient;ibxbindings;fmxobj;FireDACDSDriver;soapmidas;rtl;emsserverresource;DbxClientDriver;vclwinx;DBXSybaseASADriver;CustomIPTransport;vcldsnap;bindcomp;appanalytics;DBXInformixDriver;IndyIPClient;bindcompvcl;TeeUI;dbxcds;VclSmp;adortl;FireDACODBCDriver;DataSnapIndy10ServerTransport;DataSnapProviderClient;dsnapxml;dbrtl;FireDACMongoDBDriver;IndyProtocols;inetdbxpress;fmxase;$(DCC_UsePackage)
91 | true
92 | $(BDS)\bin\Artwork\Windows\UWP\delphi_UwpDefault_44.png
93 | $(BDS)\bin\Artwork\Windows\UWP\delphi_UwpDefault_150.png
94 |
95 |
96 | DEBUG;$(DCC_Define)
97 | true
98 | false
99 | true
100 | true
101 | true
102 |
103 |
104 | false
105 |
106 |
107 | false
108 | RELEASE;$(DCC_Define)
109 | 0
110 | 0
111 |
112 |
113 |
114 | MainSource
115 |
116 |
117 |
118 |
119 |
120 |
121 |
122 |
123 |
124 |
125 | Cfg_2
126 | Base
127 |
128 |
129 | Base
130 |
131 |
132 | Cfg_1
133 | Base
134 |
135 |
136 |
137 | Delphi.Personality.12
138 | Application
139 |
140 |
141 |
142 | NGINX.FastCGI.dpr
143 |
144 |
145 |
146 |
147 |
148 | true
149 |
150 |
151 |
152 |
153 | true
154 |
155 |
156 |
157 |
158 | true
159 |
160 |
161 |
162 |
163 | NGINX_FastCGI.exe
164 | true
165 |
166 |
167 |
168 |
169 | 1
170 |
171 |
172 | Contents\MacOS
173 | 1
174 |
175 |
176 | 0
177 |
178 |
179 |
180 |
181 | classes
182 | 1
183 |
184 |
185 | classes
186 | 1
187 |
188 |
189 |
190 |
191 | res\xml
192 | 1
193 |
194 |
195 | res\xml
196 | 1
197 |
198 |
199 |
200 |
201 | library\lib\armeabi-v7a
202 | 1
203 |
204 |
205 |
206 |
207 | library\lib\armeabi
208 | 1
209 |
210 |
211 | library\lib\armeabi
212 | 1
213 |
214 |
215 |
216 |
217 | library\lib\armeabi-v7a
218 | 1
219 |
220 |
221 |
222 |
223 | library\lib\mips
224 | 1
225 |
226 |
227 | library\lib\mips
228 | 1
229 |
230 |
231 |
232 |
233 | library\lib\armeabi-v7a
234 | 1
235 |
236 |
237 | library\lib\arm64-v8a
238 | 1
239 |
240 |
241 |
242 |
243 | library\lib\armeabi-v7a
244 | 1
245 |
246 |
247 |
248 |
249 | res\drawable
250 | 1
251 |
252 |
253 | res\drawable
254 | 1
255 |
256 |
257 |
258 |
259 | res\values
260 | 1
261 |
262 |
263 | res\values
264 | 1
265 |
266 |
267 |
268 |
269 | res\values-v21
270 | 1
271 |
272 |
273 | res\values-v21
274 | 1
275 |
276 |
277 |
278 |
279 | res\values
280 | 1
281 |
282 |
283 | res\values
284 | 1
285 |
286 |
287 |
288 |
289 | res\drawable
290 | 1
291 |
292 |
293 | res\drawable
294 | 1
295 |
296 |
297 |
298 |
299 | res\drawable-xxhdpi
300 | 1
301 |
302 |
303 | res\drawable-xxhdpi
304 | 1
305 |
306 |
307 |
308 |
309 | res\drawable-ldpi
310 | 1
311 |
312 |
313 | res\drawable-ldpi
314 | 1
315 |
316 |
317 |
318 |
319 | res\drawable-mdpi
320 | 1
321 |
322 |
323 | res\drawable-mdpi
324 | 1
325 |
326 |
327 |
328 |
329 | res\drawable-hdpi
330 | 1
331 |
332 |
333 | res\drawable-hdpi
334 | 1
335 |
336 |
337 |
338 |
339 | res\drawable-xhdpi
340 | 1
341 |
342 |
343 | res\drawable-xhdpi
344 | 1
345 |
346 |
347 |
348 |
349 | res\drawable-mdpi
350 | 1
351 |
352 |
353 | res\drawable-mdpi
354 | 1
355 |
356 |
357 |
358 |
359 | res\drawable-hdpi
360 | 1
361 |
362 |
363 | res\drawable-hdpi
364 | 1
365 |
366 |
367 |
368 |
369 | res\drawable-xhdpi
370 | 1
371 |
372 |
373 | res\drawable-xhdpi
374 | 1
375 |
376 |
377 |
378 |
379 | res\drawable-xxhdpi
380 | 1
381 |
382 |
383 | res\drawable-xxhdpi
384 | 1
385 |
386 |
387 |
388 |
389 | res\drawable-xxxhdpi
390 | 1
391 |
392 |
393 | res\drawable-xxxhdpi
394 | 1
395 |
396 |
397 |
398 |
399 | res\drawable-small
400 | 1
401 |
402 |
403 | res\drawable-small
404 | 1
405 |
406 |
407 |
408 |
409 | res\drawable-normal
410 | 1
411 |
412 |
413 | res\drawable-normal
414 | 1
415 |
416 |
417 |
418 |
419 | res\drawable-large
420 | 1
421 |
422 |
423 | res\drawable-large
424 | 1
425 |
426 |
427 |
428 |
429 | res\drawable-xlarge
430 | 1
431 |
432 |
433 | res\drawable-xlarge
434 | 1
435 |
436 |
437 |
438 |
439 | res\values
440 | 1
441 |
442 |
443 | res\values
444 | 1
445 |
446 |
447 |
448 |
449 | 1
450 |
451 |
452 | Contents\MacOS
453 | 1
454 |
455 |
456 | 0
457 |
458 |
459 |
460 |
461 | Contents\MacOS
462 | 1
463 | .framework
464 |
465 |
466 | Contents\MacOS
467 | 1
468 | .framework
469 |
470 |
471 | 0
472 |
473 |
474 |
475 |
476 | 1
477 | .dylib
478 |
479 |
480 | 1
481 | .dylib
482 |
483 |
484 | 1
485 | .dylib
486 |
487 |
488 | Contents\MacOS
489 | 1
490 | .dylib
491 |
492 |
493 | Contents\MacOS
494 | 1
495 | .dylib
496 |
497 |
498 | 0
499 | .dll;.bpl
500 |
501 |
502 |
503 |
504 | 1
505 | .dylib
506 |
507 |
508 | 1
509 | .dylib
510 |
511 |
512 | 1
513 | .dylib
514 |
515 |
516 | Contents\MacOS
517 | 1
518 | .dylib
519 |
520 |
521 | Contents\MacOS
522 | 1
523 | .dylib
524 |
525 |
526 | 0
527 | .bpl
528 |
529 |
530 |
531 |
532 | 0
533 |
534 |
535 | 0
536 |
537 |
538 | 0
539 |
540 |
541 | 0
542 |
543 |
544 | 0
545 |
546 |
547 | Contents\Resources\StartUp\
548 | 0
549 |
550 |
551 | Contents\Resources\StartUp\
552 | 0
553 |
554 |
555 | 0
556 |
557 |
558 |
559 |
560 | 1
561 |
562 |
563 | 1
564 |
565 |
566 | 1
567 |
568 |
569 |
570 |
571 | 1
572 |
573 |
574 | 1
575 |
576 |
577 | 1
578 |
579 |
580 |
581 |
582 | 1
583 |
584 |
585 | 1
586 |
587 |
588 | 1
589 |
590 |
591 |
592 |
593 | 1
594 |
595 |
596 | 1
597 |
598 |
599 | 1
600 |
601 |
602 |
603 |
604 | 1
605 |
606 |
607 | 1
608 |
609 |
610 | 1
611 |
612 |
613 |
614 |
615 | 1
616 |
617 |
618 | 1
619 |
620 |
621 | 1
622 |
623 |
624 |
625 |
626 | 1
627 |
628 |
629 | 1
630 |
631 |
632 | 1
633 |
634 |
635 |
636 |
637 | 1
638 |
639 |
640 | 1
641 |
642 |
643 | 1
644 |
645 |
646 |
647 |
648 | 1
649 |
650 |
651 | 1
652 |
653 |
654 | 1
655 |
656 |
657 |
658 |
659 | 1
660 |
661 |
662 | 1
663 |
664 |
665 | 1
666 |
667 |
668 |
669 |
670 | 1
671 |
672 |
673 | 1
674 |
675 |
676 | 1
677 |
678 |
679 |
680 |
681 | 1
682 |
683 |
684 | 1
685 |
686 |
687 | 1
688 |
689 |
690 |
691 |
692 | 1
693 |
694 |
695 | 1
696 |
697 |
698 | 1
699 |
700 |
701 |
702 |
703 | 1
704 |
705 |
706 | 1
707 |
708 |
709 | 1
710 |
711 |
712 |
713 |
714 | 1
715 |
716 |
717 | 1
718 |
719 |
720 | 1
721 |
722 |
723 |
724 |
725 | 1
726 |
727 |
728 | 1
729 |
730 |
731 | 1
732 |
733 |
734 |
735 |
736 | 1
737 |
738 |
739 | 1
740 |
741 |
742 | 1
743 |
744 |
745 |
746 |
747 | 1
748 |
749 |
750 | 1
751 |
752 |
753 | 1
754 |
755 |
756 |
757 |
758 | 1
759 |
760 |
761 | 1
762 |
763 |
764 | 1
765 |
766 |
767 |
768 |
769 | 1
770 |
771 |
772 | 1
773 |
774 |
775 | 1
776 |
777 |
778 |
779 |
780 | 1
781 |
782 |
783 | 1
784 |
785 |
786 | 1
787 |
788 |
789 |
790 |
791 | 1
792 |
793 |
794 | 1
795 |
796 |
797 | 1
798 |
799 |
800 |
801 |
802 | 1
803 |
804 |
805 | 1
806 |
807 |
808 | 1
809 |
810 |
811 |
812 |
813 | 1
814 |
815 |
816 | 1
817 |
818 |
819 | 1
820 |
821 |
822 |
823 |
824 | 1
825 |
826 |
827 | 1
828 |
829 |
830 |
831 |
832 | ..\$(PROJECTNAME).app.dSYM\Contents\Resources\DWARF
833 | 1
834 |
835 |
836 | ..\$(PROJECTNAME).app.dSYM\Contents\Resources\DWARF
837 | 1
838 |
839 |
840 |
841 |
842 | 1
843 |
844 |
845 | 1
846 |
847 |
848 |
849 |
850 | ..\
851 | 1
852 |
853 |
854 | ..\
855 | 1
856 |
857 |
858 |
859 |
860 | 1
861 |
862 |
863 | 1
864 |
865 |
866 | 1
867 |
868 |
869 |
870 |
871 | 1
872 |
873 |
874 | 1
875 |
876 |
877 | 1
878 |
879 |
880 |
881 |
882 | ..\$(PROJECTNAME).app.dSYM\Contents\Resources\DWARF
883 | 1
884 |
885 |
886 |
887 |
888 | ..\
889 | 1
890 |
891 |
892 | ..\
893 | 1
894 |
895 |
896 |
897 |
898 | Contents
899 | 1
900 |
901 |
902 | Contents
903 | 1
904 |
905 |
906 |
907 |
908 | Contents\Resources
909 | 1
910 |
911 |
912 | Contents\Resources
913 | 1
914 |
915 |
916 |
917 |
918 | library\lib\armeabi-v7a
919 | 1
920 |
921 |
922 | library\lib\arm64-v8a
923 | 1
924 |
925 |
926 | 1
927 |
928 |
929 | 1
930 |
931 |
932 | 1
933 |
934 |
935 | 1
936 |
937 |
938 | Contents\MacOS
939 | 1
940 |
941 |
942 | Contents\MacOS
943 | 1
944 |
945 |
946 | 0
947 |
948 |
949 |
950 |
951 | library\lib\armeabi-v7a
952 | 1
953 |
954 |
955 |
956 |
957 | 1
958 |
959 |
960 | 1
961 |
962 |
963 |
964 |
965 | Assets
966 | 1
967 |
968 |
969 | Assets
970 | 1
971 |
972 |
973 |
974 |
975 | Assets
976 | 1
977 |
978 |
979 | Assets
980 | 1
981 |
982 |
983 |
984 |
985 |
986 |
987 |
988 |
989 |
990 |
991 |
992 |
993 |
994 |
995 | False
996 | False
997 | False
998 | True
999 | False
1000 |
1001 | False
1002 |
1003 | 12
1004 |
1005 |
1006 |
1007 |
1008 |
1009 |
--------------------------------------------------------------------------------
/NGINX/NGINX.FastCGI.res:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/kylixfans/FastCGI/7d3dde5eb69ca911d121c3d387e3a6414921ef64/NGINX/NGINX.FastCGI.res
--------------------------------------------------------------------------------
/NGINX/NGINX.WebModule.pas:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/kylixfans/FastCGI/7d3dde5eb69ca911d121c3d387e3a6414921ef64/NGINX/NGINX.WebModule.pas
--------------------------------------------------------------------------------
/NGINX/ServerConst1.pas:
--------------------------------------------------------------------------------
1 | unit ServerConst1;
2 |
3 | interface
4 |
5 | resourcestring
6 | sPortInUse = '- Error: Port %s already in use';
7 | sPortSet = '- Port set to %s';
8 | sServerRunning = '- The Server is already running';
9 | sStartingServer = '- Starting HTTP Server on port %d';
10 | sStoppingServer = '- Stopping Server';
11 | sServerStopped = '- Server Stopped';
12 | sServerNotRunning = '- The Server is not running';
13 | sInvalidCommand = '- Error: Invalid Command';
14 | sIndyVersion = '- Indy Version: ';
15 | sActive = '- Active: ';
16 | sPort = '- Port: ';
17 | sSessionID = '- Session ID CookieName: ';
18 | sCommands = 'Enter a Command: ' + slineBreak +
19 | ' - "start" to start the server' + slineBreak +
20 | ' - "stop" to stop the server' + slineBreak +
21 | ' - "set port" to change the default port' + slineBreak +
22 | ' - "status" for Server status' + slineBreak +
23 | ' - "help" to show commands' + slineBreak +
24 | ' - "exit" to close the application';
25 |
26 | const
27 | cArrow = '->';
28 | cCommandStart = 'start';
29 | cCommandStop = 'stop';
30 | cCommandStatus = 'status';
31 | cCommandHelp = 'help';
32 | cCommandSetPort = 'set port';
33 | cCommandExit = 'exit';
34 |
35 | implementation
36 |
37 | end.
38 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # FastCGI for Delphi
2 |
3 | This is an implementation of [FastCGI](http://www.fastcgi.com/devkit/doc/fcgi-spec.html) for Delphi, written in Pascal. It implements the parts of the protocol that are necessary to build a simple web application using Delphi.
4 |
5 | This means that you can write web applications in Pascal that serve dynamic content.
6 |
7 | ## License and contributing
8 |
9 | This software is distributed under the terms of the MIT license. You can use it for your own projects for free under the conditions specified in LICENSE.
10 |
11 | If you have questions, feel free to contact me. Visit [www.mvcxe.com](https://www.mvcxe.com) for my contact details.
12 |
13 | If you think you found a bug, you can open an Issue on Github. If you make changes to this library, I would be happy about a pull request.
14 |
15 | ## Basic usage
16 |
17 | The most common usage scenario is to use this library together with a web server nginx. The web server will serve static content and forward HTTP requests for dynamic content to your application.
18 |
19 | Have a look at the NGINX.FCGIApplication.TFCGIApplication class for usage examples and more information.
20 |
21 | This code example shows how to create a FastCGI application and receive requests:
22 |
23 | ```pascal
24 | // TFCGIApplication Object, will accept FastCGI requests
25 | var
26 | app: TFCGIApplication;
27 |
28 | // Handle requests by responding with a 'Hello World' message
29 | procedure TWebModule.FCGIRequestReceived(const sender: TObject;
30 | const Request: TFCGIRequest; Response: TFCGIResponse);
31 | var
32 | Content: string;
33 | item: TPair;
34 | begin
35 | Content := 'Hello World!
这是中文内容
';
36 | for item in Request.Parameters do
37 | begin
38 | Content := Content + ' ' + item.Key + '=' + TEncoding.UTF8.GetString
39 | (item.Value) + '
';
40 | end;
41 | Response.Content := Content;
42 | end;
43 |
44 | // Create a new FCGIApplication
45 | app := TFCGIApplication.Create;
46 | app.OnRequestReceived := WebModule.FCGIRequestReceived;
47 | // Start listening on port 19000
48 | app.Run(19000);
49 |
50 | ```
51 |
52 | ## Web server configuration
53 |
54 | For nginx, use `fastcgi_pass` to pass requests to your FastCGI application:
55 |
56 | location / {
57 | fastcgi_pass 127.0.0.1:19000; # Pass all requests to port 19000 via FastCGI.
58 | include fastcgi_params; # (Optional): Set several FastCGI parameters like the remote IP and other metadata.
59 | }
60 |
61 | For more details, refer to your web server documentation for configuration details:
62 |
63 | * [nginx documentation](http://nginx.org/en/docs/http/ngx_http_fastcgi_module.html)
64 |
--------------------------------------------------------------------------------