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:
	;
}
// http://curl.haxx.se/libcurl/c/curl_easy_setopt.html#CURLOPTHEADERFUNCTION
static size_t _read_header( void *ptr, size_t size, size_t nmemb, void *userdata)
{
	_sg_curl * pMe = (_sg_curl*)userdata;
	SG_context * pCtx = pMe->pCtx;
		
	SG_ERR_IGNORE( SG_string__append__buf_len(pCtx, pMe->pstrRawHeaders, (SG_byte*)ptr, (SG_uint32) (size * nmemb)) );
	
	return size * nmemb;
}
static void _write_string_chunk(SG_context* pCtx, SG_curl* pCurl, char* buffer, SG_uint32 bufLen, void* pVoidState, SG_uint32* pLenHandled)
{
	SG_string* pstrResponse = (SG_string*)pVoidState;
	//_sg_curl* pMe = (_sg_curl*)pCurl;
	*pLenHandled = 0;

	SG_ERR_CHECK_RETURN(  _check_for_and_handle_json_500(pCtx, pCurl, buffer, bufLen)  );

	if (bufLen) // libcurl docs say we may be called with zero length if file is empty
	{
		if (pstrResponse)
			SG_ERR_CHECK_RETURN(  SG_string__append__buf_len(pCtx, pstrResponse, (const SG_byte*)buffer, bufLen)  );
		*pLenHandled = bufLen;
	}
}
Ejemplo n.º 4
0
void _read_template_file(
	SG_context *pCtx,
	const char *templateFn,
	SG_string **pContent,	/**< we allocate, we free on error, else caller owns it */
	const _request_headers *pRequestHeaders,
	_replacer_cb replacer)
{
	SG_pathname *tpath = NULL;
	SG_file *pFile = NULL;
	SG_uint32 got = 0;
	char	tbuf[1024];

    //todo: make this thread-safe:
    if(_sg_uridispatch__templatePath==NULL)
        SG_ERR_CHECK(  _sgui_set_templatePath(pCtx)  );

	SG_ERR_CHECK(  SG_PATHNAME__ALLOC__COPY(pCtx, &tpath, _sg_uridispatch__templatePath)  );
	SG_ERR_CHECK(  SG_pathname__append__from_sz(pCtx, tpath, templateFn)  );

	SG_ERR_CHECK(  SG_file__open__pathname(pCtx, tpath, SG_FILE_RDONLY|SG_FILE_OPEN_EXISTING, 0644, &pFile)  );
	SG_PATHNAME_NULLFREE(pCtx, tpath);

	SG_ERR_CHECK(  SG_STRING__ALLOC(pCtx, pContent)  );

	do
	{
		SG_file__read(pCtx, pFile, sizeof(tbuf), (SG_byte *)tbuf, &got);
        if (SG_context__err_equals(pCtx, SG_ERR_EOF))
        {
			SG_context__err_reset(pCtx);
            break;
        }
		SG_ERR_CHECK_CURRENT;

		SG_ERR_CHECK(  SG_string__append__buf_len(pCtx, *pContent, (const SG_byte *)tbuf, got) );
	} while (got > 0);

	SG_ERR_CHECK(  SG_file__close(pCtx, &pFile)  );

	SG_ERR_CHECK(  _templatize(pCtx, *pContent, pRequestHeaders, replacer)  );

	return;

fail:
	SG_STRING_NULLFREE(pCtx, *pContent);
	SG_FILE_NULLCLOSE(pCtx, pFile);
	SG_PATHNAME_NULLFREE(pCtx, tpath);
}
/**
 * Construct a pathname to a personal TEMP directory within the WD
 * and hidden in .sgdrawer.  This directory will be used for the various
 * versions of a single file/item so that we can use external tools
 * during the AUTOMERGE and/or RESOLVE.
 * 
 * We want this temp directory to be local to the WD (so that files can be
 * moved/linked rather than copied -- both for input to diff3 and for the
 * auto-merge result -- IF THAT IS APPROPRIATE.  (And so that we don't have
 * to create a bunch of trash in the user's WD.)
 *
 * We want this TEMP directory to be for the duration of the MERGE/RESOLVE/
 * COMMIT effort.  That is, if MERGE needs to create a set of Ancestor/Mine/
 * Other files for an unresolved file conflict, RESOLVE will know where to
 * find them and COMMIT will clean up the mess.  This allows RESOLVE to have
 * a "redo-merge" option with a different tool, for example.  It also allows
 * us to keep the trash out of the working directory -- both for neatness
 * and to avoid having baggage if there is also a move/rename for the file.
 * 
 * We create a pathname and store it in the conflict structure
 * so that all versions of this file in this conflict can use it.
 *
 * The directory on disk should be deleted when this item has been committed
 * or reverted and the pvhIssue has been deleted.  (I'm not talking about
 * resolve here.)
 * 
 */
