IndySockets / Indy

Indy - Internet Direct
https://www.indyproject.org
434 stars 147 forks source link

Feature Request: Limiting Incoming Stream Size in TIdHTTPServer #486

Open dbcto opened 1 year ago

dbcto commented 1 year ago

Dear Indy development team,

I am using your great Indy library in Delphi for an application that receives HTTP requests through the TIdHTTPServer component. I am looking for a way to limit the size of incoming data streams, and stop receiving them when they exceed a certain size limit.

After looking through the documentation and the available events of the TIdHTTPServer component, it appears that there isn't currently a way to achieve this. The OnCommandGet event, for example, only gets triggered after the full request data stream has been received from the client. There doesn't seem to be an event that is called while the stream is still being received, which would allow me to stop the receiving process based on the size received so far.

Therefore, I would like to propose the addition of a new feature that allows users to set a maximum size for incoming data streams and abort the reception process if this size is exceeded. I believe that this would be a valuable feature that could help to prevent potential problems caused by clients sending overly large requests.

I am hopeful that you will consider this feature for future versions of the library or I would appreciate any guidance or pointers you could provide that would help us to implement this feature on our own. I also like to contribute to the Indy project and I believe that my work could benefit other users as well.

Thanks in advance and best regards, Dennis

rlebeau commented 1 year ago

There are two different ways you can handle this in the current version:

dbcto commented 1 year ago

Thank you very much! I will check this and get back to you.

dbcto commented 1 year ago

Hi @rlebeau.

I've checked the OnHeadersAvailable and OnHeadersBlocked approach. This worked so far as I can check the headers and disrupt the communication if needed.

If I set VContinueProcessing to false the event OnHeadersBlocked is fired and I can set the VResponseNo etc. Unfortunately this information doesn't reach the calling client. I used postman for my test and there I only get "Could not get response" and "aborted".

Do I have to "send" the response in some way?

Thx!

rlebeau commented 1 year ago

No, the response is sent automatically after the event handlers return, as you can see in the source code:

  function HeadersCanContinue: Boolean;
  var
    LResponseNo: Integer;
    LResponseText, LContentText, S: String;
  begin
    // let the user decide if the request headers are acceptable
    // TODO pass the whole LRequestInfo object so the user has access
    // to the request method, too...
    Result := DoHeadersAvailable(AContext, LRequestInfo.URI, LRequestInfo.RawHeaders); // <-- FIRES THE OnHeadersAvailable EVENT
    if not Result then begin
      DoHeadersBlocked(AContext, LRequestInfo.RawHeaders, LResponseNo, LResponseText, LContentText); // <-- FIRES THE OnHeadersBlocked EVENT
      LResponseInfo.ResponseNo := LResponseNo;
      if Length(LResponseText) > 0 then begin
        LResponseInfo.ResponseText := LResponseText;
      end; 
      LResponseInfo.ContentText := LContentText;
      LResponseInfo.CharSet := 'utf-8'; {Do not localize}
      LResponseInfo.CloseConnection := True;
      LResponseInfo.WriteHeader; // <-- SENDS THE RESPONSE STATUS AND HEADERS
      if Length(LContentText) > 0 then begin
        LResponseInfo.WriteContent; // <-- SENDS THE RESPONSE BODY
      end;
      Exit;
    end;
    ...
  end;
dbcto commented 1 year ago

You are right. I tested it with Chrome and there I get the correct return code. Thank you very much.

dbcto commented 1 year ago

The limitation with the custom Stream and OnCreatePostStream also works great! Do you know the normal chunk size that is written at once with http 1.1?

rlebeau commented 1 year ago

There is no "normal chunk size" in HTTP. If the client or server sends a chunked message, each chunk specifies its own size, so it can be whatever size the sender wants.

In this case, depending on buffering, the size written to the PostStream may not always be a full chunk at a time, it may be pieces of a chunk. The only requirement is that pieces are written to the PostStream in the correct order.