The get_directory_contents
function is our powerful Oracle PL/SQL solution for querying directory contents from a Nextcloud server. By using the UTL_HTTP
package to interact with Nextcloud's WebDAV interface, the function can list files and directories, providing metadata such as filenames, modification dates, file sizes, and MIME types.
Below is a detailed walkthrough of the function, along with the full code.
Full Code of get_directory_contents
Function
FUNCTION get_directory_contents(p_dir VARCHAR2) RETURN DIR_TABLE
AS
v_wallet_path VARCHAR2(400);
v_wallet_password VARCHAR2(200);
v_url VARCHAR2(1000);
v_username VARCHAR2(1000);
v_password VARCHAR2(1000);
v_http_request UTL_HTTP.req;
v_http_response UTL_HTTP.resp;
v_response_text CLOB;
dirList DIR_TABLE := DIR_TABLE();
entrytype VARCHAR2(5);
v_name VARCHAR2(100);
BEGIN
p_log.log_debug('retrieve nextcloud dir contents: ' || p_dir);
UTL_HTTP.SET_COOKIE_SUPPORT(TRUE);
v_wallet_path := p_adm.get_param('wallet_path','');
v_wallet_password := p_adm.get_param_base64('wallet_password','');
UTL_HTTP.SET_WALLET(v_wallet_path, v_wallet_password);
v_username := p_adm.get_param('nextcloud_username', '');
v_password := p_adm.get_param_base64('nextcloud_password', '');
v_url := p_adm.get_param('nextcloud_basic_url', '') || UPPER(v_username);
p_log.log_debug('url=' || v_url);
if p_dir is not null then
v_url := v_url || '/' || p_dir ;
end if;
p_log.log_debug('url with dir=' || v_url);
p_log.log_debug('before making utl_http PROPFIND request');
v_http_request := UTL_HTTP.begin_request(v_url, 'PROPFIND', 'HTTP/1.1');
UTL_HTTP.set_authentication(v_http_request, v_username, v_password, 'Basic');
UTL_HTTP.set_header(v_http_request, 'OCS-APIREQUEST', 'true');
UTL_HTTP.set_header(v_http_request, 'Depth', '1');
v_http_response := UTL_HTTP.get_response(v_http_request);
DBMS_LOB.createtemporary(v_response_text, TRUE);
BEGIN
LOOP
DECLARE
v_buffer VARCHAR2(32767);
BEGIN
UTL_HTTP.read_text(v_http_response, v_buffer, 32767);
DBMS_LOB.writeappend(v_response_text, LENGTH(v_buffer), v_buffer);
EXCEPTION
WHEN UTL_HTTP.end_of_body THEN
EXIT;
END;
END LOOP;
END;
UTL_HTTP.end_response(v_http_response);
p_log.log_debug('nextcloud xml response: ' || DBMS_LOB.substr(v_response_text, 10000, 1));
for rec in (select xt.href,xt.lastmodified,xt.contentlength,contenttype
from XMLTABLE (
xmlnamespaces('DAV:' as "d"),
'/d:multistatus/d:response'
PASSING XMLTYPE(v_response_text)
COLUMNS
href VARCHAR2(1000) PATH 'd:href',
lastmodified VARCHAR2(200) PATH 'd:propstat/d:prop/d:getlastmodified',
contentlength NUMBER PATH 'd:propstat/d:prop/d:getcontentlength',
contenttype VARCHAR2(300) PATH 'd:propstat/d:prop/d:getcontenttype'
) xt)
loop
dirList.extend;
if (rec.contentlength is null) then entrytype := 'dir'; else entrytype := 'file'; end if;
if (entrytype = 'file') then
v_name := UTL_URL.unescape(SUBSTR(rec.href, INSTR(rec.href, '/', -1) + 1));
else
v_name := get_lastpart_dir(rec.href);
end if;
dirList(dirList.COUNT) := dir_record(v_name, rec.contentlength, nextcloud_date(rec.lastmodified), rec.contenttype,entrytype);
end loop;
RETURN dirList;
END get_directory_contents;
Detailed Breakdown
1. Authentication Setup
The function initializes secure parameters like wallet path, username, and password:
v_wallet_path := p_adm.get_param('wallet_path','');
v_wallet_password := p_adm.get_param_base64('wallet_password','');
UTL_HTTP.SET_WALLET(v_wallet_path, v_wallet_password);
v_username := p_adm.get_param('nextcloud_username', '');
v_password := p_adm.get_param_base64('nextcloud_password', '');
2. URL Construction
The Nextcloud URL is dynamically built based on the provided directory (p_dir
):
v_url := p_adm.get_param('nextcloud_basic_url', '') || UPPER(v_username);
if p_dir is not null then
v_url := v_url || '/' || p_dir ;
end if;
3. Sending HTTP Request
The PROPFIND
method is configured, and authentication headers are added:
v_http_request := UTL_HTTP.begin_request(v_url, 'PROPFIND', 'HTTP/1.1');
UTL_HTTP.set_authentication(v_http_request, v_username, v_password, 'Basic');
UTL_HTTP.set_header(v_http_request, 'OCS-APIREQUEST', 'true');
UTL_HTTP.set_header(v_http_request, 'Depth', '1');
4. Reading the Response
The XML response is read and stored in a CLOB
:
DBMS_LOB.createtemporary(v_response_text, TRUE);
BEGIN
LOOP
DECLARE
v_buffer VARCHAR2(32767);
BEGIN
UTL_HTTP.read_text(v_http_response, v_buffer, 32767);
DBMS_LOB.writeappend(v_response_text, LENGTH(v_buffer), v_buffer);
EXCEPTION
WHEN UTL_HTTP.end_of_body THEN
EXIT;
END;
END LOOP;
END;
UTL_HTTP.end_response(v_http_response);
5. Parsing XML
XMLTABLE
extracts metadata such as href
, lastmodified
, and contentlength
:
for rec in (select xt.href,xt.lastmodified,xt.contentlength,contenttype
from XMLTABLE (
xmlnamespaces('DAV:' as "d"),
'/d:multistatus/d:response'
PASSING XMLTYPE(v_response_text)
COLUMNS
href VARCHAR2(1000) PATH 'd:href',
lastmodified VARCHAR2(200) PATH 'd:propstat/d:prop/d:getlastmodified',
contentlength NUMBER PATH 'd:propstat/d:prop/d:getcontentlength',
contenttype VARCHAR2(300) PATH 'd:propstat/d:prop/d:getcontenttype'
) xt)
loop
6. Building the Directory List
Each record is stored in the DIR_TABLE
with its type (file or directory):
if (rec.contentlength is null) then entrytype := 'dir'; else entrytype := 'file'; end if;
if (entrytype = 'file') then
v_name := UTL_URL.unescape(SUBSTR(rec.href, INSTR(rec.href, '/', -1) + 1));
else
v_name := get_lastpart_dir(rec.href);
end if;
dirList(dirList.COUNT) := dir_record(v_name, rec.contentlength, nextcloud_date(rec.lastmodified), rec.contenttype,entrytype);
How to Use
This function allows Oracle developers to seamlessly retrieve directory contents from Nextcloud, making it easier to integrate cloud storage with enterprise databases.
The function can be further customized for specific needs, such as deeper directory traversal, additional metadata retrieval, or extended error handling.