Using libdavix

File interface

Most methods in the Davix::DavFile API come with an exception safe version which accepts a DavixError* as an argument, and a version which throws DavixException instead.

  • Instantiate a new DavFile.

Context c;
DavFile file(c, Uri("http://example.org/dir1/file1"));
  • Get all replicas associated to a file.

Context c;
DavixError* err = NULL;
DavFile file(c, Uri("http://example.org/dir1/file1"));
std::vector<DavFile> resultVec;
resultVec = file.getReplicas(NULL, &err);
  • Execute a vector read operation.

Context c;
DavixError* err = NULL;
DavFile file(c, Uri("http://example.org/dir1/file_to_read"));

int number_of_vector = 2;
DavIOVecInput input_vector[number_of_vector];
DavIOVecOutput output_vector[number_of_vector];

// Setup vector operations parameters
char buf1[255] = {0};
char buf2[255] = {0};

input_vector[0].diov_offset = 100;
input_vector[0].diov_size = 200;
input_vector[0].diov_buffer = buf1;

input_vector[1].diov_offset = 600;
input_vector[1].diov_size = 150;
input_vector[1].diov_buffer = buf2;

// execute query
file.readPartialBufferVec(NULL, input_vector, output_vector, number_of_vector, &err);

std::cout << "Op 1 read " << output_vector[0].diov_size << "bytes" << std::endl;
std::cout << "Op 2 read " << output_vector[1].diov_size << "bytes" << std::endl;

// do things with content in output_vector[0].diov_buffer etc
  • Write the contents of a remote file to a local file descriptor.

Context c;
DavixError* err = NULL;
DavFile file(c, Uri("http://example.org/dir1/file_to_download"));
int fd = open("/tmp/local_file" O_WRONLY, O_CREAT);
// get full file
file.getToFd(NULL, fd, &err);

// get first 200 bytes from file
file.getToFd(NULL, fd, 200, &err);
  • Download parts of a file with a single-range GET

Context c;
char buffer[255];
DavFile file(c, Uri("http://example.org/dir1/file_to_download"));

// get 100 bytes from http://example.org/dir1/file_to_download at offset 200
file.readPartial(NULL, buffer, 100, 200);
  • Download full file contents to a dynamically allocated buffer.

Context c;
DavixError* err = NULL;
DavFile file(c, Uri("http://example.org/file_to_download"));
std::vector<char> buffer;

// warning, this operation has no size limit regarding the content
file.getFull(NULL, buffer, &err);

// do things with buffer
// ...
  • Create or replace a remote file with the contents of a file descriptor.

Context c;
DavFile file(c, Uri("http://example.org/file_to_create"));

int fd = open("/tmp/file_to_upload", O_RDONLY);

// get file size
struct stat st;
fstat(fd, &st);

// execute put
file.put(NULL, fd, static_cast<dav_size_t>(st.st_size));
  • Create or replace a remote file with the contents of a buffer.

Context c;
DavFile file(c, Uri("http://example.org/file_to_create"));

char buffer[255];

// fills buffer with something useful

// execute put
file.put(NULL, &buffer, static_cast<dav_size_t>sizeof(buffer));
  • Create or replace a remote file with contents provided by a callback function.

// data provider
int myDataProvider(void* buffer, dav_size_t max_size){
    static dav_size_t content_size = 200;
    if(max_size == 0)
        return 0;
    else{
        char my_useful_content[255]={1};
        int bytes_to_write = (max_size<content_size)?max_size:content_size;

        memcpy(buffer, my_useful_content, bytes_to_write);

        content_size -= bytes_to_write;
        return bytes_to_write;
    }
}

int main(int argc, char** argv){
    Context c;
    DavFile file(c, Uri("http://example.org/file_to_create"));

    // set data provider callback
    DataProviderFun dataCB = myDataProvider;

    // execute put and write 100 bytes using data from callback
    file.put(NULL, dataCB, 100);
}
  • Move a remote resource to another location.

Context c;
DavFile source(c, Uri("http://example.org/old_location"));
DavFile destination(c, Uri("http://example.org/new_location"));

source.move(NULL, destination);
  • Delete a collection or a directory.

Context c;
DavixError* err = NULL;

// delete a WebDAV collection
DavFile myDavCollection(c, Uri("davs://example.org/collection_to_delete"));
myDavCollection.deletion(NULL, &err);

