You are not logged in.
Pages: 1
step1 send head
POST / HTTP/1.1
Host: 127.0.0.1:8080
Connection: Keep-Alive
Keep-Alive: 900
Content-Length: 90000000
CONTENT-Type: application/x-www-form-urlencoded
Accept: */*
User-Agent: Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1)
next
for i=0 to 90000000
begin
send('A');
sleep(300);
end;
The server thread is blocked
Is this a bug or a trap?
Offline
This is a trap: you made a Denial Of Service attack.
What blocks is not the mORMot server, but the http.sys kernel server.
I guess you will have the very same behavior with IIS.
To mitigate this, you have a maximum length configurable.
We may investigate further to mitigate this.
But most of the time, we simply put a nginx in front, to do the https encryption, and detect such DOS attempts.
Thanks for the feedback!
Offline
I added a worker thread pool to httpapiserver
My code looks something like this
type
PSynWorkItem = ^TSynWorkItem;
TSynWorkItem = record
FContext: TObject;
FProc: TNotifyEvent;
end;
function SynWorkItemFunction(lpThreadParameter: Pointer): Integer; stdcall;
var
W: PSynWorkItem;
begin
Result := 0;
W := PSynWorkItem(lpThreadParameter);
try
W^.FProc(W.FContext);
finally
W^.FContext.Free;
end;
end;
function THttpApiServer.GetContext: THttpServerRequest;
var
HttpResult: HRESULT;
ReqID: HTTP_REQUEST_ID;
//RequestBuffer: TBytes;
ReqBuf, RemoteIP: SockString;
Req: PHTTP_REQUEST;
BytesRead: Cardinal;
Done: boolean;
begin
// MS recomendation: 4K for normal buffers, plus 12K for authentication headers if used
//SetLength(RequestBuffer, 4096);
SetLength(ReqBuf,16384+sizeof(HTTP_REQUEST)); // space for Req^ + 16 KB of headers
Req := pointer(ReqBuf);
ReqID := 0;
Done := false;
repeat
BytesRead := 0;
HttpResult := Http.ReceiveHttpRequest(fReqQueue,ReqID,0,Req^,length(ReqBuf),BytesRead, nil);
if HttpResult = ERROR_MORE_DATA then
begin
ReqID := Req^.RequestId;
SetLength(ReqBuf, BytesRead);
Req := pointer(ReqBuf);
end
else
if (HttpResult = ERROR_INVALID_PARAMETER) and (ReqID <> 0) then
begin
ReqID := 0;
end
else
if (HttpResult = ERROR_CONNECTION_INVALID) and (ReqID <> 0) then
begin
ReqID := 0;
end
else
Done := true;
until Done;
// Check for operation aborted - this might mean the server was interrupted
// so we should not raise an exception, but rather return nil
if HttpResult = ERROR_OPERATION_ABORTED then
Exit(nil);
//HttpCheck(HttpResult);
if HttpResult<>0 then
Exit(nil);
Result := THttpServerRequest.Create(Self, 0, Self);
Result.fReqBuf := ReqBuf;
Result.fReqBufLen := BytesRead;
end;
procedure THttpApiServer.Execute;
var
WorkItem: TSynWorkItem;
LContext: THttpServerRequest;
begin
//ExecuteEx;
// THttpServerGeneric thread preparation: launch any OnHttpThreadStart event
NotifyThreadStart(self);
try
repeat
LContext := GetContext;
if (LContext <> nil) and not Terminated then
begin
WorkItem.FContext := LContext;
WorkItem.FProc := DoProcessContext;
Winapi.Windows.QueueUserWorkItem(SynWorkItemFunction, @WorkItem, 0);
end;
if Terminated then
break;
until Terminated;
finally
//Context.Free;
//fExecuteFinished := true;
end;
end;
procedure THttpApiServer.DoProcessContext(LContext: THttpServerRequest;);
begin
...
Recvbody and sendresponse
end;
Offline
I'm sorry.
The advantage of this is that the thread is not blocked
It also improves performance by more than 100%
Offline
But how the threads on the QueueUserWorkItem() thread pool are properly initialized for the framework (NotifyThreadStart)?
How do you handle HTTP_REQUEST_FLAG_MORE_ENTITY_BODY_EXISTS ?
Your code is still blocking when calling http.ReceiveHttpRequest.
Just doing it in other threads.
IMHO this behave the very same as increasing the THttpApiServer clone count (i.e. the THttpApiServer thread pool).
Just in a more complicated way.
Offline
Pages: 1