Search code examples
xmldelphi-2007indy10

Post XML with TidHttp Invalid request


I'm trying to post an XML file using Delphi 2007 to make a transaction with WorldPay, but I keep getting an "Invalid request" error.

Here is my code, I can't figure out what I'm doing wrong.

Var
  XDoc, ReturnStr:String;
  XMLToSend, resp: TStringStream;
  IdHTTP1:TIdHTTP;
  IdSSLIOHandlerSocketOpenSSL1: TIdSSLIOHandlerSocketOpenSSL;
begin   
  with Datam1.CCSetupTbl do
  begin
    XDoc := '<?xml version="1.0" encoding="UTF-8"?>' +
            '<TransactionSetup xmlns="https://certtransaction.elementexpress.com">' +
              '<Credentials>' +
                '<AccountID>' + FieldByName('M').AsString + '</AccountID>' +
                '<AccountToken>' + FieldByName('MW').AsString + '</AccountToken>' +
                '<AcceptorID>' + FieldByName('MP').AsString + '</AcceptorID>' +
              '</Credentials>' +
              '<Application>' +
                '<ApplicationID>00000</ApplicationID>' +
                '<ApplicationVersion>7.60.0</ApplicationVersion>' +
                '<ApplicationName>CPOS</ApplicationName>' +
              '</Application>' +
              '<TransactionSetup>' +
                '<TransactionSetupMethod>7</TransactionSetupMethod>' +
                '<Embedded>1</Embedded>' +
                '<CVVRequired>0</CVVRequired>' +
                '<AutoReturn>1</AutoReturn>' +
                '<ReturnURL>http://localhost</ReturnURL>' +
                '<CustomCss>body{margin-left: 50px;}</CustomCss>' +
              '</TransactionSetup>' +
              '<Transaction>' +
                '<TransactionAmount>1.00</TransactionAmount>' +
                '<MarketCode>0</MarketCode>' +
                '<ReferenceNumber>123456</ReferenceNumber>' +
                '<TicketNumber>123456</TicketNumber>' +
                '<PartialApprovedFlag>0</PartialApprovedFlag>' +
              '</Transaction>' +
              '<Terminal>' +
                '<TerminalID>01</TerminalID>' +
                '<TerminalType>0</TerminalType>' +
                '<CardholderPresentCode>0</CardholderPresentCode>' +
                '<CardInputCode>0</CardInputCode>' +
                '<TerminalCapabilityCode>0</TerminalCapabilityCode>' +
                '<TerminalEnvironmentCode>0</TerminalEnvironmentCode>' +
                '<CardPresentCode>0</CardPresentCode>' +
                '<MotoECICode>0</MotoECICode>' +
                '<CVVPresenceCode>0</CVVPresenceCode>' +
              '</Terminal>'+
              '<PaymentAccount>' +
                '<PaymentAccountType>1</PaymentAccountType>' +
                '<PaymentAccountReferenceNumber>' + CusAccount + '</PaymentAccountReferenceNumber>' +
              '</PaymentAccount>' +
            '</TransactionSetup>';
  end;
  Try
    IdHTTP1 := TIdHTTP.Create;
    with IdHTTP1 do
    begin
      Request.Accept := 'text/html';
      Request.ContentType := 'text/html';
      Request.CharSet := 'utf-8';
      Request.CacheControl := 'no-cache';
      ReadTimeout := 30000;
      ConnectTimeout := 30000;
      Request.BasicAuthentication := False;
      Request.UserAgent := 'Mozilla/3.0 (compatible; Indy Library)';
      HTTPOptions := [hoForceEncodeParams];
    end;

    IdSSLIOHandlerSocketOpenSSL1:= TIdSSLIOHandlerSocketOpenSSL.Create;
    IdSSLIOHandlerSocketOpenSSL1.SSLOptions.SSLVersions:= [sslvTLSv1_2];
    IdSSLIOHandlerSocketOpenSSL1.SSLOptions.Method := sslvTLSv1_2;
    IdHttp1.IOHandler := IdSSLIOHandlerSocketOpenSSL1;
    XMLToSend := TStringStream.Create(XDoc);

    ReturnStr := IdHTTP1.Post('https://certtransaction.elementexpress.com', XMLToSend);
  finally
    IdHTTP1.Free;
    IdSSLIOHandlerSocketOpenSSL1.Free;
    XMLToSend.Free;
  end;

Solution

  • Well, for starters, you are telling the server that you are posting HTML instead of XML. 'text/html' is the wrong Content-Type for XML.

    Second, you are not escaping the values you insert into your XML, if they happen to contain any reserved characters. You really should be using a proper XML library to prepare your post data.

    Lastly, your exception handling is not structured very well.

    Try this instead:

    Var
      XDoc, ReturnStr: String;
      XMLToSend: TStringStream;
      IdHTTP1: TIdHTTP;
      IdSSLIOHandlerSocketOpenSSL1: TIdSSLIOHandlerSocketOpenSSL;
    begin   
      with Datam1.CCSetupTbl do
      begin
        XDoc := ...;
      end;
      IdHTTP1 := TIdHTTP.Create;
      try
        with IdHTTP1 do
        begin
          Request.Accept := 'text/html';
          Request.ContentType := 'text/xml'; // or 'application/xml', or whatever the server actually expects...
          Request.CharSet := 'utf-8';
          Request.CacheControl := 'no-cache';
          ReadTimeout := 30000;
          ConnectTimeout := 30000;
          Request.BasicAuthentication := False;
          Request.UserAgent := 'Mozilla/3.0 (compatible; Indy Library)';
          HTTPOptions := [hoForceEncodeParams];
        end;
    
        IdSSLIOHandlerSocketOpenSSL1 := TIdSSLIOHandlerSocketOpenSSL.Create(IdHTTP1);
        IdSSLIOHandlerSocketOpenSSL1.SSLOptions.SSLVersions := [sslvTLSv1_2];
        IdHTTP1.IOHandler := IdSSLIOHandlerSocketOpenSSL1;
    
        XMLToSend := TStringStream.Create(XDoc);
        try
          ReturnStr := IdHTTP1.Post('https://certtransaction.elementexpress.com', XMLToSend);
        finally
          XMLToSend.Free;
        end;
      finally
        IdHTTP1.Free;
      end;