// to delete a S3 bucket (note: bucket has to be empty or operation will fail)
// setup S3 authorisation keys
RequestParams params;
params.setAwsAuthorizationKeys("xxxxx", "yyyyy");
DavFile myS3Bucket(c, Uri("s3://bucket_to_delete.example.org"));
myS3Bucket.deletion(&params, &err);
  • Create a collection or directory.

Context c;
DavixError* err = NULL;
// Instantiate RequestParams object to hold request options
RequestParams params;

// to create a WebDav collection
DavFile myDavCollection(c, Uri("dav://example.org/collection_to_create"));
myDavCollection.makeCollection(NULL, &err);

// to create a new S3 bucket
// first we need to setup S3 authorisation keys for this request
params.setAwsAuthorizationKeys("xxxxx", "yyyyy");
DavFile myS3Bucket(c, Uri("s3://bucket_to_create.example.org"));
myS3Bucket.makeCollection(&params, &err);
  • Query basic file metadata.

Contect c;
DavFile file(c, Uri("http://example.org/dir/file_to_stat"));

StatInfo info;
file.stat(NULL, info);
std::cout << "my file is " << info.size << " bytes large " << std::endl;
std::cout << " mode : 0" << std::oct << info.mode << std::endl;
std::cout << " atime : " << info.atime << std::endl;
std::cout << " mtime : " << info.mtime << std::endl;
std::cout << " ctime : " << info.ctime << std::endl;
  • List the contents of a collection.

Contect c;
DavFile file(c, Uri("http://example.org/collection_to_list"));

DavFile::Iterator it = file.listCollection(NULL);

// prints out entries' name
do {
    std::cout << it.name() << std::endl;
}while(it.next());
  • Calculate a checksum

Context c;
DavFile file(c, Uri("http://example.org/file_to_checksum"));
std::string chk;

// calculate MD5, also supports CRC32, ADLER32
file.checksum(NULL, chk, "MD5", &err);
std::cout << "MD5 " << chk << std::endl;

POSIX interface

  • Instantiate a new DavPosix

Context c;
DavPosix pos(&c);
  • Query basic file metadata

Contect c;
DavixError* err = NULL;
DavPosix pos(&c);
struct stat info;

pos.stat(NULL, "http://example.org/file_to_stat", &info, &err);

std::cout << " atime : " << info.st_atime << std::endl;
std::cout << " mtime : " << info.st_mtime << std::endl;
std::cout << " ctime : " << info.st_ctime << std::endl;
std::cout << " mode : 0" << std::oct << info.st_mode << std::endl;
std::cout << " len : " << info.st_size << std::endl;
  • Open and read a collection

Context c;
DavixError* err = NULL;
DavPosix pos(&c);

DAVIX_DIR* fd;
struct dirent* entry;

fd = pos.opendir(NULL, "dav://example.org/collection_to_open", &err);

while(entry = pos.readdir(fd, &err)){
    std::cout << entry->d_name << std::endl;
}

pos.closedir(fd, &err);
  • Open and read a collection with per-entry metadata

Context c;
DavixError* err = NULL;
DavPosix pos(&c);

DAVIX_DIR* fd;
struct dirent* entry;
struct stat info;

fd = posix.opendirpp(NULL, "dav://example.org/collection_to_open", &err);

while(entry = pos.readdirpp(fd, &info, &err)){
    std::cout << entry->d_name << "is " << info.st_size << "bytes in size." << std::endl;
}

pos.closedirpp(fd, &err);
  • Create a collection or directory

Context c;
DavixError* err = NULL;
DavPosix pos(&c);

pos.mkdir(NULL, "dav://example.org/collection_to_create", S_IRWXU | S_IRWXG | S_IROTH | S_IXOTH, &err);
  • Rename a file or collection

Context c;
DavixError* err = NULL;
DavPosix pos(&c);

pos.rename(NULL, "http://example.org/myfolder/old_file_name", "http://example.org/myfolder/new_file_name", &err);
  • Remove a file

Context c;
DavixError* err = NULL;
DavPosix pos(&c);

pos.unlink(NULL, "http://example.org/file_to_delete", &err);
  • Remove a collection or directory

Context c;
DavixError* err = NULL;
DavPosix pos(&c);