static void _sg_mrg__ensure_temp_dir_for_file_conflict(SG_context * pCtx,
													   SG_mrg * pMrg,
													   SG_mrg_cset_entry_conflict * pMrgCSetEntryConflict)
{
	SG_string * pString = NULL;
	const SG_byte * pszGid = (const SG_byte *)pMrgCSetEntryConflict->pMrgCSetEntry_Ancestor->bufGid_Entry;

	if (pMrgCSetEntryConflict->pPathTempDirForFile)
		return;

	// create something like: "<sgtemp>/<gid7>_YYYYMMDD_<k>/"

	SG_ERR_CHECK(  SG_STRING__ALLOC(pCtx, &pString)  );
	SG_ERR_CHECK(  SG_string__append__buf_len(pCtx, pString, pszGid, 7)  );
	SG_ERR_CHECK(  SG_workingdir__generate_and_create_temp_dir_for_purpose(pCtx, pMrg->pWcTx->pDb->pPathWorkingDirectoryTop,
																		   SG_string__sz(pString),
																		   &pMrgCSetEntryConflict->pPathTempDirForFile)  );

fail:
	SG_STRING_NULLFREE(pCtx, pString);
}
Ejemplo n.º 6
0
static void my_dump_id(SG_context * pCtx,
					   const char* psz_hid,
					   SG_uint32 nrDigits,
					   SG_uint32 indent,
					   SG_string * pStringOutput)
{
	char buf[4000];

	// we can abbreviate the full IDs.

	nrDigits = SG_MIN(nrDigits, SG_HID_MAX_BUFFER_LENGTH);
	nrDigits = SG_MAX(nrDigits, 4);

	// create:
	//     Dagnode[addr]: <child_id> <gen> [<parent_id>...]

	SG_ERR_CHECK_RETURN(  SG_sprintf(pCtx,buf,SG_NrElements(buf),"%*c ",indent,' ')  );
	SG_ERR_CHECK_RETURN(  SG_string__append__sz(pCtx,pStringOutput,buf)  );
	SG_ERR_CHECK_RETURN(  SG_string__append__buf_len(pCtx,pStringOutput,(SG_byte *)(psz_hid),nrDigits)  );
	SG_ERR_CHECK_RETURN(  SG_string__append__sz(pCtx,pStringOutput,"\n")  );
}
static void read_entire_stream__string(
    SG_context* pCtx,
    CFReadStreamRef myReadStream,
    SG_string** ppstr,
    CFHTTPMessageRef* pp
)
{
    SG_string* pstr = NULL;
    CFHTTPMessageRef myResponse = NULL;
    CFIndex numBytesRead = 0;

    SG_ERR_CHECK(  SG_string__alloc__sz(pCtx, &pstr, "")  );
    do
    {
        UInt8 buf[8192]; // TODO
        numBytesRead = CFReadStreamRead(myReadStream, buf, sizeof(buf));
        if( numBytesRead > 0 )
        {
            SG_ERR_CHECK(  SG_string__append__buf_len(pCtx, pstr, buf, numBytesRead)  );

            if (!myResponse)
            {
                myResponse = (CFHTTPMessageRef)CFReadStreamCopyProperty(myReadStream, kCFStreamPropertyHTTPResponseHeader);
            }
        }
        else if( numBytesRead < 0 )
        {
            CFStreamError myErr = CFReadStreamGetError(myReadStream);
            // TODO clean this up
            if (myErr.domain == kCFStreamErrorDomainPOSIX)
            {
                if (ETIMEDOUT == myErr.error)
                {
                    usleep(5000);
                    numBytesRead = 0;
                }
                else
                {
                    // Interpret myErr.error as a UNIX errno.
                    SG_ERR_THROW(  SG_ERR_ERRNO(myErr.error)  );
                }
            }
            else if (myErr.domain == kCFStreamErrorDomainMacOSStatus)
            {
                // Interpret myErr.error as a MacOS error code.
                // TODO SG_ERR_THROW(  SG_ERR_MAC((OSStatus) myErr.error)  );
                SG_ERR_THROW(  SG_ERR_UNSPECIFIED  );
            }
        }
    } while( numBytesRead > 0 );

    if (!myResponse)
    {
        myResponse = (CFHTTPMessageRef)CFReadStreamCopyProperty(myReadStream, kCFStreamPropertyHTTPResponseHeader);
    }

    *pp = myResponse;
    myResponse = NULL;

    *ppstr = pstr;
    pstr = NULL;

fail:
    if (myResponse)
    {
        CFRelease(myResponse);
    }
    SG_STRING_NULLFREE(pCtx, pstr);
}
Ejemplo n.º 8
0
void my_strip_comments(
    SG_context* pCtx,
    char* pjson,
    SG_string** ppstr
    )
{
    char *p = pjson;
    SG_string* pstr = NULL;

    SG_ERR_CHECK(  SG_STRING__ALLOC(pCtx, &pstr)  );

    while (*p)
    {
        char *q = NULL;
        char *r = NULL;

        q = p;
        while (*q)
        {
            if (13 == *q)
            {
                q++;
                if (10 == *q)
                {
                    q++;
                }
                break;
            }
            else if (10 == *q)
            {
                q++;
                break;
            }
            q++;
        }

        // now q points to the char after the EOL, or to the zero terminator
        r = p;
        while (
                (r < q)
                && (
                    (' ' == *r)
                    || ('\t' == *r)
                   )
              )
        {
            r++;
        }

        if (
                *r
                && ('/' == r[0])
                && ('/' == r[1])
           )
        {
            // this is a comment.  skip it.
        }
        else
        {
            SG_ERR_CHECK(  SG_string__append__buf_len(pCtx, pstr, (void*) p, q - p)  );
        }
        p = q;
    }

    *ppstr = pstr;
    pstr = NULL;

fail:
    SG_STRING_NULLFREE(pCtx, pstr);
}
Ejemplo n.º 9
0
static void _templatize(
	SG_context *pCtx,
	SG_string *content,
	const _request_headers *pRequestHeaders,
	_replacer_cb replacer)
{
	SG_string *instr = NULL;
	const char *next = NULL;
	SG_string *piece = NULL;
	SG_string *replacement = NULL;
	SG_string *inclusion = NULL;
	SG_string *replaceRaw = NULL;

	SG_ERR_CHECK(  SG_STRING__ALLOC__COPY(pCtx, &instr, content)  );
	SG_ERR_CHECK(  SG_string__clear(pCtx, content)  );
	SG_ERR_CHECK(  SG_STRING__ALLOC(pCtx, &piece)  );
	SG_ERR_CHECK(  SG_STRING__ALLOC(pCtx, &replacement)  );
	SG_ERR_CHECK(  SG_STRING__ALLOC(pCtx, &replaceRaw)  );

	next = SG_string__sz(instr);

	while (*next)
	{
		const char *delim = strstr(next, "{{{");

		if (delim == NULL)
		{
			SG_ERR_CHECK(  SG_string__append__sz(pCtx, content, next)  );
			break;
		}
		else
		{
			const char *rest = delim + 3;
			const char *end = strstr(rest, "}}}");

			if (end == NULL)
			{
				SG_ERR_CHECK(  SG_string__append__sz(pCtx, content, next)  );
				break;
			}

			SG_ERR_CHECK(  SG_string__append__buf_len(pCtx, content, (const SG_byte *)next, (delim - next) * sizeof(char))  );

			SG_ERR_CHECK(  SG_string__clear(pCtx, piece)  );
			SG_ERR_CHECK(  SG_string__clear(pCtx, replacement)  );

			SG_ERR_CHECK(  SG_string__append__buf_len(pCtx, piece, (const SG_byte *)rest, (end - rest) * sizeof(char))  );
			SG_ERR_CHECK(  SG_string__append__string(pCtx, replacement, piece)  );

			if (SG_string__sz(piece)[0] == '<')
			{
				SG_string__remove(pCtx, piece, 0, 1);

				SG_ASSERT(inclusion == NULL);
				SG_ERR_CHECK( _read_template_file(pCtx, SG_string__sz(piece), &inclusion, pRequestHeaders, replacer)  );

				SG_STRING_NULLFREE(pCtx, replacement);
				replacement = inclusion;
				inclusion = NULL;
			}
			else
			{
				SG_bool needEncoding = SG_TRUE;

				SG_ERR_CHECK(  replacer(pCtx, pRequestHeaders, piece, replaceRaw)  );

				// no verb-specific replacement? try generics
				if (sgeq(piece, replacement))
				{
					SG_ERR_CHECK(  _default_replacer(pCtx, pRequestHeaders, piece, replaceRaw,  &needEncoding)  );
				}

				if (needEncoding)
					SG_ERR_CHECK(  SG_htmlencode(pCtx, replaceRaw, replacement)  );
				else
					SG_ERR_CHECK(  SG_string__set__string(pCtx, replacement, replaceRaw)  );
			}

			SG_ERR_CHECK(  SG_string__append__string(pCtx, content, replacement)  );

			next = end + 3;
		}
	}

fail:
	SG_STRING_NULLFREE(pCtx, instr);
	SG_STRING_NULLFREE(pCtx, piece);
	SG_STRING_NULLFREE(pCtx, replacement);
	SG_STRING_NULLFREE(pCtx, replaceRaw);
	SG_STRING_NULLFREE(pCtx, inclusion);
}