Search code examples
xmldelphiindy10tastypie

Delphi Indy post error 501


I'm having some troubles trying to post xml to a web service using Indy.

My client is a class in delphi using Indy 10.0.52 and my api server is django-tastypie. My stack on the server is:

Django==1.5.1
defusedxml==0.4.1
django-tastypie==0.10.0
lxml==3.2.3
mimeparse==0.1.3

Other clients (like plain curl, python, js) are posting to the same resources without problems. For example:

$ curl --dump-header - -H "Content-Type: application/xml" -H "Authentication: Basic 875488" -k -X POST --data '<object>...</object>' https://www....object/?format=xml
HTTP/1.1 201 CREATED
Date: Tue, 19 Nov 2013 10:28:01 GMT
Server: Apache/2.2.14 (Ubuntu)
Access-Control-Allow-Headers: Origin,Authorization,Content-Type,Accept
Vary: Accept,Accept-Encoding
Location: https://www....object/12
Access-Control-Allow-Credentials: true
Access-Control-Allow-Origin: *
Access-Control-Allow-Methods: POST,GET,OPTIONS,PUT,DELETE
Content-Length: 0
Content-Type: text/html; charset=utf-8

But using Indy I always get: '501 not implemented'. This is my procedure:

procedure TRestObject.post( postURL:String; doc:IXMLDocument );
var
  aStream : TMemoryStream;
  data : TStringStream;
  xmlString, urlString : String;
begin
  aStream := TMemoryStream.Create;
  data := TStringStream.Create('');
  try
    http.HandleRedirects := True;
    http.ReadTimeout := 50000;
    // encoding
    xmlString := doc.XML.Strings[1];
    urlString := URLencode(xmlString);
    showmessage(xmlString);
    //showmessage(urlString);
    data.WriteString( urlString );
    aStream.Write( urlString[1], Length(urlString) * SizeOf(Char) );
    with http do
    begin
      try
        Response.KeepAlive := False;
        //Post( postURL, data, aStream );
        Post( postURL, aStream );
      except
        on E: EIdException do
          showmessage('Exception (class '+ E.ClassName +'): ' + E.Message);
        on E: EIdHTTPProtocolException do
          showmessage('Protocol Exception (HTTP status '+ IntToStr(E.ErrorCode) +'): ' + E.Message);
        on E: EIdSocketError do
          showmessage('Socket Error ('+ IntToStr(E.LastError) +'): ' + E.Message);
      end;
    end;
  finally
    aStream.Free;
    data.Free;
  end;
end;

'http' is a member instance of Indy TIdHTTP.

Can somebody please point me to what i'm doing wrong?


Solution

  • You are not resetting your stream's Position back to 0 before posting it, you are not even posting the XML stream at all (you commented it out). You are also not taking character encoding into account, or replicating the same properties that you are passing to curl.

    Try this:

    procedure TRestObject.post( postURL:String; doc:IXMLDocument );
    var
      aStream: TMemoryStream;
      data : TStringStream;
      xmlString : String;
    begin
      aStream := TMemoryStream.Create;
      try
        http.HandleRedirects := True;
        http.ReadTimeout := 50000;
        // encoding
        xmlString := doc.XML.Text;
        ShowMessage(xmlString);
        data := TStringStream.Create(xmlString, TEncoding.UTF8);
        try
          http.Request.ContentType := 'application/xml';
          http.Request.Connection := 'close';
          try
            http.Post( postURL, data, aStream );
          except
            on E: EIdHTTPProtocolException do
              ShowMessage('Protocol Exception (HTTP status '+ IntToStr(E.ErrorCode) +'): ' + E.Message);
            on E: EIdSocketError do
              ShowMessage('Socket Error ('+ IntToStr(E.LastError) +'): ' + E.Message);
            on E: Exception do
              ShowMessage('Exception (class '+ E.ClassName +'): ' + E.Message);
          end;
        finally
          data.Free;
        end;
      finally
        aStream.Free;
      end;
    end;