pos.rmdir(NULL, "dav://example.org/collection_to_remove", &err);
  • Open a file for random I/O (read, partial read, and write)

Context c;
DavixError* err = NULL;
DavPosix pos(&c);

DAVIX_FD* fd;
fd = pos.open(NULL, "http://example.org/myfile", O_RDONLY, &err);

// read 200 bytes from myfile
char buffer[255];
pos.read(fd, &buffer, 200, &err);

// read 50 bytes from myfile at offset 100
char buffer2[255];
pos.pread(fd, &buffer2, 50, 100, &err);
pos.close(fd);

// create a new file and write 200 bytes from buffer to it
fd = pos.open(NULL, "http://example.org/myfolder/mynewfile", O_WRONLY | O_CREAT, &err);
pos.write(fd, &buffer, 200);
pos.close(fd);
  • Vectored read - carry out several read operations in one single request, if the server supports it

Context c;
DavixError* err = NULL;
DavPosix pos(&c);

int number_of_vector = 2;
DavIOVecInput input_vector[number_of_vector];
DavIOVecOuput output_vector[number_of_vector];

DAVIX_FD* fd;
fd = pos.open(NULL, "http://example.org/myfile", O_RDONLY, &err);

// Setup vector operations parameters
char buf1[255] = {0};
char buf2[255] = {0};

input_vector[0].diov_offset = 100;
input_vector[0].diov_size = 200;
input_vector[0].diov_buffer = buf1;

input_vector[1].diov_offset = 600;
input_vector[1].diov_size = 150;
input_vector[1].diov_buffer = buf2;

// execute query
pos.preadVec(fd, input_vector, output_vector, number_of_vector, &err);

std::cout << "Op 1 read " << output_vector[0].diov_size << "bytes" << std::endl;
std::cout << "Op 2 read " << output_vector[1].diov_size << "bytes" << std::endl;

// do things with content in output_vector[0].diov_buffer etc

pos.close(fd);
  • Re-position read/write file offset

Context c;
DavixError* err = NULL;
DavPosix pos(&c);

DAVIX_FD* fd;
fd = pos.open(NULL, "http://example.com/myfile", O_RDONLY, &err);

// position cursor to 200 bytes offset
lseek(fd, 200, SEEK_SET, &err);

// position cursor to current location plus 100 offset
lseek(fd, 100, SEEK_CUR, &err);

// position cursor to end of the file plus offset 200
lseek(fd, 200, SEEK_END, &err);

pos.close(fd);

HTTP requests

The Davix::HttpRequest interface allows you to construct, customise and execute HTTP requests. It also provides methods for retrieving server responses.

Requests can be executed in two ways:

  • Using the executeRequest() method, which will execute the entire request immediately.

  • Using the beginRequest() function, which will initiate a multi-part request. This should be used for requests that expect a large answer. Note that requests initiated by beginRequest() should be closed by using the endRequest().

  • Instantiate a new HttpRequest

Context c;
DavixError* err = NULL;
HttpRequest myrequest(c, "http://example.org/some_useful_stuff", &err);
  • Set the request method

myrequest.setRequestMethod("GET");
  • Configure request parameters

RequestParams params;
params.setUserAgent("MyAwesomeApp");
params.setClientLoginPassword("my_login_name", "my_uber_secure_password");
// ...
myrequest.setParameters(params);
  • Add custom header field

myrequest.addHeaderField("Accept", "application/metalink4+xml");
  • Set the request body

// from a string
std::string content_string
myrequest.setRequestBody(content_string);

// from a buffer
char buffer [255];
// fills buffer with something useful
myrequest.setRequestBody(&buffer, sizeof(buffer));

// from a file descriptor, at offset 100 for 200 bytes
int fd = open("/tmp/myfile", O_RDONLY);
myrequest.setRequestBody(fd, 100, 200);
close(fd);
  • Execute a full request

myrequest.executeRequest(&err);
  • Start a multi-part HTTP request

myrequest.beginRequest(&err);
  • End a multi-part HTTP request

myrequest.endRequest(&err);
  • Read a block of size n bytes from the answer

// read max n bytes to static buffer
char buffer[255];
myrequest.readBlock(&buffer, n, &err);

