CloudPolis / webdav-client-cpp

:cloud: C++ WebDAV Client provides easy and convenient to work with WebDAV-servers.
http://cloudpolis.github.io/webdav-client-cpp/
Other
120 stars 51 forks source link

method info() not working #40

Open avocadochicken opened 6 years ago

avocadochicken commented 6 years ago

Returned 'dict_t' from Client::info() has always size zero. I am connecting to an owncload server and the rest seems to work (I can create directories and upload files).

rusdevops commented 6 years ago

@avocadochicken, You can help:

  1. Run script:
    $ git clone https://github.com/CloudPolis/webdav-client-cpp.git
    $ cd webdav-client-cpp
    $ cmake -H. -B_builds -DBUILD_EXAMPLES=ON -DWDC_VERBOSE=ON -DCMAKE_INSTALL_PREFIX=install
    $ cmake --build _builds --target install
    $ export WEBDAV_HOSTNAME =<your_webdav_hostname>
    $ export WEBDAV_USERNAME =<your_webdav_username>
    $ export WEBDAV_PASSWORD =<your_webdav_password>
    $ cd install/bin
    $ ./cli info <your_file_path>
  2. Send screenshot or your log
rusdevops commented 6 years ago

For example: screen shot 2017-08-12 at 9 46 18 pm

rusdevops commented 6 years ago

I deploy OwnCloud version 10.0.2-1 on AWS. The server provide this link for transfering by WebDAV: http://ec2-54-205-59-139.compute-1.amazonaws.com/remote.php/webdav

I tried without setting WEBDAV_ROOT environment variable 🔥

$ export WEBDAV_HOSTNAME=http://ec2-54-205-59-139.compute-1.amazonaws.com/remote.php/webdav

Then I tried with it 🎊

$ export WEBDAV_HOSTNAME=http://ec2-54-205-59-139.compute-1.amazonaws.com
$ export WEBDAV_ROOT=/remote.php/webdav

You can try use that code:

std::map<std::string, std::string> options =
{
    {"webdav_hostname", "your_webdav_hostname"},
    {"webdav_username", "your_webdav_username"},
    {"webdav_password", "your_webdav_password"},
    {"webdav_root",     "your_webdav_root"} // in my case: /remote.php/webdav
};
avocadochicken commented 6 years ago

@rusdevops : Sorry for responding this late. I was on vacations and then my PC broke down, etc... I did a checkout (today), and compiled like your described in your first respond. Win10 + VS2015. Hunter captured all necessary packages while storing them in C:/.hunter ... For my own project I copied them out (include/libs) in order to compile.

Please add line: #include <memory> to client.hpp, otherwise it will not compile out of the box.

Running cli info/list .. and other example commands show a valid response info(....) ! Please check your own posted image. You are just getting the WDC_VERBOSE output. Regarding cli.cpp line 102: auto info = client->info(remote_resource); std::cout << info << std::endl; is not showing anything at stdout (same in your post).

Here is an example code (just if someone needs it in the future, as it gives an idea where to find the other libs....):

#include "stdafx.h"
#include "webdav\client.hpp"

#include <string>
#include <map>
#include <memory>
#include <iostream>

// libwdcd.lib and some includes are defined in project properties... rest is here:
#pragma comment(lib, "C:/.hunter/_Base/d238dc1/b617f0a/3a2d701/Install/lib/libcurld.lib")
#pragma comment(lib, "C:/.hunter/_Base/d238dc1/b617f0a/3a2d701/Install/lib/ssleay32.lib")
#pragma comment(lib, "C:/.hunter/_Base/d238dc1/b617f0a/3a2d701/Install/lib/libeay32.lib")
#pragma comment(lib, "winmm.lib")
#pragma comment(lib, "ws2_32.lib")
#pragma comment(lib, "C:/.hunter/_Base/d238dc1/b617f0a/3a2d701/Install/lib/zlibd.lib")
#pragma comment(lib, "C:/.hunter/_Base/d238dc1/b617f0a/3a2d701/Install/lib/pugixmld.lib")

using dict_t = std::map<std::string, std::string>;
using strings_t = std::vector<std::string>;

auto operator<<(std::ostream& out, const dict_t& dict) -> std::ostream& {
    for (auto& item : dict) {
        out << item.first << ": " << item.second << std::endl;
    }
    return out;
}

auto operator<<(std::ostream& out, const strings_t& dict) -> std::ostream& {
    for (auto& item : dict) {
        out << "- " << item << std::endl;
    }
    return out;
}

int main()
{
    std::map<std::string, std::string> options =
    {
        { "webdav_hostname", "ADD YOUR" },
        { "webdav_username", "DATA" },
        { "webdav_password", "HERE..." }
    };

    std::unique_ptr<WebDAV::Client> client{ new WebDAV::Client{ options } };

    auto remote_resource = "/"; // ADJUST IF NEEDED
    auto info = client->info(remote_resource);
    std::cout << info << std::endl;

    return 0;
}

