Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Converting API call from PHP and cURL to ColdFusion cfhttp

I am attempting to code an API call to a online testing company. They have provided a sample call in PHP and cURL that I need to implement in ColdFusion 11 using <CFHTTP>. So far my attempt has failed. The only response I get from their server / API is:

Statuscode = "Connection Failure. Status code unavailable. "

and

ErrorDetail = "I/O Exception: Remote host closed connection during handshake".

If it were working I would get a JSON string detailing computed scores. Note that in the code below I've changed a few values for security reasons, other than that it's the original code. Any suggestions or comments would be much appreciated, thanks.

Here is the ColdFusion/cfhttp code:

<cfoutput>
<cfset sdata = [
    {
        "customerid" = "ACompany",
        "studentid" = "test",
        "form" = "X",
        "age" = "18.10",
        "norms" = "grade",
        "grade" = "2"
    },
    {
        "scores" = [
        {"subtest"="math","score"="34"},
        {"score"="23","subtest"="lang"},
        {"score"="402","subtest"="rcomp"}
        ]
    }

]>
<!--- create JSON string for request --->
<cfset jsdata = serializeJSON(sdata)>
<!--- make the call --->
<cfhttp method="Get" url="https://www.APIwebsite.php" timeout="10" result="varx">
     <cfhttpparam type="header" name="Content-Type" value = "application/json; charset=utf-8"/>
     <cfhttpparam type="body" value = "#jsdata#"/>
     <cfhttpparam type="header" name="Authorization" value="AuthCode"/> 
     <cfhttpparam type="header" name="Content-Length" value = "#len(jsdata)#"/>
</cfhttp>

<!--- show results --->
cfhttp return status code: [#varx.statusCode#]<br> 
cfhttp return fileContent: [#varx.fileContent#]<br>
</cfoutput>

Here is the PHP/cURL code:

<?php
    $data = array
    (
    "customerid" => "ACompany",
    "studentid" => "test",
    "scoringtype" => 2,
    "form" => "X",
    "age" => "18.10",
    "norms" => 'grade',
    "grade" => '2',
    "scores" => array(
        array("subtest" => "math", "score" => "34"),
        array("subtest" => "lang", "score" => "23"),
        array("subtest" => "rcomp", "score" => "402")
    ));

    $url = 'https://www.APIwebsite.php';
    $json_string = json_encode($data);

   $headers = array (
        "Content-Type: application/json; charset=utf-8",
        "Content-Length: " .strlen($json_string),
        "Authorization: AuthCode"
    );

    $channel = curl_init($url);
    curl_setopt($channel, CURLOPT_RETURNTRANSFER, true);
    curl_setopt($channel, CURLOPT_CUSTOMREQUEST, "GET");
    curl_setopt($channel, CURLOPT_HTTPHEADER, $headers);
    curl_setopt($channel, CURLOPT_POSTFIELDS, $json_string);
    curl_setopt($channel, CURLOPT_SSL_VERIFYPEER, false);
    curl_setopt($channel, CURLOPT_CONNECTTIMEOUT, 10);

    $response = curl_exec($channel); // execute the request
    $statusCode = curl_getInfo($channel, CURLINFO_HTTP_CODE);
    $error = curl_error($channel);
    curl_close($channel);

    http_response_code($statusCode);
    if ( $statusCode != 200 ){
        echo "Status code: {$statusCode} \n".$error;
    } else {
        $data = json_decode($response,true);
        foreach ($data as $key => $value) {
            echo nl2br($key . ': ' . $value . "\n");
        }
    }
?>
like image 931
LocoRolly Avatar asked Nov 25 '19 18:11

LocoRolly


1 Answers

First make sure the url you provided is correct (I know it's for the example but .php is not a valid domain name extension), and that the SSL certificate is valid

If both are correct, you should change the request method to POST for sending json data through the body

According to the http semantics

A client should not generate a body in a GET request. A payload received in a GET request has no defined semantics, cannot alter the meaning or target of the request, and might lead some implementations to reject the request and close the connection because of its potential as a request smuggling attack

There is a charset parameter in cfhttp so you don't need to send it in the header

Here is a code that should work

<cfset sdata = [
    {
        "customerid" = "ACompany",
        "studentid" = "test",
        "form" = "X",
        "age" = "18.10",
        "scoringtype" = 2,
        "norms" = "grade",
        "grade" = "2"
    },
    {
        "scores" = [
            {"subtest"="math","score"="34"},
            {"score"="23","subtest"="lang"},
            {"score"="402","subtest"="rcomp"}

        ]
    }

]>
<!--- create JSON string for request --->
<cfset jsdata = serializeJSON(sdata)>
<!--- make the call --->
<cfhttp method="post" charset="utf-8" url="https://api.website.com/" timeout="10" result="varx">
     <cfhttpparam type="header" name="Content-Type" value="application/json"/>
     <cfhttpparam type="header" name="Authorization" value="AuthCode"/> 
     <cfhttpparam type="header" name="Content-Length" value="#len(jsdata)#"/>
     <cfhttpparam type="body" value="#jsdata#"/>
</cfhttp>

<!--- show results --->
<cfoutput>
cfhttp return status code: [#varx.statusCode#]<br>
cfhttp return fileContent: [#varx.fileContent#]<br>
</cfoutput>
like image 114
Tofandel Avatar answered Oct 12 '22 15:10

Tofandel