// read to dynamically sized buffer, with max size n
std::vector<char> buffer2;
myrequest.readBlock(&buffer2, n, &err);
  • Read a segment of size n from the answer

// readSegment calls readBlock repeatedly until n size is read, or end of answer
char buffer[50*1024];
myrequest.readSegment(&buffer, n, &err);
  • Read a line of text from the answer, with a maximum size of n

char buffer[255];
myrequest.readLine(&buffer, n, &err);
  • Write the answer contents to a file descriptor

char buffer[255]
int fd = open("tmp/myfile", O_WRONLY | O_CREAT);

// with no size limit
myrequest.readToFd(fd, &err);

// with 100 bytes limit
myrequest.readToFd(fd, 100, &err);
  • Get size of answer

dav_ssize_t size;
size = myrequest.getAnswerSize();
  • Get response body

// into dynamically sized buffer
std::vector<char> buffer1;
buffer1 = myrequest.getAnswerContentVec();

// into static buffer
const char* buffer2 = myrequest.getAnswerContent();
  • Get the status code of the response

int code;
code = myrequest.getRequestCode();
  • Get last modified time

time_t last_modified;
last_modified = myrequest.getLastModified();
  • Get the value associated with a particular header key

std::string value;
myrequest.getAnswerHeader("Content-Type", &value);
std::cout << "Content-Type is " << value << std::endl;
  • Get all header fields into a vector

HeaderVec headers;
myrequest.getAnswerHeaders(headers);
for(HeaderVec::iterator it = headers.begin(), it < headers.end(); ++it){
    std::cout << it->first << ": " << it->second << std::endl;
}
  • Clear the HttpRequest answer buffer

myrequest.clearAnswerContent();
  • Process then discard the response body

// calls readSegment on the answer repeatedly but do nothing with content
myrequest.discardBody(&err);
  • Use pre-configured requests for specific HTTP operations

Context c;
DavixError* err = NULL;
Uri myuri("http://example.org/myfile");

// Get request
GetRequest req(c, myuri, &err);

// Put request
PutRequest req(c, myuri, &err);

// Head request
HeadRequest req(c, myuri, &err);

// Delete request
DeleteRequest req(c, myuri, &err);

// Propfind request
ProfindRequest req(c, myuri, &err);

Error reporting and exceptions

Davix uses an error reporting system similar to Glib, relying on Davix::DavixError objects to store the scope where an error occurred, the error code, and the error message.

The DavixError objects can be checked on local level, or passed into other functions for error handling, or be propagated back up the stack frame.

Davix also provides a Davix::DavixException class that encapsulates DavixError, for situations where exceptions are more appropriate.

Most functions in the Davix::DavFile API provide an exception safe version that takes a DavixError* as argument, as well as a version that throws DavixException and does not require DavixError.

Davix::DavixError

The DavixError error reporting system can be used when exception throwing behavior is not desirable.

A DavixError object should not be instantiated manually, the DavixError::setupError() function should be used where an error has occurred.

Most functions provided by the APIs accept a pointer to the DavixError type, which if set to NULL, will bypasses the error reporting system. In the event where an error occurs, a new DavixError object is created and its address assigned to the DavixError* passed into the function.

Context c;
DavixError* err = NULL;

// delete a WebDAV collection
DavFile myDavCollection(c, Uri("davs://example.org/collection_to_delete"));
myDavCollection.deletion(NULL, &err);

// check if an error occurred
// if err is not NULL anymore, that means a DavixError object had been created
// if *err is not NULL, the object is valid
if(err && *err){
    std::cerr << err->getErrScope() <<
                 " Error code: " << err->getStatus() <<
                 " Error: " << err->getErrMsg() << std::endl;
}

Davix::DavixException

DavixException is the recommended error handling method when using the DavFile API, it encapsulates a DavixError object which holds information such as the scope where an error occurred, the error code, and the error message.

  • Throw a DavixException

throw DavixException("Where", "What", "This is what has happened...");
  • Catch a DavixException

TRY_DAVIX{
    DavFile myDavCollection(c, Uri("davs://example.org/doomed_to_fail"));
        myDavCollection.deletion(NULL);
}CATCH_DAVIX(&err){
    std::cerr << err->getErrScope() <<
    " Error code: " << err->getStatus() <<
    " Error: " << err->getErrMsg() << std::endl;

    // handle error or propagate
    // ...
}