Search code examples
delphiindyindy-9

How to send a DELETE request with Indy 9?


I am trying to send HTTP DELETE request using Indy 9.

Attempt (like that):

type
  TIdHTTPAccess = class(TIdHTTP)
  end;

TIdHTTPAccess(IdHttp).DoRequest(hmDelete, deleteURL, nil, nil);

This doesn't work, because hmDelete skipped in TIdHTTPProtocol.BuildAndSendRequest.

Is there any chance, to send HTTP DELETE request using Indy 9?

Delpphi 7, Indy 9.00.10, part of unit IdHTTP;

procedure TIdHTTPProtocol.BuildAndSendRequest(AURI: TIdURI);
...
  case Request.Method of
    hmHead: FHTTP.WriteLn('HEAD ' + Request.URL + ' HTTP/' + ProtocolVersionString[FHTTP.ProtocolVersion]); {do not localize}
    hmGet: FHTTP.WriteLn('GET ' + Request.URL + ' HTTP/' + ProtocolVersionString[FHTTP.ProtocolVersion]); {do not localize}
    hmPost: FHTTP.WriteLn('POST ' + Request.URL + ' HTTP/' + ProtocolVersionString[FHTTP.ProtocolVersion]); {do not localize}
    // HTTP 1.1 only
    hmOptions: FHTTP.WriteLn('OPTIONS ' + Request.URL + ' HTTP/' + ProtocolVersionString[FHTTP.ProtocolVersion]); {do not localize}
    hmTrace: FHTTP.WriteLn('TRACE ' + Request.URL + ' HTTP/' + ProtocolVersionString[FHTTP.ProtocolVersion]); {do not localize}
    hmPut: FHTTP.WriteLn('PUT ' + Request.URL + ' HTTP/' + ProtocolVersionString[FHTTP.ProtocolVersion]); {do not localize}
    hmConnect: FHTTP.WriteLn('CONNECT ' + Request.URL + ' HTTP/' + ProtocolVersionString[FHTTP.ProtocolVersion]); {do not localize}
  end;
...

Solution

  • Calling TIdHTTP.DoRequest() directly is the correct way to send a DELETE request in Indy 9. Using an accessor class is one option to do that. Another option would be to derive a new component from TIdHTTP to add your own Delete() method that calls DoRequest() (much like TIdHTTP does in Indy 10):

    type
      TMyHTTP = class(TIdHTTP)
      public
        procedure Delete(AURL: string; AResponseContent: TStream); overload;
        function Delete(AURL: string): string; overload;
      end;
    
    procedure TMyHTTP.Delete(AURL: string; AResponseContent: TStream);
    begin
      DoRequest(hmDelete, AURL, nil, AResponseContent);
    end;
    
    function TMyHTTP.Delete(AURL: string): string;
    var
      Stream: TMemoryStream;
    begin
      Stream := TMemoryStream.Create;
      try
        Delete(AURL, Stream);
        SetLength(Result, Stream.Size);
        Move(PChar(Stream.Memory)^, PChar(Result)^, Stream.Size);
      finally
        Stream.Free;
      end;
    end;
    

    However, that being said, you are using an outdated version of Indy 9. The last version is 9.0.50, and its BuildAndSendRequest() code is different than what you showed:

    const
      ProtocolVersionString: array[TIdHTTPProtocolVersion] of string = ('1.0', '1.1'); {do not localize}
      MethodString: array[TIdHTTPMethod] of String = ('HEAD', 'GET', 'POST', 'OPTIONS', 'TRACE', 'PUT', 'DELETE', 'CONNECT'); {do not localize}
    
    ...
    
    procedure TIdHTTPProtocol.BuildAndSendRequest(AURI: TIdURI);
    var
      ...
    begin
      ...
      FHTTP.WriteLn(MethodString[Request.Method] + ' ' + Request.URL + ' HTTP/' + ProtocolVersionString[FHTTP.ProtocolVersion]); {do not localize}
      ...
    end;
    

    The very issue you are having trouble with was addressed in the last revision made to Indy 9's IdHTTP.pas file (in SVN revision 35 on Dec 24 2007):

    Updated TIdHTTPProtocol.BuildAndSendRequest() to use a string array of method names instead of using a 'case of' statement, which was originally missing an entry for 'hmDelete'.

    You need to upgrade to an up-to-date version of Indy 9 (if not to Indy 10).

    If that is not an option, then you will have to edit your current copy of IdHTTP.pas to add the missing hmDelete case, and then recompile Indy.