Watch, Follow, &
Connect with Us

For forums, blogs and more please visit our
Developer Tools Community.


Welcome, Guest
Guest Settings
Help

Thread: Delphi XE7, fmx, IdWebdav access with Indy Components problem on Owncloud


This question is answered. Helpful answers available: 2. Correct answers available: 1.


Permlink Replies: 3 - Last Post: Aug 1, 2016 12:02 PM Last Post By: Remy Lebeau (Te...
K-A Feucht

Posts: 3
Registered: 9/23/01
Delphi XE7, fmx, IdWebdav access with Indy Components problem on Owncloud  
Click to report abuse...   Click to reply to this thread Reply
  Posted: Jul 27, 2016 9:00 AM
Hello,
i do have a problem acessing calendars on an owncloud server.

After much trial and errors i found out that i can access the server like this:

procedure TForm1.Button2Click(Sender: TObject);
var
lhttp: tidwebdav;
s : string;
ts_xml, ts_res : tstringstream;
begin
ts_xml := tstringstream.Create(
'<propfind xmlns="DAV:">' + #10 +
' <allprop />' + #10 +
'</propfind>'
);

ts_res := tstringstream.Create;

lHTTP := TIdWebDav.Create(nil);
lHTTP.IOHandler := TIdSSLIOHandlerSocketOpenSSL.Create(nil);
try
lhttp.Request.Username := 'user';
lhttp.Request.Password := 'password';
lhttp.Request.ContentType := 'text/html';
lhttp.Request.Charset := 'utf-8';
lhttp.HandleRedirects := true;
lhttp.AllowCookies := true;
lhttp.URL.URI := '/remote.php/caldav/principals/user/';
lhttp.URL.Host := 'https://IP-NUMBER';
lhttp.Request.BasicAuthentication := true;
lHTTP.DAVPropFind('https://IP-UMBER/remote.php/caldav/calendars/user/', ts_xml, ts_res);

ts_res.Position := 0;
memo1.text := ts_res.ReadString(ts_res.Size);

finally
lHTTP.Free;
ts_res.Free;
ts_xml.Free;
end;

end;

The server answers with code 200 OK.
But it does not list the calendars on the server.

The same syntax with curl on command line lists all calendars.

Does someone have a tip ? Or a place with more documentation for the component ?
Unfortunately there are not much examples on the internet for that.

Thank you all
Karl-Anton
Eli M

Posts: 1,346
Registered: 11/9/13
Re: Delphi XE7, fmx, IdWebdav access with Indy Components problem on Owncloud  
Click to report abuse...   Click to reply to this thread Reply
  Posted: Jul 30, 2016 5:30 AM   in response to: K-A Feucht in response to: K-A Feucht
Run both connections through http://www.telerik.com/fiddler and compare what is being sent in both. Modify the Delphi HTTP header until it matches the CURL one.
K-A Feucht

Posts: 3
Registered: 9/23/01
Re: Delphi XE7, fmx, IdWebdav access with Indy Components problem on Owncloud  
Click to report abuse...   Click to reply to this thread Reply
  Posted: Jul 31, 2016 6:21 AM   in response to: Eli M in response to: Eli M
Eli M wrote:
Run both connections through http://www.telerik.com/fiddler and compare what is being sent in both. Modify the Delphi HTTP header until it matches the CURL one.

Hi Eli,
thank you for the tip. With this I was able to solve the problem.

The final code looks like this:
procedure TForm1.Button2Click(Sender: TObject);
var
  lhttp: tidwebdav;
  s : string;
  ts_xml, ts_res : tstringstream;
begin
  ts_xml := tstringstream.Create(
                     '<d:propfind xmlns:d="DAV:" xmlns:cs="http://calendarserver.org/ns/">' + #10 +
                     '  <d:prop>' + #10 +
                     '    <d:displayname />' + #10 +
                     '    <cs:getctag />' + #10 +
                     '  </d:prop>' + #10 +
                     '</d:propfind>');
 
  ts_xml.Position := 0;
  Memo1.Lines.Text := ts_xml.ReadString(ts_xml.Size);
 
  ts_res := tstringstream.Create;
  ts_res.Seek(0,0);
 
  lHTTP := TIdWebDav.Create(nil);
  lHTTP.IOHandler := TIdSSLIOHandlerSocketOpenSSL.Create(nil);
  try
    lhttp.Request.Username := 'user';
    lhttp.Request.Password := 'password';
    lhttp.Request.ContentType := 'text/html';
    lhttp.Request.Charset := 'utf-8';
    lhttp.HandleRedirects := true;
    lhttp.AllowCookies := true;
    lhttp.Request.Method := 'PROPFIND';
    lhttp.Request.Source := ts_res;
    lhttp.URL.URI := '/remote.php/caldav/calendars/user/';
    lhttp.URL.Host := 'https://IP-Server';
 
    lhttp.Request.BasicAuthentication := true;
    lHTTP.DAVPropFind('https://IP-SERVER/remote.php/caldav/calendars/user/', ts_xml, ts_res, '1');
 
    ts_res.Position := 0;
    memo1.text := ts_res.ReadString(ts_res.Size);
    memo1.Text := stringreplace(memo1.text, '><'>' + #10 + '<', [ rfreplaceall ]);
 
  finally
    lHTTP.Free;
    ts_res.Free;
    ts_xml.Free;
  end;
 
end;
 


So the main problem - how easy - was the depth-flag in the HTTPS-Request. IDWebDav sets depth 0 an must be override with 1.
The question for ctag also works now with the correct syntax against an owncloud server.

Thank you very much !
Karl-Anton
Remy Lebeau (Te...


Posts: 9,447
Registered: 12/23/01
Re: Delphi XE7, fmx, IdWebdav access with Indy Components problem onOwncloud  
Click to report abuse...   Click to reply to this thread Reply
  Posted: Aug 1, 2016 12:02 PM   in response to: K-A Feucht in response to: K-A Feucht
K-A Feucht wrote:

Memo1.Lines.Text := ts_xml.ReadString(ts_xml.Size);

You should be using the DataString property instead:

Memo1.Lines.Text := ts_xml.DataString;


Either way, you should be resetting the stream's Position back to 0 after
reading the XML from the stream:

ts_xml.Position := 0;


Otherwise, you may end up not even posting any XML to the server at all.

A better solution would be to write the XML to a string first, and then wrap
that string in a TStringStream only when you are ready to post it:

s := '<d:propfind xmlns:d="DAV:" xmlns:cs="http://calendarserver.org/ns/">' 
+ #10 +
      ' <d:prop>' + #10 +
      ' <d:displayname />' + #10 +
      ' <cs:getctag />' + #10 +
      ' </d:prop>' + #10 +
      '</d:propfind>';
 
Memo1.Lines.Text := s;
 
ts_xml := tstringstream.Create(s);
...


ts_res := tstringstream.Create;
ts_res.Seek(0,0);

There is no point in seeking an empty stream.

lHTTP := TIdWebDav.Create(nil);
lHTTP.IOHandler := TIdSSLIOHandlerSocketOpenSSL.Create(nil);
try

The assignment of the IOHandler should be inside the 'try' block. And
you are leaking the TIdSSLIOHandlerSocketOpenSSL object as you are not assigning
an Owner to it or Free()'ing it manually.

lhttp.Request.ContentType := 'text/html';

That is wrong. Your are posting XML, not HTML, so you should be using a
ContentType that is appropriate for XML, such as "text/xml". See RFC 2376
"XML Media Types" (https://tools.ietf.org/html/rfc2376), which is what the
WebDAV protocol spec refers to.

lhttp.Request.Charset := 'utf-8';

This assignment itself is fine, but your input TStringStream is not actually
using UTF-8. In this particular example, your input XML does not contain
any non-ASCII characters, so it does not really matter. But you should be
passing TEncoding.UTF8 to the TStringStream constructor in general, in case
you ever do need to send non-ASCII characters in the future.

lhttp.Request.Method := 'PROPFIND';
lhttp.Request.Source := ts_res;
lhttp.URL.URI := '/remote.php/caldav/calendars/user/';
lhttp.URL.Host := 'https://IP-Server';

Do not perform those assignments manually at all. Especially considering
that 3 of them are incorrect anyway. DAVPropFind() handles them internally
for you. Remove them from your code.

memo1.text := ts_res.ReadString(ts_res.Size);
memo1.Text := stringreplace(memo1.text, '><'>' + #10 + '<'><'>' + #10 + '<', [ rfreplaceall
]);
{code}

--
Remy Lebeau (TeamB)
Legend
Helpful Answer (5 pts)
Correct Answer (10 pts)

Server Response from: ETNAJIVE02