ErikMinekus / sm-ripext

SourceMod REST in Pawn Extension
https://forums.alliedmods.net/showthread.php?t=298024
GNU General Public License v3.0
136 stars 38 forks source link

Malformed JSON body sent on Windows #76

Closed dysphie closed 4 months ago

dysphie commented 4 months ago

I think there's an issue with the extension when it comes to sending JSON content on Windows. I've tried with 3 different backends and all of them are unable to parse the request body sent by RipExt. The same endpoints respond appropriately to requests made through Postman and Curl, or when the SourcePawn script is run on Linux. The extension can successfully GET, but not POST or PUT.

Node.js, Express ```js const express = require('express') const app = express() app.use(express.json()) app.post('/', (req, res) => { console.log(req.body) res.sendStatus(200) }) app.listen(8080) ``` ``` BadRequestError: request aborted at IncomingMessage.onAborted (/home/test/node_modules/raw-body/index.js:245:10) at IncomingMessage.emit (node:events:520:28) at IncomingMessage._destroy (node:_http_incoming:224:10) at _destroy (node:internal/streams/destroy:122:10) at IncomingMessage.destroy (node:internal/streams/destroy:84:5) at abortIncoming (node:_http_server:806:9) at socketOnClose (node:_http_server:800:3) at Socket.emit (node:events:532:35) at TCP. (node:net:338:12) ```
Python, Flask ```py from flask import Flask, request, jsonify, make_response app = Flask(__name__) @app.route('/', methods=['POST']) def echo_post(): data = request.get_json() print(data) return make_response('', 200) if __name__ == '__main__': app.run(debug=True, port=8080) ``` ``` An error occurred: Invalid chunk header 127.0.0.1 - - [14/Jun/2024 14:46:24] "POST / HTTP/1.1" 500 - ```
Rust, Actix Web: ``` use actix_web::{web, App, HttpResponse, HttpServer, Responder}; use serde_json::Value; async fn handle_post(json: web::Json) -> impl Responder { println!("{}", json.0); HttpResponse::Ok() } #[actix_web::main] async fn main() -> std::io::Result<()> { HttpServer::new(|| { App::new().route("/", web::post().to(handle_post)) }) .bind("127.0.0.1:8080")?.run().await } ``` ``` 400 Response, no output ```

SourcePawn code:

Action Cmd_Echo(int client, int args)
{
    HTTPRequest request = new HTTPRequest("http://localhost:8080/");
    JSONObject json = new JSONObject();
    json.SetInt("value", 123);
    request.Post(json, HTTPResult_Echo);
    delete json;

    return Plugin_Handled;
}

void HTTPResult_Echo(HTTPResponse response, any value, const char[] error)
{
    if (response.Status != HTTPStatus_OK)
    {
        LogError("HTTPResult_Echo: %d", response.Status);
        return;
    }

    PrintToServer("Ok");
}

Extension debug verbose:

] sm_echo 
Sending
=== Info: STATE: INIT => CONNECT handle 0x41d39820; line 1646 (connection #-5000)

=== Info: Added connection 3. The cache now contains 4646263185219780609 members

=== Info: Hostname in DNS cache was stale, zapped

=== Info: family0 == v4, family1 == v6

=== Info:   Trying 127.0.0.1:8080...

=== Info: STATE: CONNECT => WAITCONNECT handle 0x41d39820; line 1707 (connection #3)

=== Info: Connected to 127.0.0.1 (127.0.0.1) port 8080 (#3)

=== Info: STATE: WAITCONNECT => SENDPROTOCONNECT handle 0x41d39820; line 1842 (connection #3)

=== Info: STATE: SENDPROTOCONNECT => DO handle 0x41d39820; line 1861 (connection #3)

==> Send header
POST / HTTP/1.1
Host: 127.0.0.1:8080
User-Agent: sm-ripext/1.3.1
Accept-Encoding: deflate, gzip
Transfer-Encoding: chunked
Accept: application/json
Content-Type: application/json
Expect: 100-continue

=== Info: STATE: DO => DO_DONE handle 0x41d39820; line 1935 (connection #3)

=== Info: STATE: DO_DONE => PERFORM handle 0x41d39820; line 2056 (connection #3)

=== Info: Mark bundle as not supporting multiuse

=== Info: HTTP 1.1 or later with persistent connection

<== Recv header
HTTP/1.1 100 Continue

==> Send data
60c48e3000
=== Info: Signaling end of chunked upload via terminating chunk.

==> Send data
60c48e3000
=== Info: Mark bundle as not supporting multiuse

=== Info: HTTP 1.1 or later with persistent connection

<== Recv header
HTTP/1.1 400 Bad Request

<== Recv header
Connection: close

<== Recv header

<== Recv data

=== Info: STATE: PERFORM => DONE handle 0x41d39820; line 2254 (connection #3)

=== Info: multi_done

=== Info: The cache now contains 4733681987489890304 members

=== Info: Closing connection 3

=== Info: Expire cleared (transfer 0x41d39820)

L 06/14/2024 - 14:57:10: [rusty.smx] HTTPResult_Echo: 400

I'm running all of my tests on Windows 11 and RipExt 1.3.1. I've tried local and remote backends with the same results.

dysphie commented 4 months ago

It seems this issue is actually resolved in the main branch, and the builds are simply outdated. Getting the correct readings after rebuilding.