[SalesForce] HTTPRequest: GET submitting as a POST

I'm developing a batch class to make api calls and get data from that api in to salesforce. I'm making a POST request (to the login url) first to login to the api. The authentication process sends back a sessionid cookie. Then I'm making a GET request (to the report url), using the returned sessionid, to get data from the api.

The GET request is failing with response

"[Status=Forbidden, StatusCode=403]" and

body of that response is

{"detail": "CSRF Failed: CSRF cookie not set."} (The POST request to the login URL is successful).

I contacted our api developers to debug this, they used Python script to duplicate what I'm trying to do in the batch class. They can successfully login to the login url and get data from the report url (passing only the sessionid as I did and not they are not getting the CSRF error)! They looked at the nginx log and it shows that Salesforce is making a POST request to the report url but not GET. So they concluded that there is something wrong on the salesforce side but I can't figure out why the GET method in my batch class is ending up making a POST request to the api! Can anyone please help me out with this? Thanks in advance.

Following is the code from my batch class:

//Instantiate a new http object
        Http login = new Http();
        //Instantiate a new HTTP request, specify the method (POST) as well as the endpoint
        HttpRequest loginReq = new HttpRequest();
        loginReq.setEndpoint('http://dev.ph.jgi.com/reporting_api/v1/login/');
        loginReq.setMethod('POST');
        loginReq.setHeader('Content-Type', 'application/x-www-form-urlencoded');
        loginReq.setBody('email='+EncodingUtil.urlEncode(Username, 'UTF-8')+'&password='+EncodingUtil.urlEncode(Password, 'UTF-8'));
        //Send the request, and get a response
        HttpResponse loginRes = login.send(loginReq);
        loginResult = loginRes.getBody();
        if(loginResult.contains('Success'))
        {
            cookie = loginRes.getHeader('Set-Cookie');
            index1 = cookie.indexOf('sessionid=')+10;
            cookie = cookie.substring(index1);
            index2 = cookie.indexOf(';');
            sessionId = cookie.substring(0,index2);
            /********'GET' request*******/
            //Instantiate a new http object
            Http h = new Http();            
            //Instantiate a new HTTP request, specify the method (GET) as well as the endpoint
            HttpRequest req = new HttpRequest();
            req.setEndpoint('http://dev.ph.jgi.com/reporting_api/v1/report/');            
            req.setHeader('Connection', 'keep-alive');
            req.setHeader('Cookie', 'sessionid='+sessionId);
            metrics = 'net_flows,inflows,outflows';
            startDate = Date.Today().Year() + '-1-1';
            endDate = Date.Today().Year() + '-' + Date.Today().Month() + '-' + Date.Today().Day();
            req.setBody('metrics='+EncodingUtil.urlEncode(metrics, 'UTF-8')+'&dimensions=fund&o=net_flows&c=200&start_date='+startDate+'&end_date='+endDate);
            req.setMethod('GET');
            //Send the request, and return a response
            HttpResponse res = h.send(req);
            result = res.getBody();
        }

The nginx log shows the following:

"POST /reporting_api/v1/report/ HTTP/1.1" 0.091 403 58 "-" "SFDC-Callout/29.0"

Best Answer

I'm not certain, but it could be because you're setting a body on the request. Most GET requests don't have a body, so Salesforce may be 'helpfully' trying to force your request to have the default 'correct' for use with a non-empty body.

Is there a way to make that request while specifying the parameters you needs somewhere other than the body of the request?

Edit: I've confirmed the above on my own instance.

If you set a non-empty body on the HTTPRequest, the received method is a POST, not the requested GET. If you have an empty body, the other server receives the correct GET request.

Related Topic