static void _check_for_and_handle_json_500(SG_context* pCtx, SG_curl* pCurl, char* buffer, SG_uint32 bufLen) { SG_int32 responseCode = 0; _sg_curl* pMe = (_sg_curl*)pCurl; SG_ERR_CHECK( SG_curl__getinfo__int32(pCtx, pCurl, CURLINFO_RESPONSE_CODE, &responseCode) ); if (responseCode == 500 || responseCode == 410) { if (pMe->pstrErr == NULL) { SG_int32 lenResponse = 0; /* We assume an HTTP 500 response will be small enough to fit into an SG_string. */ SG_ERR_CHECK( SG_curl__getinfo__int32(pCtx, pCurl, CURLINFO_CONTENT_LENGTH_DOWNLOAD, &lenResponse) ); if (lenResponse > 0) SG_ERR_CHECK( SG_STRING__ALLOC__RESERVE(pCtx, &pMe->pstrErr, (SG_uint32)lenResponse + 1) ); else SG_ERR_CHECK( SG_STRING__ALLOC(pCtx, &pMe->pstrErr) ); } SG_ERR_CHECK( SG_string__append__buf_len(pCtx, pMe->pstrErr, (const SG_byte*)buffer, bufLen) ); } fail: ; }
static void _get_sync_url(SG_context* pCtx, const char* pszBaseUrl, const char* pszUrlSuffix, const char* pszPushId, const char* pszQueryString, char** ppszUrl) { SG_string* pstrUrl = NULL; SG_ERR_CHECK( SG_STRING__ALLOC__RESERVE(pCtx, &pstrUrl, 1024) ); SG_ERR_CHECK( SG_string__append__sz(pCtx, pstrUrl, pszBaseUrl) ); if (pszUrlSuffix) SG_ERR_CHECK( SG_string__append__sz(pCtx, pstrUrl, pszUrlSuffix) ); if (pszPushId) { SG_ERR_CHECK( SG_string__append__sz(pCtx, pstrUrl, "/") ); SG_ERR_CHECK( SG_string__append__sz(pCtx, pstrUrl, pszPushId) ); } if (pszQueryString) { SG_ERR_CHECK( SG_string__append__sz(pCtx, pstrUrl, "?") ); SG_ERR_CHECK( SG_string__append__sz(pCtx, pstrUrl, pszQueryString) ); } SG_ERR_CHECK( SG_string__sizzle(pCtx, &pstrUrl, (SG_byte**)ppszUrl, NULL) ); return; fail: SG_STRING_NULLFREE(pCtx, pstrUrl); }
void sg_sync_client__http__pull_clone( SG_context* pCtx, SG_sync_client* pSyncClient, SG_vhash* pvh_clone_request, const SG_pathname* pStagingPathname, char** ppszFragballName) { SG_vhash* pvhRequest = NULL; char* pszFragballName = NULL; SG_pathname* pPathFragball = NULL; SG_string* pstrRequest = NULL; char* pszUrl = NULL; SG_ERR_CHECK( SG_log__push_operation(pCtx, "Requesting repository from server", SG_LOG__FLAG__NONE) ); SG_NULLARGCHECK_RETURN(pSyncClient); SG_ERR_CHECK( SG_allocN(pCtx, SG_TID_MAX_BUFFER_LENGTH, pszFragballName) ); SG_ERR_CHECK( SG_tid__generate(pCtx, pszFragballName, SG_TID_MAX_BUFFER_LENGTH) ); SG_ERR_CHECK( _get_sync_url(pCtx, pSyncClient->psz_remote_repo_spec, SYNC_URL_SUFFIX FRAGBALL_URL_SUFFIX, NULL, NULL, &pszUrl) ); SG_ERR_CHECK( SG_VHASH__ALLOC(pCtx, &pvhRequest) ); SG_ERR_CHECK( SG_vhash__add__null(pCtx, pvhRequest, SG_SYNC_STATUS_KEY__CLONE) ); if (pvh_clone_request) { SG_ERR_CHECK( SG_vhash__addcopy__vhash(pCtx, pvhRequest, SG_SYNC_STATUS_KEY__CLONE_REQUEST, pvh_clone_request) ); } SG_ERR_CHECK( SG_STRING__ALLOC__RESERVE(pCtx, &pstrRequest, 50) ); SG_ERR_CHECK( SG_vhash__to_json(pCtx, pvhRequest, pstrRequest) ); SG_ERR_CHECK( SG_pathname__alloc__pathname_sz(pCtx, &pPathFragball, pStagingPathname, (const char*)pszFragballName) ); SG_ERR_CHECK( do_url(pCtx, pszUrl, "POST", SG_string__sz(pstrRequest), pSyncClient->psz_username, pSyncClient->psz_password, NULL, pPathFragball, SG_TRUE) ); SG_RETURN_AND_NULL(pszFragballName, ppszFragballName); /* fall through */ fail: SG_log__pop_operation(pCtx); SG_NULLFREE(pCtx, pszFragballName); SG_VHASH_NULLFREE(pCtx, pvhRequest); SG_PATHNAME_NULLFREE(pCtx, pPathFragball); SG_NULLFREE(pCtx, pszUrl); SG_STRING_NULLFREE(pCtx, pstrRequest); }
SG_error SG_context__err_to_string(SG_context* pCtx, SG_string** ppErrString) { SG_error err = SG_ERR_OK; char szErr[SG_ERROR_BUFFER_SIZE]; SG_string* pTempStr = NULL; SG_uint32 lenRequired; SG_ASSERT( pCtx ); // SG_ASSERT( pCtx->level < SG_CONTEXT_MAX_ERROR_LEVELS ); if (!ppErrString) return SG_ERR_INVALIDARG; if (pCtx->level > 0) { // when in an error-on-error (level > 0), the error string DOES NOT belong to the // error context/level that we are in. The full message is only defined for the // original error that triggered things. *ppErrString = NULL; return SG_ERR_OK; } SG_error__get_message(pCtx->errValues[pCtx->level], szErr, sizeof(szErr)); lenRequired = ( strlen(szErr) + strlen(pCtx->szDescription) + pCtx->lenStackTrace + 100); // do all of the formatting in an error-on-error context/level // so that none of the string allocation/manipulation trashes // the current error context. // // ***DO NOT JUMP OUT OF THIS PUSH..POP BLOCK.*** SG_context__push_level(pCtx); { SG_STRING__ALLOC__RESERVE(pCtx,&pTempStr,lenRequired); if (SG_IS_OK(pCtx->errValues[pCtx->level])) { // since we pre-reserved all of the space we require, we // don't expect any of the appends to fail. So we can // ignore intermediate errors after each step. if one of // them does have a problem, the subsequent statements will // fail because we already have an error at this level. // either way, we don't care because we're going to pop the // level in a minute anyway. if (szErr[0] != 0) { SG_string__append__sz(pCtx, pTempStr, szErr); if (pCtx->szDescription[0] != 0) SG_string__append__sz(pCtx, pTempStr, ": "); else SG_string__append__sz(pCtx, pTempStr, "."); } if (pCtx->szDescription[0] != 0) SG_string__append__sz(pCtx, pTempStr, pCtx->szDescription); if (szErr[0] != 0 || pCtx->szDescription[0] != 0) SG_string__append__sz(pCtx, pTempStr, "\n"); SG_string__append__sz(pCtx, pTempStr, pCtx->szStackTrace); // if all of the formating works, we return the allocated string. // if not, we delete it and return the formatting error. if (SG_IS_OK(pCtx->errValues[pCtx->level])) *ppErrString = pTempStr; else SG_STRING_NULLFREE(pCtx, pTempStr); } err = pCtx->errValues[pCtx->level]; // we return the error value of the allocation/formatting } SG_context__pop_level(pCtx); return err; }