boblemaire / asyncHTTPrequest

asynchronous HTTP for ESP using ESPasyncTCP. Works like XMLHTTPrequest in JS.
GNU General Public License v3.0
65 stars 31 forks source link

Connection not Closing #24

Closed lbussy closed 4 years ago

lbussy commented 4 years ago

This is not a bug, it's likely me being a dumba%$, but I'm willing to accept ridicule right now. I am unit testing some code and POSTing a JSON to a PHP endpoint just to get the code working. It looks as if the session never closes, therefore the onData callback keeps firing. If I were to place money on it, I'd say I messed up my PHP somewhere but I am not sure where.

Here's my C++ code snippet:

asyncHTTPrequest postobject;

void sendPost()
{
    // Do stuff here to make the json

    postobject.onData(resultHandler);
    if (postobject.readyState() == 0 || postobject.readyState() == 4)
    {
        Log.verbose(F("DEBUG: About to send JSON." CR));    // DEBUG
        Serial.println(json.c_str());                       // DEBUG
        postobject.setDebug(true);                          // DEBUG

        postobject.setTimeout(5);
        postobject.open("POST", "http://host.com/api.php");
        postobject.setReqHeader("Content-Type","application/json");
        postobject.send(json.c_str());
    }
    else
    {
        Log.verbose(F("DEBUG: Previous post still in progress." CR));
    }
}

void resultHandler(void* optParm, asyncHTTPrequest* report, int readyState) {
    if (readyState == 4)
    {
        if (report->responseHTTPcode() == 200)
        {
            Log.notice(F("HTTP response code %d received ($dms). The request was successfully received, understood, and accepted." CR), report->responseHTTPcode(), report->elapsedTime());
        }
    }
}

And here is the receiving PHP code:

<?php

$debug = true;                                  // Write log file if true
$file = "api.txt";                           // API Log
$args = "LOCK_EX | FILE_APPEND";                // File lock mode
$json = file_get_contents('php://input');       // Get incoming post

function writeLog($logLine) { // Log file writer (if $debug == true)
    global $debug;
    if ($debug) {
        // Get timestamp
        $date = date('Y-m-j H:m:s  ', time());
        //Open the File Stream
        global $file;
        $handle = fopen($file, "a");

        //Lock File, error if unable to lock
        if (flock($handle, LOCK_EX)) {
            fwrite($handle, $date);
            fwrite($handle, $logLine);
            fwrite($handle, "\n");
            flock($handle, LOCK_UN);
        }
    }
}

$result = json_decode($json);

if (json_last_error() === JSON_ERROR_NONE) { // JSON is valid
    writeLog("Received JSON: " . $json);
    header("HTTP/1.1 200 OK");
    echo "Ok\n\n";
} else {
    // Unable to decode JSON
    writeLog("Invalid JSON received.");
    header("HTTP/1.1 400 Bad Request");
    echo "Invalid JSON received.";
}

?>

Here's my serial log when this fires:

2020-07-14T14:51:45Z V: DEBUG: About to send JSON.
Debug(15859): setDebug(on) version 1.1.15
Debug(15865): setTimeout(5)
Debug(15866): open(POST, http://192.168.168.xxx/api.ph)  
Debug(  0): _parseURL() HTTP://192.168.168.xxx:80/api.php
Debug(  5): _connect()
Debug( 12): send(char*) {"dummy":"json"}.16... (165)                     <-- (JSON redacted)
Debug( 25): _buildRequest()
Debug( 28): _send() 270
Debug( 29): *can't send
Debug( 62): _onConnect handler
Debug( 63): _setReadyState(1)
Debug( 63): _send() 270
Debug( 65): *sent 270
... (153)): _onData handler HTTP/1.1 200 OK
Debug( 72): _collectHeaders()
Debug( 73): _setReadyState(2)
Debug( 73): _setReadyState(3)
Debug( 74): *all data received - no disconnect
Debug( 59): _setReadyState(4)
2020-07-14T15:13:57Z N: HTTP response code 200 received (59ms). The request was successfully received, understood, and accepted.
2020-07-14T15:13:57Z N: HTTP response code 200 received (59ms). The request was successfully received, understood, and accepted.
[...]

The last line repeats every second or so till the next POST event.

As I said, the Debug( 74): *all data received - no disconnect points to me not doing something right at the webserver level. Does my problem jump out at you?

boblemaire commented 4 years ago

@lbussy

Not very fluent at php, but I think that in addition to the HTTP header, it is sending back a payload with either "ok" or "Invalid JSON received.". That would be the data received by asyncHTTPrequest. Ordinarily, an application would read that data, either in the ondata callback, or elsewhere upon some event signaled by the callback. In your case, it looks as if you never actually retrieve the data, as a result the ondata callback continues to be invoked.

Unfortunately, I have not provided a flush function, so you will need to actually read the data. Presumably this is something you should do anyway to verify that the json parsed. Once you retrieve the data, the callbacks should stop.

BTW/ It is advisable to check the return from open and send as they can and do fail for reasons beyond the control of the program.

lbussy commented 4 years ago

Aha! That seems reasonable. I'll try that as soon as I get of this call. Thank you!

lbussy commented 4 years ago

That was it, thank you sir!