Question

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?

Was it helpful?

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;
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top