s3.cpp revision e717dbd995f2f9f62b59b24b2e2b1487986fc07a
/* $Id$ */
/** @file
* IPRT - S3 communication API.
*/
/*
* Copyright (C) 2009 Sun Microsystems, Inc.
*
* This file is part of VirtualBox Open Source Edition (OSE), as
* available from http://www.virtualbox.org. This file is free software;
* General Public License (GPL) as published by the Free Software
* Foundation, in version 2 as it comes in the "COPYING" file of the
* VirtualBox OSE distribution. VirtualBox OSE is distributed in the
* hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
*
* The contents of this file may alternatively be used under the terms
* of the Common Development and Distribution License Version 1.0
* (CDDL) only, as it comes in the "COPYING.CDDL" file of the
* VirtualBox OSE distribution, in which case the provisions of the
* CDDL are applicable instead of those of the GPL.
*
* You may elect to license modified versions of this file under the
* terms and conditions of either the GPL or the CDDL or both.
*
* Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa
* Clara, CA 95054 USA or visit http://www.sun.com if you need
* additional information or have any questions.
*/
/*******************************************************************************
* Header Files *
*******************************************************************************/
/*******************************************************************************
* Structures and Typedefs *
*******************************************************************************/
typedef struct RTS3INTERNAL
{
char *pszAccessKey;
char *pszSecretKey;
char *pszBaseUrl;
char *pszUserAgent;
void *pvUser;
long lLastResp;
} RTS3INTERNAL;
typedef RTS3INTERNAL* PRTS3INTERNAL;
typedef struct RTS3TMPMEMCHUNK
{
char *pszMem;
typedef RTS3TMPMEMCHUNK *PRTS3TMPMEMCHUNK;
/*******************************************************************************
* Defined Constants And Macros *
*******************************************************************************/
/** Validates a handle and returns VERR_INVALID_HANDLE if not valid. */
do { \
} while (0)
/** Validates a handle and returns VERR_INVALID_HANDLE if not valid. */
/** Validates a handle and returns (void) if not valid. */
#define RTS3_VALID_RETURN_VOID(hS3) \
do { \
} while (0)
/*******************************************************************************
* Private RTS3 helper *
*******************************************************************************/
{
char* pszUrl;
/* Host header entry */
if (pszBucket[0] == 0)
else if (pszKey[0] == 0)
else
return pszUrl;
}
{
char* pszUrl;
/* Host header entry */
if (pszBucket[0] != 0)
else
return pszUrl;
}
static char* rtS3DateHeader()
{
/* Date header entry */
return pszDate;
}
{
char pszEmpty[] = "";
{
{
{
}
{
// char *pszTmp = RTStrDup (&(ppHeaders[i][14]));
// if (pszRes)
// {
// char *pszTmp1 = pszRes;
// RTStrAPrintf(&pszRes, "%s\n%s", pszRes, pszTmp);
// RTStrFree(pszTmp);
// RTStrFree(pszTmp1);
// }
// else
// pszRes = pszTmp;
}
}
}
return pszRes;
}
static char* rtS3Canonicalize(const char* pszAction, const char* pszBucket, const char* pszKey, char** ppszHead, size_t cHead)
{
char* pszRes;
/* Grep the necessary info out of the headers & put them in a string */
/* Create the string which will be used as signature */
pszHead);
/* Add the bucket if the bucket isn't empty */
if (pszBucket[0] != 0)
{
}
/* Add the key if the key isn't empty. */
if (pszKey[0] != 0)
{
}
return pszRes;
}
static char* rtS3CreateSignature(PRTS3INTERNAL pS3Int, const char* pszAction, const char* pszBucket, const char* pszKey, char** ppszHead, size_t cHead)
{
/* Create a string we can sign */
// printf ("Sig %s\n", pszSig);
/* Sign the string by creating a SHA1 finger print */
char pszSigEnc[1024];
/* Convert the signature to Base64 */
return pszSigBase64Enc;
}
static char* rtS3CreateAuthHeader(PRTS3INTERNAL pS3Int, const char* pszAction, const char* pszBucket, const char* pszKey, char** ppszHead, size_t cHead)
{
char *pszAuth;
/* Create the authorization header entry */
return pszAuth;
}
{
int rc = VERR_INTERNAL_ERROR;
{
{
case 200:
}
}else
{
switch(code)
{
case CURLE_URL_MALFORMAT:
#if defined(CURLE_REMOTE_ACCESS_DENIED)
#elif defined(CURLE_FTP_ACCESS_DENIED)
#endif
default: break;
}
}
return rc;
}
{
}
{
{
}
return cRSize;
}
{
return cWritten;
}
{
return cRead;
}
static int rtS3ProgressCallback(void *pvUser, double dDlTotal, double dDlNow, double dUlTotal, double dUlNow)
{
if (pvUser)
{
if (pS3Int->pfnProgressCallback)
{
int rc = VINF_SUCCESS;
if (dDlTotal > 0)
else if (dUlTotal > 0)
if (rc != VINF_SUCCESS)
return -1;
}
}
return CURLE_OK;
}
{
if (pS3Int &&
{
/* Reset the CURL object to an defined state */
/* Make sure HTTP 1.1 is used */
/* We are cool we are a user agent now */
if (pS3Int->pszUserAgent)
/* Check if the user has a progress callback requested */
if (pS3Int->pfnProgressCallback)
{
/* Yes, we are willing to receive progress info */
/* Callback for the progress info */
}
/* Disable the internal cURL write function by providing one which does
* nothing */
/* Set this do get some verbose info what CURL is doing */
// curl_easy_setopt(pS3Int->pCurl, CURLOPT_VERBOSE, 1);
}
}
/*******************************************************************************
* Private XML helper *
*******************************************************************************/
{
{
/* Check this level */
return pNode;
/* Recursively check the childs of this node */
if (pChildNode != NULL)
return pChildNode;
/* Next node*/
}
return pNode;
}
static int rtS3ReadXmlFromMemory(PRTS3TMPMEMCHUNK pChunk, const char* pszRootElement, xmlDocPtr *ppDoc, xmlNodePtr *ppCur)
{
return VERR_PARSE_ERROR;
{
xmlFreeDoc(*ppDoc);
return VERR_PARSE_ERROR;
}
{
xmlFreeDoc(*ppDoc);
return VERR_PARSE_ERROR;
}
return VINF_SUCCESS;
}
{
{
while (pCurBucket != NULL)
{
{
if (pPrevBucket)
else
{
{
}
{
}
}
}
}
}
}
{
{
{
{
if (pPrevKey)
else
{
{
}
{
}
{
}
}
}
}
}
}
/*******************************************************************************
* Public RTS3 interface *
*******************************************************************************/
RTR3DECL(int) RTS3Create(PRTS3 ppS3, const char* pszAccessKey, const char* pszSecretKey, const char* pszBaseUrl, const char* pszUserAgent /* = NULL */)
{
/* We need at least an URL to connect with */
if (pszBaseUrl == NULL ||
pszBaseUrl[0] == 0)
return VERR_INVALID_PARAMETER;
/* In windows, this will init the winsock stuff */
if (curl_global_init(CURL_GLOBAL_ALL) != 0)
return VERR_INTERNAL_ERROR;
if (!pCurl)
return VERR_INTERNAL_ERROR;
return VERR_NO_MEMORY;
if (pszUserAgent)
return VINF_SUCCESS;
}
{
return;
if (pS3Int->pszUserAgent)
}
RTR3DECL(void) RTS3SetProgressCallback(RTS3 hS3, PFNRTS3PROGRESS pfnProgressCallback, void *pvUser /* = NULL */)
{
}
{
/* Properly initialize this */
/* Reset the CURL object to an defined state */
/* Create the CURL object to operate on */
/* Create the three basic header entries */
char *ppszHead[3] =
{
rtS3DateHeader(), /* Date entry */
NULL /* Authorization entry */
};
/* Create the authorization header entry */
ppszHead[RT_ELEMENTS(ppszHead)-1] = rtS3CreateAuthHeader(pS3Int, "GET", "", "", ppszHead, RT_ELEMENTS(ppszHead));
/* Add all headers to curl */
/* Pass our list of custom made headers */
/* Set the callback which receive the content */
/* Start the request */
/* Regardless of the result, free all used resources first*/
/* On success parse the result */
if (RT_SUCCESS(rc))
{
/* Parse the xml memory for "ListAllMyBucketsResult" */
if (RT_SUCCESS(rc))
{
/* Now extract all buckets */
/* Free the xml stuff */
}
}
/* Free the temporary memory */
return rc;
}
{
if (!pBuckets)
return VINF_SUCCESS;
while (pBuckets)
{
}
return VINF_SUCCESS;
}
{
/* Reset the CURL object to an defined state */
/* Create the basic header entries */
char *ppszHead[4] =
{
rtS3DateHeader(), /* Date entry */
NULL /* Authorization entry */
};
/* Create the authorization header entry */
ppszHead[RT_ELEMENTS(ppszHead)-1] = rtS3CreateAuthHeader(pS3Int, "PUT", pszBucketName, "", ppszHead, RT_ELEMENTS(ppszHead));
/* Add all headers to curl */
/* Pass our list of custom made headers */
/* Set CURL in upload mode */
/* Set the size of the file we like to transfer */
/* Start the request */
if (RT_FAILURE(rc))
{
/* Handle special failures */
}
/* Regardless of the result, free all used resources first*/
return rc;
}
{
/* Reset the CURL object to an defined state */
/* Create the three basic header entries */
char *ppszHead[3] =
{
rtS3DateHeader(), /* Date entry */
NULL /* Authorization entry */
};
/* Create the authorization header entry */
ppszHead[RT_ELEMENTS(ppszHead)-1] = rtS3CreateAuthHeader(pS3Int, "DELETE", pszBucketName, "", ppszHead, RT_ELEMENTS(ppszHead));
/* Add all headers to curl */
/* Pass our list of custom made headers */
/* Set CURL in delete mode */
/* Start the request */
if (RT_FAILURE(rc))
{
/* Handle special failures */
}
/* Regardless of the result, free all used resources first*/
return rc;
}
{
/* Reset the CURL object to an defined state */
/* Create the three basic header entries */
char *ppszHead[3] =
{
rtS3DateHeader(), /* Date entry */
NULL /* Authorization entry */
};
/* Create the authorization header entry */
ppszHead[RT_ELEMENTS(ppszHead)-1] = rtS3CreateAuthHeader(pS3Int, "GET", pszBucketName, "", ppszHead, RT_ELEMENTS(ppszHead));
/* Add all headers to curl */
/* Pass our list of custom made headers */
/* Set the callback which recieve the content */
/* Start the request */
/* Regardless of the result, free all used resources first*/
/* On success parse the result */
if (RT_SUCCESS(rc))
{
/* Parse the xml memory for "ListBucketResult" */
if (RT_SUCCESS(rc))
{
/* Now extract all buckets */
/* Free the xml stuff */
}
}
/* Free the tempory memory */
return rc;
}
{
if (!pKeys)
return VINF_SUCCESS;
while (pKeys)
{
}
return VINF_SUCCESS;
}
{
/* Reset the CURL object to an defined state */
/* Create the three basic header entries */
char *ppszHead[3] =
{
rtS3DateHeader(), /* Date entry */
NULL /* Authorization entry */
};
/* Create the authorization header entry */
ppszHead[RT_ELEMENTS(ppszHead)-1] = rtS3CreateAuthHeader(pS3Int, "DELETE", pszBucketName, pszKeyName, ppszHead, RT_ELEMENTS(ppszHead));
/* Add all headers to curl */
/* Pass our list of custom made headers */
/* Set CURL in delete mode */
/* Start the request */
/* Regardless of the result, free all used resources first*/
return rc;
}
RTR3DECL(int) RTS3GetKey(RTS3 hS3, const char* pszBucketName, const char* pszKeyName, const char* pszFileName)
{
/* Reset the CURL object to an defined state */
/* Open the file */
if (RT_FAILURE(rc))
return rc;
/* Create the three basic header entries */
char *ppszHead[3] =
{
rtS3DateHeader(), /* Date entry */
NULL /* Authorization entry */
};
/* Create the authorization header entry */
ppszHead[RT_ELEMENTS(ppszHead)-1] = rtS3CreateAuthHeader(pS3Int, "GET", pszBucketName, pszKeyName, ppszHead, RT_ELEMENTS(ppszHead));
/* Add all headers to curl */
/* Pass our list of custom made headers */
/* Set the callback which receive the content */
/* Start the request */
/* Regardless of the result, free all used resources first*/
/* Close the open file */
/* If there was an error delete the newly created file */
if (RT_FAILURE(rc))
return rc;
}
RTR3DECL(int) RTS3PutKey(RTS3 hS3, const char* pszBucketName, const char* pszKeyName, const char* pszFileName)
{
/* Reset the CURL object to an defined state */
/* Open the file */
if (RT_FAILURE(rc))
return rc;
if (RT_FAILURE(rc))
{
return rc;
}
char* pszContentLength;
/* Create the three basic header entries */
char *ppszHead[5] =
{
/* todo: For now we use octet-stream for all types. Later we should try
* to set the right one (libmagic from the file packet could be a
* candidate for finding the right type). */
pszContentLength, /* Content length entry */
rtS3DateHeader(), /* Date entry */
NULL /* Authorization entry */
};
/* Create the authorization header entry */
ppszHead[RT_ELEMENTS(ppszHead)-1] = rtS3CreateAuthHeader(pS3Int, "PUT", pszBucketName, pszKeyName, ppszHead, RT_ELEMENTS(ppszHead));
/* Add all headers to curl */
/* Pass our list of custom made headers */
/* Set CURL in upload mode */
/* Set the size of the file we like to transfer */
/* Set the callback which send the content */
/* Start the request */
/* Regardless of the result, free all used resources first*/
/* Close the open file */
return rc;
}