#1 2018-06-30 23:19:43

pony5551
Member
Registered: 2018-01-24
Posts: 9

Blocks the httpapiserver thread

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

#2 2018-07-01 18:58:37

ab
Administrator
From: France
Registered: 2010-06-21
Posts: 14,661
Website

Re: Blocks the httpapiserver thread

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

#3 2018-07-02 15:10:16

pony5551
Member
Registered: 2018-01-24
Posts: 9

Re: Blocks the httpapiserver thread

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

#4 2018-07-02 20:38:19

ab
Administrator
From: France
Registered: 2010-06-21
Posts: 14,661
Website

Re: Blocks the httpapiserver thread

Please do not post huge code in the forum.
Check the forum rules.

There is already a thread pool in the current implementation, so I don't see what is the benefit of this.. sad

Offline

#5 2018-07-02 21:43:07

pony5551
Member
Registered: 2018-01-24
Posts: 9

Re: Blocks the httpapiserver thread

I'm sorry.
The advantage of this is that the thread is not blocked
It also improves performance by more than 100%

Offline

#6 2018-07-03 18:03:42

ab
Administrator
From: France
Registered: 2010-06-21
Posts: 14,661
Website

Re: Blocks the httpapiserver thread

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

Board footer

Powered by FluxBB