Problem is: info.size() = 0

rusdevops commented 6 years ago

@avocadochicken, to work out of the box, you must use CMake for your projects as well. for example: https://github.com/CloudPolis/webdav-client-cpp#usage If you provide me a test login and password for your test server. I will try to understand and help solve your problem.

avocadochicken commented 6 years ago

Please mind my last post and your second. To emphasize it again here my command line output:

D:\WebDavGit\webdav-client-cpp\install\bin>cli info TESTFOLDER
* timeout on name lookup is not supported
*   Trying 46.189.16.111...
* Connected to ##DELETED_SUBDOMAIN##.safershare.de (46.189.16.111) port 443 (#0)
* libcurl is now using a weak random seed!
* ALPN, offering http/1.1
* Cipher selection: ALL:!EXPORT:!EXPORT40:!EXPORT56:!aNULL:!LOW:!RC4:@STRENGTH
* SSL connection using TLSv1.2 / ECDHE-RSA-AES256-GCM-SHA384
* ALPN, server accepted to use http/1.1
* Server certificate:
*  subject: C=DE; ST=Baden Wuerttemberg; L=Stuttgart; O=OmegaGate GmbH & Co. KG; OU=IT; CN=*.safershare.de
*  start date: Oct 31 00:00:00 2016 GMT
*  expire date: Oct 31 23:59:59 2019 GMT
*  issuer: C=US; O=thawte, Inc.; CN=thawte SHA256 SSL CA
*  SSL certificate verify result: self signed certificate in certificate chain (19), continuing anyway.
* Server auth using Basic with user '##DELETED_USERNAME##'
> PROPFIND /remote.php/webdav/TESTFOLDER HTTP/1.1
Host: ##DELETED_SUBDOMAIN##.safershare.de
Authorization: Basic ##DELETED_HASH##
Accept: */*
Depth: 1

< HTTP/1.1 207 Multi-Status
< Server: nginx/1.10.3 (Ubuntu)
< Date: Fri, 22 Sep 2017 06:36:08 GMT
< Content-Type: application/xml; charset=utf-8
< Content-Length: 607
< Connection: keep-alive
< Set-Cookie: ##DELETED_HASH##; path=/; HttpOnly
< Expires: Thu, 19 Nov 1981 08:52:00 GMT
< Cache-Control: no-store, no-cache, must-revalidate
< Pragma: no-cache
< Set-Cookie: oc_sessionPassphrase=##DELETED_HASH##; path=/; HttpOnly
< Content-Security-Policy: default-src 'none';
< X-XSS-Protection: 1; mode=block
< X-Content-Type-Options: nosniff
< X-Frame-Options: Sameorigin
< X-Robots-Tag: none
< X-Download-Options: noopen
< X-Permitted-Cross-Domain-Policies: none
< Set-Cookie: ##DELETED_HASH##; path=/; HttpOnly
< Set-Cookie: ##DELETED_HASH##; path=/; HttpOnly
< Vary: Brief,Prefer
< DAV: 1, 3, extended-mkcol
<
* Connection #0 to host ##DELETED_SUBDOMAIN##.safershare.de left intact
<?xml version="1.0"?>
<d:multistatus xmlns:d="DAV:" xmlns:s="http://sabredav.org/ns" xmlns:oc="http://owncloud.org/ns">
        <d:response>
                <d:href>/remote.php/webdav/TESTFOLDER/</d:href>
                <d:propstat>
                        <d:prop>
                                <d:getlastmodified>Thu, 21 Sep 2017 08:58:03 GMT</d:getlastmodified>
                                <d:resourcetype>
                                        <d:collection />
                                </d:resourcetype>
                                <d:quota-used-bytes>0</d:quota-used-bytes>
                                <d:quota-available-bytes>-3</d:quota-available-bytes>
                                <d:getetag>"59c37f1b9be28"</d:getetag>
                        </d:prop>
                        <d:status>HTTP/1.1 200 OK</d:status>
                </d:propstat>
        </d:response>
</d:multistatus>
THIS IS INFO (size: 0) OUTPUT

I updated the webdav-client-cpp\examples\cli\cli.cpp file in line 103:

} else if (command == "info") {
    auto info = client->info(remote_resource);
    std::cout << "THIS IS INFO (size: " << std::to_string(info.size()) << ") OUTPUT" << std::endl;
    std::cout << info << std::endl;

and compiled with CMAKE.

Mind your picture in your second post. It has the same issue! I am expecting info.size() = 1 and valid info inside

dict_t information = {
    { "created", creation_date.first_child().value() },
    { "name", display_name.first_child().value() },
    { "size", content_length.first_child().value() },
    { "modified", modified_date.first_child().value() },
    { "type", resource_type.first_child().name() }
};

I guess something goes wrong with pugixml.

avocadochicken commented 6 years ago

Further digging: https://github.com/CloudPolis/webdav-client-cpp/blob/master/sources/client.cpp line 452:

if (resource_path_without_sep == target_path_without_sep) {

expression is false in my case. This is why info() returns dict_t{}; My debug output:

target_path = /TESTFOLDER
target_path_without_sep = /
resource_path_without_sep = /remote.php/webdav/TESTFOLDER/

Seems fishy...

avocadochicken commented 6 years ago
<?xml version="1.0"?>
<d:multistatus xmlns:d="DAV:" xmlns:s="http://sabredav.org/ns" xmlns:oc="http://owncloud.org/ns">
        <d:response>
                <d:href>/remote.php/webdav/TESTFOLDER/</d:href>
                <d:propstat>
                        <d:prop>
                                <d:getlastmodified>Fri, 22 Sep 2017 07:29:03 GMT</d:getlastmodified>
                                <d:resourcetype>
                                        <d:collection />
                                </d:resourcetype>
                                <d:quota-used-bytes>0</d:quota-used-bytes>
                                <d:quota-available-bytes>-3</d:quota-available-bytes>
                                <d:getetag>"59c4bbbfcfdb3"</d:getetag>
                        </d:prop>
                        <d:status>HTTP/1.1 200 OK</d:status>
                </d:propstat>
        </d:response>
        <d:response>
                <d:href>/remote.php/webdav/TESTFOLDER/empty.txt</d:href>
                <d:propstat>
                        <d:prop>
                                <d:getlastmodified>Fri, 22 Sep 2017 07:29:03 GMT</d:getlastmodified>
                                <d:getcontentlength>0</d:getcontentlength>
                                <d:resourcetype />
                                <d:getetag>"eedd9be6f360997b9e06552bcf2a7b80"</d:getetag>
                                <d:getcontenttype>text/plain</d:getcontenttype>
                        </d:prop>
                        <d:status>HTTP/1.1 200 OK</d:status>
                </d:propstat>
        </d:response>
</d:multistatus>

Some debug output (I added) of inside for (auto response : responses) line 444 file client.hpp:

[1] INSIDE FOR LOOP
resource_path: /remote.php/webdav/TESTFOLDER/
target_path: /TESTFOLDER
target_path_without_sep: /
resource_path_without_sep: /remote.php/webdav/TESTFOLDER/
[2] INSIDE FOR LOOP
resource_path: /remote.php/webdav/TESTFOLDER/empty.txt
target_path: /TESTFOLDER
target_path_without_sep: /
resource_path_without_sep: /remote.php/webdav/TESTFOLDER/
WanpengShao commented 6 years ago

@avocadochicken I find this problem, too. I have another question: if I get this kind of information, dict_t information = { { "created", creation_date.first_child().value() }, { "name", display_name.first_child().value() }, { "size", content_length.first_child().value() }, { "modified", modified_date.first_child().value() }, { "type", resource_type.first_child().name() } };

How can I get icon information. Because I want to show file icons in my application. not just file name,date, and type.

WanpengShao commented 6 years ago

@rusdevops @avocadochicken When I use the info funciton: After this step request.set(CURLOPT_WRITEDATA, reinterpret_cast(&data));, I could get the data: data = {buffer=0x000000000047f130 "<?xml version=\"1.0\"?>\n<d:multistatus xmlns:d=\"DAV:\" xmlns:s=\"http://sabredav.org/ns\" xmlns:oc=\"http://owncloud.org/ns\">/remote.php/webdav/Photos/</d:href><d:get... ...} But here: `pugi::xml_document document; document.load_buffer(data.buffer, static_cast(data.size));

ifdef WDC_VERBOSE

    document.save(std::cout);

endif

    auto multistatus = document.select_node("*[local-name()='multistatus']").node();
    auto responses = multistatus.select_nodes("*[local-name()='response']");`

response return nullptr. I think it is the pugixml error. So would you pls tell me what should I do to fix it?

avocadochicken commented 6 years ago

@WanpengShao: Please format your text and be more precise about the things you post. For instance, tell which file you are refering to if you post some source. Please help the person you are asking in order to get help. You can switch above your written text from 'Write' to 'Preview' in order to ensure you desired markdown output.

I guess you refer to webdav-client-cpp/blob/master/sources/client.cpp line 428 and following. Yes you are right, the data is there. The debug function outputs it (see rusdevops and my posts). This is working: document.load_buffer(data.buffer, static_cast<size_t>(data.size));

-> The problem lies between lines 442 and 452. You could debug it line by line. Print output of each operation to stdout for instance. You can also post it here, then I might be able to help you. What is the value of multistatus? responses == nullptr right? It worked for me, because as far as I remember (and wrote above) line 452 was evaluated.

To be honest: I moved on and I am busy with other stuff. I used this library to upload files and check existence of them at my remote resource. Doing so I just realised a misbehaving info() function, but I do not needed the correct integration of such a function for my project. This is an open source project, please try to fix the fault and tell us how you did it, if you need this function to work. If I take something, I should give something back.