Reputation: 3
I am developing a simple Web Server to communicate with my Web App which runs in a browser.
I managed to create a IdTcpServer and get the RequestHeaders submitted by the browser. I don't know how it's possible to get POST parameters of the form.
here is my code so far:
procedure TMyServer.WebServerExecute(AContext: TIdContext);
var
RawData: String;
TRequestHeader: TStringList;
begin
TRequestHeader := TStringList.Create;
// GET Request Headers
RawData := AContext.Connection.Socket.ReadLn(IndyTextEncoding_UTF8);
while RawData <> '' do
begin
TRequestHeader.Add(RawData);
RawData := AContext.Connection.Socket.ReadLn(IndyTextEncoding_UTF8);
end;
// How To get POST or GET Parameters of the HTML form?
// ...
// Respond to the Client
Respond(...);
TRequestHeader.Free;
end;
Upvotes: 0
Views: 1114
Reputation: 596672
Once you have the request headers, you need to analyze them to know whether a message body even exists, and in what format it is encoded in so you can read it properly (see RFC 2616 section 4.4), eg:
procedure TMyServer.WebServerConnect(AContext: TIdContext);
begin
AContext.Connection.IOHandler.DefStringEncoding := IndyTextEncoding_UTF8;
end;
procedure TMyServer.WebServerExecute(AContext: TIdContext);
var
ReqLine, Value: String;
I: Integer;
Size: Int64;
TRequestHeader: TIdHeaderList;
begin
TRequestHeader := TIdHeaderList.Create;
try
// GET Request Line ...
ReqLine := AContext.Connection.IOHandler.ReadLn;
// TODO: parse ReqLine as needed to extract HTTP version, resource, and query params ...
// GET Request Headers ...
repeat
Value := AContext.Connection.IOHandler.ReadLn;
if Value = '' then Break;
TRequestHeader.Add(Value);
until False;
// alternatively:
// AContext.Connection.IOHandler.Capture(TRequestHeader, '', False);
// get POST or GET data ...
Value := TRequestHeader.Values['Transfer-Encoding'];
if (Value <> '') and (not TextIsSame(Value, 'identity')) then
begin
repeat
Value := AContext.Connection.IOHandler.ReadLn;
I := Pos(';', Value);
if I > 0 then begin
Value := Copy(Value, 1, I - 1);
end;
Size := StrToInt64('$' + Trim(S));
if Size = 0 then begin
Break;
end;
// read specified number of bytes as needed ...
AContext.Connection.IOHandler.ReadLn; // read CRLF at end of chunk data
until False;
// read trailer headers
repeat
Value := AContext.Connection.IOHandler.ReadLn;
if (Value = '') then Break;
// update TRequestHeader as needed...
until False;
end
else
begin
Value := TRequestHeader.Values['Content-Length'];
if Value = '' then
begin
// respond with 411 error
Exit;
end;
Size := StrToInt64(Value);
// read specified number of bytes as needed ...
end;
// process request as needed, based on the value of
// ReqLine, TRequestHeader.Values['Content-Type'], etc ...
// Respond to the Client
Respond(...);
finally
TRequestHeader.Free;
end;
end;
That being said, Indy has a TIdHTTPServer
component that handles the hard work of implementing the HTTP protocol for you (which is not as trivial a task as you think it is). You should not be using TIdTCPServer
for this.
You can assign a handler to the TIdHTTPServer.OnCommandGet
event and use the provided ARequestInfo
and AResponseInfo
parameters as needed. The request headers will be in the ARequestInfo.RawHeaders
property, and various sub-properties (ARequestInfo.ContentType
, ARequestInfo.ContentLength
, etc). The GET
/POST
data will be in the ARequestInfo.QueryParams
, ARequestInfo.FormParams
, and ARequestInfo.PostStream
properties accordingly, eg:
procedure TMyServer.WebServerCommandGet(AContext: TIdContext; ARequestInfo: TIdHTTPRequestInfo; AResponseInfo: TIdHTTPResponseInfo);
begin
// use ARequestInfo.RawHeaders and ARequestInfo.QueryParams as needed ...
if ARequestInfo.CommandType = hcPOST then
begin
if IsHeaderMediaType(ARequestInfo.ContentType, 'application/x-www-form-urlencoded') then
begin
// use ARequestInfo.FormParams as needed ...
end
else begin
// use ARequestInfo.PostStream as needed ...
end;
end else
begin
// process GET/HEAD requests as needed ...
end;
// Respond to the Client, by populating AResponseInfo as needed ...
end;
Upvotes: 1