--
-- $Id: DET_S3.sql,v 1.5 2009/06/19 16:39:59 ddimitrov Exp $
--
-- This file is part of the OpenLink Software Virtuoso Open-Source (VOS)
-- project.
--
-- Copyright (C) 1998-2009 OpenLink Software
--
-- This project is free software; you can redistribute it and/or modify it
-- under the terms of the GNU General Public License as published by the
-- Free Software Foundation; only version 2 of the License, dated June 1991.
--
-- This program is distributed in the hope that it will be useful, but
-- WITHOUT ANY WARRANTY; without even the implied warranty of
-- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
-- General Public License for more details.
--
-- You should have received a copy of the GNU General Public License along
-- with this program; if not, write to the Free Software Foundation, Inc.,
-- 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
--
-------------------------------------------------------------------------------
--
create function DB.DBA.S3__encode (
in S varchar)
{
S := sprintf ('%U', S);
S := replace(S, '''', '%27');
S := replace(S, '%2F', '/');
return S;
}
;
-------------------------------------------------------------------------------
--
create function DB.DBA.S3__params (
in colID integer,
out bucket varchar,
out accessCode varchar,
out secretKey varchar)
{
bucket := DB.DBA.DAV_PROP_GET_INT (colID, 'C', 'virt:S3-BucketName', 0);
accessCode := DB.DBA.DAV_PROP_GET_INT (colID, 'C', 'virt:S3-AccessKeyID', 0);
secretKey := DB.DBA.DAV_PROP_GET_INT (colID, 'C', 'virt:S3-SecretKey', 0);
}
;
-------------------------------------------------------------------------------
--
create function DB.DBA.S3__parts2path (
in bucket varchar,
in pathParts any,
in what any)
{
-- dbg_obj_princ ('S3__parts2path (', bucket, pathParts, ')');
declare path varchar;
path := DB.DBA.DAV_CONCAT_PATH (pathParts, null);
if ((path <> '') and (chr (path[0]) <> '/'))
path := '/' || path;
if (bucket <> '')
path := '/' || bucket || path;
-- dbg_obj_princ ('path', path);
path := rtrim (path, '/') || case when (what = 'C') then '/' end;
return path;
}
;
-------------------------------------------------------------------------------
--
create function DB.DBA.S3__item2entry (
in detcolID integer,
in detcolPath varchar,
in bucket varchar,
in item any)
{
-- dbg_obj_princ ('DB.DBA.S3__item2entry (', detcolID, detcolPath, bucket, item, ')');
declare entryPath, entryType varchar;
declare detcolEntry any;
if (item is null)
return null;
detcolEntry := DB.DBA.DAV_DIR_SINGLE_INT (detcolID, 'C', '', null, null, http_dav_uid ());
entryPath := get_keyword ('path', item);
if (not is_empty_or_null (bucket))
entryPath := subseq (entryPath, length (bucket)+1);
entryType := get_keyword ('type', item);
if ('C' = entryType)
return vector (detcolPath || ltrim (entryPath, '/'), -- 0 full path
entryType, -- 1 type
get_keyword ('size', item), -- 2 size
get_keyword ('updated', item), -- 3 modification time
vector (UNAME'S3', detcolID, entryPath), -- 4 id
detcolEntry[5], -- 5 permissions
detcolEntry[6], -- 6 group
detcolEntry[7], -- 7 owner
get_keyword ('updated', item), -- 8 creation time
'dav/unix-directory', -- 9 mime type
get_keyword ('name', item) -- 10 name
);
if ('R' = entryType)
return vector (detcolPath || ltrim (entryPath, '/'), -- 0 full path
entryType, -- 1 type
get_keyword ('size', item), -- 2 size
get_keyword ('updated', item), -- 3 modification time
vector (UNAME'S3', detcolID, entryPath), -- 4 id
detcolEntry[5], -- 5 permissions
detcolEntry[6], -- 6 group
detcolEntry[7], -- 7 owner
get_keyword ('updated', item), -- 8 creation time
http_mime_type (detcolPath || entryPath), -- 9 mime type
get_keyword ('name', item) -- 10 name
);
}
;
create function DB.DBA.S3__headers2item (
in headers varchat,
in s3Path varchar,
in what varchar)
{
declare item any;
item := vector ('path', s3Path,
'name', DB.DBA.S3__getNameFromUrl (s3Path),
'type', what,
'etag', http_request_header (headers, 'ETag'),
'size', cast (http_request_header (headers, 'Content-Length') as integer),
'mimeType', http_request_header (headers, 'Content-Type'),
'updated', http_string_date (http_request_header (headers, 'Last-Modified'))
);
return item;
}
;
-------------------------------------------------------------------------------
--
create function DB.DBA.S3__makeHostUrl (
in path varchar,
in isSecure integer := 1)
{
declare hostUrl, bucket, dir varchar;
declare s3Protocol, s3URL varchar;
if (isSecure)
{
s3Protocol := 'http://';
s3URL := 'http://s3.amazonaws.com';
} else {
s3Protocol := 'http://';
s3URL := 'http://s3.amazonaws.com';
}
path := ltrim (path, '/');
bucket := DB.DBA.S3__getBucketFromUrl (path);
dir := '';
if (length (bucket) < length (path))
dir := subseq (path, length (bucket)+1);
if ((lcase (bucket) = bucket) and (bucket <> ''))
{
hostUrl := s3Protocol || bucket || '.s3.amazonaws.com/' || dir;
} else {
if (bucket <> '')
bucket := bucket || '/';
hostUrl := s3Protocol || 's3.amazonaws.com/' || bucket || dir;
}
return hostUrl;
}
;
-------------------------------------------------------------------------------
--
create function DB.DBA.S3__getBucketFromUrl (
in url varchar)
{
declare parts any;
parts := split_and_decode (trim (url, '/'), 0, '\0\0/');
if (length (parts) <> 0)
return parts[0];
return '';
}
;
-------------------------------------------------------------------------------
--
create function DB.DBA.S3__getNameFromUrl (
in url varchar)
{
declare parts any;
parts := split_and_decode (trim (url, '/'), 0, '\0\0/');
if (length (parts) <> 0)
return parts[length (parts) - 1];
return '';
}
;
-------------------------------------------------------------------------------
--
create function DB.DBA.S3__getPathFromUrl (
in url varchar)
{
declare bucket any;
bucket := DB.DBA.S3__getBucketFromUrl (url);
if (isnull (bucket))
return '';
return ltrim (subseq (url, length (bucket)+1), '/');
}
;
-------------------------------------------------------------------------------
--
create function DB.DBA.S3__makeAWSHeader (
in accessCode varchar,
in secretKey varchar,
in authHeader varchar,
in authMode integer := 0)
{
declare S, T, hmacKey varchar;
hmacKey := xenc_key_RAW_read (null, encode_base64 (secretKey));
S := xenc_hmac_sha1_digest (authHeader, hmacKey);
xenc_key_remove (hmacKey);
T := sprintf ('AWS %s:%s', accessCode, S);
if (authMode)
T := 'Authorization:' || T;
return T;
}
;
-------------------------------------------------------------------------------
--
create function DB.DBA.S3__getBuckets (
in accessCode varchar,
in secretKey varchar,
in bucket varchar := null)
{
-- dbg_obj_princ ('DB.DBA.S3__getBuckets (', accessCode, secretKey, ')');
declare dateUTC, authHeader, path, S varchar;
declare reqHdr, resHdr varchar;
declare xt, xtItems, buckets any;
path := '/';
dateUTC := date_rfc1123 (now());
S := sprintf ('GET\n\n\n%s\n%s', dateUTC, path);
authHeader := DB.DBA.S3__makeAWSHeader (accessCode, secretKey, S);
reqHdr := sprintf ('Authorization: %s\r\nDate: %s', authHeader, dateUTC);
commit work;
xt := http_client_ext (DB.DBA.S3__makeHostUrl (path),
http_method=>'GET',
http_headers=>reqHdr,
headers=>resHdr);
-- dbg_obj_princ ('xt', xt);
if (resHdr[0] like 'HTTP/1._ 4__ %' or resHdr[0] like 'HTTP/1._ 5__ %')
{
-- dbg_obj_princ ('xt', xt);
return null;
}
buckets := vector ();
xt := xml_tree_doc (xt);
xtItems := xpath_eval ('//Buckets/Bucket', xt, 0);
foreach (any xtItem in xtItems) do
{
declare name, creationDate any;
name := cast (xpath_eval ('./Name', xtItem) as varchar);
if ((name = bucket) or isnull (bucket))
{
creationDate := stringdate (cast (xpath_eval ('./CreationDate', xtItem) as varchar));
buckets := vector_concat (buckets, vector (
vector ('path', '/' || name || '/',
'name', name,
'type', 'C',
'updated', creationDate,
'size', 0
)
)
);
}
}
return buckets;
}
;
-------------------------------------------------------------------------------
--
-- select DB.DBA.S3__getBucket ('19T7EE0DC8XBDGF6SPG2', '7uCNPezCuQaaJzGasAxqnvb8DPhUZ3u0gVZy5GKG', '/openlink-test/probica/');
--
create function DB.DBA.S3__getBucket (
in accessCode varchar,
in secretKey varchar,
in url varchar,
in delimiter varchar := '/')
{
-- dbg_obj_princ ('DB.DBA.S3__getBucket (', accessCode, secretKey, url, ')');
declare N integer;
declare dateUTC, authHeader, S, bucket, bucketPath varchar;
declare reqHdr, resHdr, params varchar;
declare xt, xtItems, buckets any;
-- ?prefix=prefix;marker=marker;max-keys=max-keys;delimiter=delimiter
bucket := '/' || DB.DBA.S3__getBucketFromUrl (url) || '/';
bucketPath := DB.DBA.S3__getPathFromUrl (url);
dateUTC := date_rfc1123 (now());
S := sprintf ('GET\n\n\n%s\n%s', dateUTC, bucket);
authHeader := DB.DBA.S3__makeAWSHeader (accessCode, secretKey, S);
reqHdr := sprintf ('Authorization: %s\r\nDate: %s', authHeader, dateUTC);
params := sprintf ('?prefix=%U&marker=%s&delimiter=%s', bucketPath, '', delimiter);
commit work;
xt := http_client_ext (url=>DB.DBA.S3__makeHostUrl (bucket) || params,
http_method=>'GET',
http_headers=>reqHdr,
headers=>resHdr);
-- dbg_obj_princ ('xt', xt);
if (resHdr[0] like 'HTTP/1._ 4__ %' or resHdr[0] like 'HTTP/1._ 5__ %')
{
-- dbg_obj_princ ('DB.DBA.S3__getBucket - resHdr[0]', resHdr[0]);
return null;
}
-- dbg_obj_princ ('xt', xt);
buckets := vector ();
xt := xml_tree_doc (xt);
xtItems := xpath_eval ('//Contents', xt, 0);
foreach (any xtItem in xtItems) do
{
declare keyName, itemPath, itemName, itemType, lastModified, itemSize, itemETag any;
keyName := cast (xpath_eval ('./Key', xtItem) as varchar);
keyName := replace (keyName, bucketPath, '');
itemName := replace (keyName, '_\$folder\$', '');
itemType := case when (itemName <> keyName) then 'C' else 'R' end;
itemPath := url || itemName || case when (itemType = 'C') then '/' end;
lastModified := stringdate (cast (xpath_eval ('./LastModified', xtItem) as varchar));
itemSize := cast (xpath_eval ('./Size', xtItem) as integer);
itemETag := cast (xpath_eval ('./ETag', xtItem) as varchar);
buckets := vector_concat (buckets, vector (
vector ('path', itemPath,
'name', itemName,
'type', itemType,
'updated', lastModified,
'size', itemSize,
'etag', itemETag
)
)
);
}
return buckets;
}
;
-------------------------------------------------------------------------------
--
create function DB.DBA.S3__putObject (
in accessCode varchar,
in secretKey varchar,
in s3Path varchar,
inout s3Content any,
inout s3Type any)
{
-- dbg_obj_princ ('DB.DBA.S3__putObject (', accessCode, secretKey, s3Path, s3Content, s3Type, ')');
declare dateUTC, authHeader, S, what, workPath varchar;
declare reqHdr, resHdr, xt varchar;
what := case when (chr (s3Path [length (s3Path) - 1]) = '/') then 'C' else 'R' end;
workPath := DB.DBA.S3__encode (s3Path);
if (trim (s3Path, '/') <> DB.DBA.S3__getBucketFromUrl (s3Path))
workPath := rtrim (workPath, '/') || case when (what = 'C') then '_\$folder\$' end;
dateUTC := date_rfc1123 (now());
S := sprintf ('PUT\n\n%s\n%s\n%s', coalesce (s3Type, ''), dateUTC, workPath);
authHeader := DB.DBA.S3__makeAWSHeader (accessCode, secretKey, S);
reqHdr := sprintf ('Authorization: %s\r\nDate: %s', authHeader, dateUTC);
if (not isnull (s3Type))
reqHdr := sprintf ('%s\r\nContent-Type: %s', reqHdr, s3Type);
if (not isnull (s3Content))
reqHdr := sprintf ('%s\r\nContent-Length: %d', reqHdr, length(s3Content));
commit work;
xt := http_client_ext (url=>DB.DBA.S3__makeHostUrl (workPath),
http_method=>'PUT',
http_headers=>reqHdr,
headers=>resHdr,
body=>s3Content);
if (resHdr[0] like 'HTTP/1._ 4__ %' or resHdr[0] like 'HTTP/1._ 5__ %')
{
-- dbg_obj_princ ('xt', xt);
return -1;
}
return 1;
}
;
-------------------------------------------------------------------------------
--
create function DB.DBA.S3__headObject (
in accessCode varchar,
in secretKey varchar,
in s3Path varchar,
in what varchar,
in s3Mode integer := 1)
{
-- dbg_obj_princ ('DB.DBA.S3__headObject (', accessCode, secretKey, s3Path, ')');
declare dateUTC, authHeader, S, workPath varchar;
declare reqHdr, resHdr varchar;
declare item, xt any;
item := connection_get ('S3__' || s3Path);
if (isnull (item))
{
if (trim (s3Path, '/') = DB.DBA.S3__getBucketFromUrl (s3Path))
{
-- bucket
item := DB.DBA.S3__getBuckets (accessCode, secretKey, trim (s3Path, '/'));
if (length (item) < 1)
return null;
item := item[0];
} else {
-- bucket object
workPath := DB.DBA.S3__encode (s3Path);
workPath := rtrim (workPath, '/') || case when (what = 'C') then '_\$folder\$' end;
dateUTC := date_rfc1123 (now());
S := sprintf ('HEAD\n\n\n%s\n%s', dateUTC, workPath);
authHeader := DB.DBA.S3__makeAWSHeader (accessCode, secretKey, S);
reqHdr := sprintf ('Authorization: %s\r\nDate: %s', authHeader, dateUTC);
commit work;
xt := http_client_ext (url=>DB.DBA.S3__makeHostUrl (workPath),
http_method=>'HEAD',
http_headers=>reqHdr,
headers=>resHdr);
if (resHdr[0] like 'HTTP/1._ 4__ %' or resHdr[0] like 'HTTP/1._ 5__ %')
{
-- dbg_obj_princ ('resHdr[0]', DB.DBA.S3__makeHostUrl (workPath), s3Path, resHdr[0]);
return null;
}
item := DB.DBA.S3__headers2item (resHdr, s3Path, what);
}
connection_set ('S3__' || s3Path, item);
}
if (s3Mode)
return 1;
return item;
}
;
-------------------------------------------------------------------------------
--
create function DB.DBA.S3__getObject (
in accessCode varchar,
in secretKey varchar,
in s3Path varchar)
{
-- dbg_obj_princ ('DB.DBA.S3__getObject (', accessCode, secretKey, s3Path, ')');
declare dateUTC, authHeader, S, what, workPath varchar;
declare reqHdr, resHdr varchar;
declare xt, item any;
workPath := DB.DBA.S3__encode (s3Path);
what := case when (chr (s3Path [length (s3Path) - 1]) = '/') then 'C' else 'R' end;
workPath := rtrim (workPath, '/') || case when (what = 'C') then '_\$folder\$' end;
dateUTC := date_rfc1123 (now());
S := sprintf ('GET\n\n\n%s\n%s', dateUTC, workPath);
authHeader := DB.DBA.S3__makeAWSHeader (accessCode, secretKey, S);
reqHdr := sprintf ('Authorization: %s\r\nDate: %s', authHeader, dateUTC);
commit work;
xt := http_client_ext (url=>DB.DBA.S3__makeHostUrl (workPath),
http_method=>'GET',
http_headers=>reqHdr,
headers=>resHdr);
if (resHdr[0] like 'HTTP/1._ 4__ %' or resHdr[0] like 'HTTP/1._ 5__ %')
{
-- dbg_obj_princ ('xt', xt);
return null;
}
item := vector_concat (vector ('content', xt), DB.DBA.S3__headers2item (resHdr, s3Path, what));
return item;
}
;
-------------------------------------------------------------------------------
--
create function DB.DBA.S3__deleteObject (
in accessCode varchar,
in secretKey varchar,
in s3Path varchar)
{
-- dbg_obj_princ ('DB.DBA.S3__deleteObject (', accessCode, secretKey, s3Path, ')');
declare dateUTC, authHeader, S, what, workPath varchar;
declare reqHdr, resHdr varchar;
declare items, xt any;
dateUTC := date_rfc1123 (now());
what := case when (chr (s3Path [length (s3Path) - 1]) = '/') then 'C' else 'R' end;
items := vector (vector ('path', s3Path));
if (what = 'c')
items := vector_concat (items, DB.DBA.S3__getBucket (accessCode, secretKey, s3Path, ''));
foreach (any item in items) do
{
s3Path := get_keyword ('path', item);
what := case when (chr (s3Path [length (s3Path) - 1]) = '/') then 'C' else 'R' end;
workPath := DB.DBA.S3__encode (s3Path);
if (trim (s3Path, '/') <> DB.DBA.S3__getBucketFromUrl (s3Path))
workPath := rtrim (workPath, '/') || case when (what = 'C') then '_\$folder\$' end;
S := sprintf ('DELETE\n\n\n%s\n%s', dateUTC, workPath);
authHeader := DB.DBA.S3__makeAWSHeader (accessCode, secretKey, S);
reqHdr := sprintf ('Authorization: %s\r\nDate: %s', authHeader, dateUTC);
commit work;
http_client_ext (url=>DB.DBA.S3__makeHostUrl (workPath),
http_method=>'DELETE',
http_headers=>reqHdr,
headers=>resHdr);
if (resHdr[0] like 'HTTP/1._ 4__ %' or resHdr[0] like 'HTTP/1._ 5__ %')
{
-- dbg_obj_princ ('xt', xt);
return -1;
}
connection_set ('S3__' || s3Path, null);
}
return 1;
}
;
--| This matches DAV_AUTHENTICATE (in id any, in what char(1), in req varchar, in a_uname varchar, in a_pwd varchar, in a_uid integer := null)
--| The difference is that the DET function should not check whether the pair of name and password is valid; the auth_uid is not a null already.
create function DB.DBA."S3_DAV_AUTHENTICATE" (in id any, in what char(1), in req varchar, in auth_uname varchar, in auth_pwd varchar, in auth_uid integer)
{
-- dbg_obj_princ ('S3_DAV_AUTHENTICATE (', id, what, req, auth_uname, auth_pwd, auth_uid, ')');
if (auth_uid >= 0)
return auth_uid;
return -12;
}
;
--| This exactly matches DAV_AUTHENTICATE_HTTP (in id any, in what char(1), in req varchar, in can_write_http integer, inout a_lines any, inout a_uname varchar, inout a_pwd varchar, inout a_uid integer, inout a_gid integer, inout _perms varchar) returns integer
--| The function should fully check access because DAV_AUTHENTICATE_HTTP do nothing with auth data either before or after calling this DET function.
--| Unlike DAV_AUTHENTICATE, user name passed to DAV_AUTHENTICATE_HTTP header may not match real DAV user.
--| If DET call is successful, DAV_AUTHENTICATE_HTTP checks whether the user have read permission on mount point collection.
--| Thus even if DET function allows anonymous access, the whole request may fail if mountpoint is not readable by public.
create function DB.DBA."S3_DAV_AUTHENTICATE_HTTP" (in id any, in what char(1), in req varchar, in can_write_http integer, inout a_lines any, inout a_uname varchar, inout a_pwd varchar, inout a_uid integer, inout a_gid integer, inout _perms varchar) returns integer
{
-- dbg_obj_princ ('S3_DAV_AUTHENTICATE_HTTP (', id, what, req, can_write_http, a_lines, a_uname, a_pwd, a_uid, a_gid, _perms, ')');
declare rc integer;
declare puid, pgid integer;
declare u_password, pperms varchar;
declare allow_anon integer;
if (length (req) <> 3)
return -15;
whenever not found goto nf_col_or_res;
puid := http_dav_uid();
pgid := coalesce
(
( select G_ID
from WS.WS.SYS_DAV_GROUP
where G_NAME = 'S3_' || coalesce ((select COL_NAME
from WS.WS.SYS_DAV_COL
where COL_ID = id[1] and COL_DET = 'S3'), '')
),
puid+1
);
pperms := '110100100NN';
if ((what <> 'R') and (what <> 'C'))
return -14;
allow_anon := WS.WS.PERM_COMP (substring (cast (pperms as varchar), 7, 3), req);
if (a_uid is null)
{
if ((not allow_anon) or ('' <> WS.WS.FINDPARAM (a_lines, 'Authorization:')))
rc := WS.WS.GET_DAV_AUTH (a_lines, allow_anon, can_write_http, a_uname, u_password, a_uid, a_gid, _perms);
if (rc < 0)
return rc;
}
if (isinteger (a_uid))
{
if (a_uid < 0)
return a_uid;
if (a_uid = 1) -- Anonymous FTP
{
a_uid := http_nobody_uid ();
a_gid := http_nogroup_gid ();
}
}
if (DAV_CHECK_PERM (pperms, req, a_uid, a_gid, pgid, puid))
return a_uid;
return -13;
nf_col_or_res:
return -1;
}
;
--| This should return ID of the collection that contains resource or collection with given ID,
--| Possible ambiguity (such as symlinks etc.) should be resolved by using path.
--| This matches DAV_GET_PARENT (in id any, in st char(1), in path varchar) returns any
create function DB.DBA."S3_DAV_GET_PARENT" (in id any, in st char(1), in path varchar) returns any
{
-- dbg_obj_princ ('S3_DAV_GET_PARENT (', id, st, path, ')');
return -20;
}
;
--| When DAV_COL_CREATE_INT calls DET function, authentication, check for lock and check for overwrite are passed, uid and gid are translated from strings to IDs.
--| Check for overwrite, but the deletion of previously existing collection should be made by DET function.
create function DB.DBA."S3_DAV_COL_CREATE" (in detcolID any, in pathParts any, in permissions varchar, in uid integer, in gid integer, in auth_uid integer) returns any
{
-- dbg_obj_princ ('S3_DAV_COL_CREATE (', detcolID, pathParts, permissions, uid, gid, auth_uid, ')');
declare bucket, accessCode, secretKey, s3Path, s3Content, s3Type varchar;
DB.DBA.S3__params (detcolID, bucket, accessCode, secretKey);
s3Path := DB.DBA.S3__parts2path (bucket, pathParts, 'C');
s3Content := null;
s3Type := null;
if (DB.DBA.S3__putObject (accessCode, secretKey, s3Path, s3Content, s3Type) < 1)
return -1;
return vector (UNAME'S3', detcolID, s3Path);
}
;
--| When DAV_DELETE_INT calls DET function, authentication and check for lock are passed.
create function DB.DBA."S3_DAV_DELETE" (
in detcolID any,
in pathParts any,
in what char(1),
in silent integer,
in auth_uid integer) returns integer
{
-- dbg_obj_princ ('S3_DAV_DELETE (', detcolID, pathParts, what, silent, auth_uid, ')');
declare bucket, accessCode, secretKey, s3Path varchar;
DB.DBA.S3__params (detcolID, bucket, accessCode, secretKey);
s3Path := DB.DBA.S3__parts2path (bucket, pathParts, what);
return DB.DBA.S3__deleteObject (accessCode, secretKey, s3Path);
}
;
--| When DAV_RES_UPLOAD_STRSES_INT calls DET function, authentication and check for locks are performed before the call.
--| There's a special problem, known as 'Transaction deadlock after reading from HTTP session'.
--| The DET function should do only one INSERT of the 'content' into the table and do it as late as possible.
--| The function should return -29 if deadlocked or otherwise broken after reading blob from HTTP.
create function DB.DBA."S3_DAV_RES_UPLOAD" (in detcolID any, in pathParts any, inout content any, in type varchar, in permissions varchar, in uid integer, in gid integer, in auth_uid integer) returns any
{
-- dbg_obj_princ ('S3_DAV_RES_UPLOAD (', detcolID, pathParts, ', [content], ', type, permissions, uid, gid, auth_uid, ')');
return -20;
}
;
--| When DAV_PROP_REMOVE_INT calls DET function, authentication and check for locks are performed before the call.
--| The check whether it's a system name or not (when an error in returned if name is system) is _not_ permitted.
--| It should delete any dead property even if the name looks like system name.
create function DB.DBA."S3_DAV_PROP_REMOVE" (in id any, in what char(0), in propname varchar, in silent integer, in auth_uid integer) returns integer
{
-- dbg_obj_princ ('S3_DAV_PROP_REMOVE (', id, what, propname, silent, auth_uid, ')');
return -20;
}
;
--| When DAV_PROP_SET_INT calls DET function, authentication and check for locks are performed before the call.
--| The check whether it's a system property or not is _not_ permitted and the function should return -16 for live system properties.
create function DB.DBA."S3_DAV_PROP_SET" (in id any, in what char(0), in propname varchar, in propvalue any, in overwrite integer, in auth_uid integer) returns any
{
-- dbg_obj_princ ('S3_DAV_PROP_SET (', id, what, propname, propvalue, overwrite, auth_uid, ')');
if (propname[0] = 58)
return -16;
return -20;
}
;
--| When DAV_PROP_GET_INT calls DET function, authentication and check whether it's a system property are performed before the call.
create function DB.DBA."S3_DAV_PROP_GET" (in id any, in what char(0), in propname varchar, in auth_uid integer)
{
-- dbg_obj_princ ('S3_DAV_PROP_GET (', id, what, propname, auth_uid, ')');
return -11;
}
;
--| When DAV_PROP_LIST_INT calls DET function, authentication is performed before the call.
--| The returned list should contain only user properties.
create function DB.DBA."S3_DAV_PROP_LIST" (in id any, in what char(0), in propmask varchar, in auth_uid integer)
{
-- dbg_obj_princ ('S3_DAV_PROP_LIST (', id, what, propmask, auth_uid, ')');
return vector ();
}
;
--| When DAV_PROP_GET_INT or DAV_DIR_LIST_INT calls DET function, authentication is performed before the call.
create function DB.DBA."S3_DAV_DIR_SINGLE" (
in id any,
in what char(0),
in path any,
in auth_uid integer) returns any
{
-- dbg_obj_princ ('S3_DAV_DIR_SINGLE (', id, what, path, auth_uid, ')');
declare detcolID integer;
declare bucket, accessCode, secretKey, detcolPath, s3Path varchar;
declare s3Object any;
detcolID := id[1];
s3Path := id[2];
DB.DBA.S3__params (detcolID, bucket, accessCode, secretKey);
s3Object := DB.DBA.S3__headObject (accessCode, secretKey, s3Path, what, 0);
if (isnull (s3Object))
return -1;
detcolPath := DB.DBA.DAV_SEARCH_PATH (detcolID, 'C');
return DB.DBA.S3__item2entry (detcolID, detcolPath, bucket, s3Object);
}
;
--| When DAV_PROP_GET_INT or DAV_DIR_LIST_INT calls DET function, authentication is performed before the call.
create function DB.DBA."S3_DAV_DIR_LIST" (
in detcolID any,
in pathParts any,
in detcol_pathParts any,
in name_mask varchar,
in recursive integer,
in auth_uid integer) returns any
{
-- dbg_obj_princ ('S3_DAV_DIR_LIST (', detcolID, pathParts, detcol_pathParts, name_mask, recursive, auth_uid, ')');
declare N integer;
declare bucket, accessCode, secretKey, s3Path varchar;
declare detcolPath varchar;
declare res, items any;
DB.DBA.S3__params (detcolID, bucket, accessCode, secretKey);
if (is_empty_or_null (bucket) and (length (pathParts) = 1) and pathParts[0] = '')
{
s3Path := '/';
items := DB.DBA.S3__getBuckets (accessCode, secretKey);
}
else
{
s3Path := DB.DBA.S3__parts2path (bucket, pathParts, 'C');
items := DB.DBA.S3__getBucket (accessCode, secretKey, s3Path);
}
detcolPath := DB.DBA.DAV_CONCAT_PATH (detcol_pathParts, '/');
res := vector ();
for (N := 0; N < length (items); N := N + 1)
{
res := vector_concat (res, vector (DB.DBA.S3__item2entry (detcolID, detcolPath, bucket, items[N])));
}
return res;
}
;
--| When DAV_DIR_FILTER_INT calls DET function, authentication is performed before the call and compilation is initialized.
create function DB.DBA."S3_DAV_DIR_FILTER" (in detcolID any, in pathParts any, in detcol_path varchar, inout compilation any, in recursive integer, in auth_uid integer) returns any
{
-- dbg_obj_princ ('S3_DAV_DIR_FILTER (', detcolID, pathParts, detcol_path, compilation, recursive, auth_uid, ')');
return vector();
}
;
--| When DAV_PROP_GET_INT or DAV_DIR_LIST_INT calls DET function, authentication is performed before the call.
create function DB.DBA."S3_DAV_SEARCH_ID" (
in detcolID any,
in pathParts any,
in what char(1)) returns any
{
-- dbg_obj_princ ('S3_DAV_SEARCH_ID (', detcolID, pathParts, what, ')');
declare bucket, accessCode, secretKey, s3Path varchar;
declare s3Object any;
DB.DBA.S3__params (detcolID, bucket, accessCode, secretKey);
s3Path := DB.DBA.S3__parts2path (bucket, pathParts, what);
s3Object := DB.DBA.S3__headObject (accessCode, secretKey, s3Path, what, 1);
if (isnull (s3Object))
return -1;
return vector (UNAME'S3', detcolID, s3Path);
}
;
--| When DAV_SEARCH_PATH_INT calls DET function, authentication is performed before the call.
create function DB.DBA."S3_DAV_SEARCH_PATH" (
in id any,
in what char(1)) returns any
{
-- dbg_obj_princ ('S3_DAV_SEARCH_PATH (', id, what, ')');
declare detcolID integer;
declare bucket, accessCode, secretKey, detcolPath, s3Path varchar;
declare s3Object any;
detcolID := id[1];
detcolPath := coalesce ((select WS.WS.COL_PATH (COL_ID) from WS.WS.SYS_DAV_COL where COL_ID = detcolID and COL_DET = 'S3'));
if (detcolPath is null)
return -23;
s3Path := id[2];
DB.DBA.S3__params (detcolID, bucket, accessCode, secretKey);
s3Object := DB.DBA.S3__headObject (accessCode, secretKey, s3Path, what, 0);
if (isnull (s3Object))
return -23;
return rtrim (detcolPath, '/') || get_keyword ('path', s3Object);
}
;
create function DB.DBA."S3_DAV_RES_UPLOAD" (
in detcolID any,
in pathParts any,
inout content any,
in type varchar,
in permissions varchar,
in uid integer,
in gid integer,
in auth_uid integer) returns any
{
-- dbg_obj_princ ('S3_DAV_RES_UPLOAD (', detcolID, pathParts, ', [content], ', type, permissions, uid, gid, auth_uid, ')');
declare bucket, accessCode, secretKey, s3Path varchar;
DB.DBA.S3__params (detcolID, bucket, accessCode, secretKey);
s3Path := DB.DBA.S3__parts2path (bucket, pathParts, 'R');
if (DB.DBA.S3__putObject (accessCode, secretKey, s3Path, content, type) < 1)
return -1;
return vector (UNAME'S3', detcolID, s3Path);
}
;
--| When DAV_COPY_INT calls DET function, authentication and check for locks are performed before the call, but no check for existing/overwrite.
create function DB.DBA."S3_DAV_RES_UPLOAD_COPY" (in detcolID any, in pathParts any, in sourceID any, in what char(1), in overwrite_flags integer, in permissions varchar, in uid integer, in gid integer, in auth_uid integer) returns any
{
-- dbg_obj_princ ('S3_DAV_RES_UPLOAD_COPY (', detcolID, pathParts, sourceID, what, overwrite_flags, permissions, uid, gid, auth_uid, ')');
if (what = 'R')
{
declare bucket, accessCode, secretKey, s3Path varchar;
DB.DBA.S3__params (detcolID, bucket, accessCode, secretKey);
s3Path := DB.DBA.S3__parts2path (bucket, pathParts, 'R');
declare rc integer;
declare sourceContent, sourceMimeType any;
rc := DB.DBA.DAV_RES_CONTENT_INT (sourceID, sourceContent, sourceMimeType, 0, 0);
if (rc < 0)
return rc;
sourceContent := case when (__tag (sourceContent) = 126) then blob_to_string (sourceContent) else sourceContent end;
if (DB.DBA.S3__putObject (accessCode, secretKey, s3Path, sourceContent, sourceMimeType) < 1)
return -28;
return vector (UNAME'S3', detcolID, s3Path);
}
return -20;
}
;
--| When DAV_COPY_INT calls DET function, authentication and check for locks are performed before the call, but no check for existing/overwrite.
create function DB.DBA."S3_DAV_RES_UPLOAD_MOVE" (in detcolID any, in pathParts any, in sourceID any, in what char(1), in overwrite_flags integer, in auth_uid integer) returns any
{
-- dbg_obj_princ ('S3_DAV_RES_UPLOAD_MOVE (', detcolID, pathParts, sourceID, what, overwrite_flags, auth_uid, ')');
if (what = 'R')
{
declare rc integer;
declare sourcePath, sourceContent, sourceMimeType any;
declare bucket, accessCode, secretKey, s3Path varchar;
DB.DBA.S3__params (detcolID, bucket, accessCode, secretKey);
s3Path := DB.DBA.S3__parts2path (bucket, pathParts, 'R');
rc := DB.DBA.DAV_RES_CONTENT_INT (sourceID, sourceContent, sourceMimeType, 0, 0);
if (rc < 0)
return rc;
sourceContent := case when (__tag (sourceContent) = 126) then blob_to_string (sourceContent) else sourceContent end;
if (DB.DBA.S3__putObject (accessCode, secretKey, s3Path, sourceContent, sourceMimeType) < 1)
return -28;
sourcePath := DB.DBA.DAV_SEARCH_PATH (sourceID, 'R');
if (not isnull (sourcePath))
DB.DBA.DAV_DELETE_INT (sourcePath, 1, null, null, 0);
return vector (UNAME'S3', detcolID, s3Path);
}
return -20;
}
;
--| When DAV_RES_CONTENT or DAV_RES_COPY_INT or DAV_RES_MOVE_INT calls DET function, authentication is made.
--| If content_mode is 1 then content is a valid output stream before the call.
create function DB.DBA."S3_DAV_RES_CONTENT" (
in id any,
inout content any,
out type varchar,
in content_mode integer) returns integer
{
-- dbg_obj_princ ('S3_DAV_RES_CONTENT (', id, ', [content], [type], ', content_mode, ')');
declare detcolID integer;
declare bucket, accessCode, secretKey, s3Path varchar;
declare s3Object, s3Content any;
detcolID := id[1];
s3Path := id[2];
DB.DBA.S3__params (detcolID, bucket, accessCode, secretKey);
s3Object := DB.DBA.S3__getObject (accessCode, secretKey, s3Path);
if (isnull (s3Object))
return -1;
s3Content := get_keyword ('content', s3Object);
type := get_keyword ('mimeType', s3Object);
if ((content_mode = 0) or (content_mode = 2))
content := s3Content;
else if (content_mode = 1)
http (s3Content, content);
else if (content_mode = 3)
http (s3Content);
return 0;
}
;
--| This adds an extra access path to the existing resource or collection.
create function DB.DBA."S3_DAV_SYMLINK" (in detcolID any, in pathParts any, in sourceID any, in what char(1), in overwrite integer, in uid integer, in gid integer, in auth_uid integer) returns any
{
-- dbg_obj_princ ('S3_DAV_SYMLINK (', detcolID, pathParts, sourceID, overwrite, uid, gid, auth_uid, ')');
return -20;
}
;
--| This gets a list of resources and/or collections as it is returned by DAV_DIR_LIST and and writes the list of quads (old_id, 'what', old_full_path, dereferenced_id, dereferenced_full_path).
create function DB.DBA."S3_DAV_DEREFERENCE_LIST" (in detcolID any, inout report_array any) returns any
{
-- dbg_obj_princ ('S3_DAV_DEREFERENCE_LIST (', detcolID, report_array, ')');
return -20;
}
;
--| This gets one of reference quads returned by ..._DAV_REREFERENCE_LIST() and returns a record (new_full_path, new_dereferenced_full_path, name_may_vary).
create function DB.DBA."S3_DAV_RESOLVE_PATH" (in detcolID any, inout reference_item any, inout old_base varchar, inout new_base varchar) returns any
{
-- dbg_obj_princ ('S3_DAV_RESOLVE_PATH (', detcolID, reference_item, old_base, new_base, ')');
return -20;
}
;
--| There's no API function to lock for a while (do we need such?) The "LOCK" DAV method checks that all parameters are valid but does not check for existing locks.
create function DB.DBA."S3_DAV_LOCK" (in path any, in id any, in type char(1), inout locktype varchar, inout scope varchar, in token varchar, inout owner_name varchar, inout owned_tokens varchar, in depth varchar, in timeout_sec integer, in auth_uid integer) returns any
{
-- dbg_obj_princ ('S3_DAV_LOCK (', path, id, type, locktype, scope, token, owner_name, owned_tokens, depth, timeout_sec, auth_uid, ')');
return -20;
}
;
--| There's no API function to unlock for a while (do we need such?) The "UNLOCK" DAV method checks that all parameters are valid but does not check for existing locks.
create function DB.DBA."S3_DAV_UNLOCK" (in id any, in type char(1), in token varchar, in auth_uid integer)
{
-- dbg_obj_princ ('S3_DAV_UNLOCK (', id, type, token, auth_uid, ')');
return -27;
}
;
--| The caller does not check if id is valid.
--| This returns -1 if id is not valid, 0 if all existing locks are listed in owned_tokens whitespace-delimited list, 1 for soft 2 for hard lock.
create function DB.DBA."S3_DAV_IS_LOCKED" (inout id any, inout Type char(1), in owned_tokens varchar) returns integer
{
-- dbg_obj_princ ('S3_DAV_IS_LOCKED (', id, type, owned_tokens, ')');
declare rc integer;
declare orig_id any;
declare orig_type char(1);
-- save
orig_id := id;
orig_type := type;
ID := orig_id[1];
Type := 'C';
rc := DB.DBA.DAV_IS_LOCKED_INT (id, type, owned_tokens);
-- restore
id := orig_id;
Type := orig_type;
if (rc <> 0)
return rc;
return 0;
}
;
--| The caller does not check if id is valid.
--| This returns -1 if id is not valid, list of tuples (LOCK_TYPE, LOCK_SCOPE, LOCK_TOKEN, LOCK_TIMEOUT, LOCK_OWNER, LOCK_OWNER_INFO) otherwise.
create function DB.DBA."S3_DAV_LIST_LOCKS" (in id any, in type char(1), in recursive integer) returns any
{
-- dbg_obj_princ ('S3_DAV_LIST_LOCKS (', id, type, recursive);
return vector ();
}
;