json_object* OGRCouchDBDataSource::REQUEST(const char* pszVerb,
                                           const char* pszURI,
                                           const char* pszData)
{
    bMustCleanPersistent = true;

    char** papszOptions = NULL;
    papszOptions = CSLAddString(papszOptions, CPLSPrintf("PERSISTENT=CouchDB:%p", this));

    CPLString osCustomRequest("CUSTOMREQUEST=");
    osCustomRequest += pszVerb;
    papszOptions = CSLAddString(papszOptions, osCustomRequest);

    CPLString osPOSTFIELDS("POSTFIELDS=");
    if (pszData)
        osPOSTFIELDS += pszData;
    papszOptions = CSLAddString(papszOptions, osPOSTFIELDS);

    papszOptions = CSLAddString(papszOptions, "HEADERS=Content-Type: application/json");

    if (!osUserPwd.empty() )
    {
        CPLString osUserPwdOption("USERPWD=");
        osUserPwdOption += osUserPwd;
        papszOptions = CSLAddString(papszOptions, osUserPwdOption);
    }

    CPLDebug("CouchDB", "%s %s", pszVerb, pszURI);
    CPLString osFullURL(osURL);
    osFullURL += pszURI;
    CPLPushErrorHandler(CPLQuietErrorHandler);

    CPLHTTPResult * psResult = CPLHTTPFetch( osFullURL, papszOptions);
    CPLPopErrorHandler();
    CSLDestroy(papszOptions);
    if (psResult == NULL)
        return NULL;

    const char* pszServer = CSLFetchNameValue(psResult->papszHeaders, "Server");
    if (pszServer == NULL || !STARTS_WITH_CI(pszServer, "CouchDB"))
    {
        CPLHTTPDestroyResult(psResult);
        return NULL;
    }

    if (psResult->nDataLen == 0)
    {
        CPLHTTPDestroyResult(psResult);
        return NULL;
    }

    json_object* jsobj = NULL;
    const char* pszText = reinterpret_cast<const char*>(psResult->pabyData);
    if( !OGRJSonParse(pszText, &jsobj, true) )
    {
        CPLHTTPDestroyResult(psResult);
        return NULL;
    }

    CPLHTTPDestroyResult(psResult);
    return jsobj;
}
json_object* OGRCouchDBDataSource::REQUEST(const char* pszVerb,
                                           const char* pszURI,
                                           const char* pszData)
{
    bMustCleanPersistant = TRUE;

    char** papszOptions = NULL;
    papszOptions = CSLAddString(papszOptions, CPLSPrintf("PERSISTENT=CouchDB:%p", this));

    CPLString osCustomRequest("CUSTOMREQUEST=");
    osCustomRequest += pszVerb;
    papszOptions = CSLAddString(papszOptions, osCustomRequest);

    CPLString osPOSTFIELDS("POSTFIELDS=");
    if (pszData)
        osPOSTFIELDS += pszData;
    papszOptions = CSLAddString(papszOptions, osPOSTFIELDS);

    papszOptions = CSLAddString(papszOptions, "HEADERS=Content-Type: application/json");

    if (osUserPwd.size())
    {
        CPLString osUserPwdOption("USERPWD=");
        osUserPwdOption += osUserPwd;
        papszOptions = CSLAddString(papszOptions, osUserPwdOption);
    }

    CPLDebug("CouchDB", "%s %s", pszVerb, pszURI);
    CPLString osFullURL(osURL);
    osFullURL += pszURI;
    CPLPushErrorHandler(CPLQuietErrorHandler);

    CPLHTTPResult * psResult = CPLHTTPFetch( osFullURL, papszOptions);
    CPLPopErrorHandler();
    CSLDestroy(papszOptions);
    if (psResult == NULL)
        return NULL;

    const char* pszServer = CSLFetchNameValue(psResult->papszHeaders, "Server");
    if (pszServer == NULL || !EQUALN(pszServer, "CouchDB", 7))
    {
        CPLHTTPDestroyResult(psResult);
        return NULL;
    }

    if (psResult->nDataLen == 0)
    {
        CPLHTTPDestroyResult(psResult);
        return NULL;
    }

    json_tokener* jstok = NULL;
    json_object* jsobj = NULL;

    jstok = json_tokener_new();
    jsobj = json_tokener_parse_ex(jstok, (const char*)psResult->pabyData, -1);
    if( jstok->err != json_tokener_success)
    {
        CPLError( CE_Failure, CPLE_AppDefined,
                    "JSON parsing error: %s (at offset %d)",
                    json_tokener_error_desc(jstok->err), jstok->char_offset);

        json_tokener_free(jstok);

        CPLHTTPDestroyResult(psResult);
        return NULL;
    }
    json_tokener_free(jstok);

    CPLHTTPDestroyResult(psResult);
    return jsobj;
}