microsoft / cpprestsdk

The C++ REST SDK is a Microsoft project for cloud-based client-server communication in native code using a modern asynchronous C++ API design. This project aims to help C++ developers connect to and interact with services.
Other
7.99k stars 1.65k forks source link

Http exception `Failed to write request body` if request is too big. #1728

Open zabeyka opened 1 year ago

zabeyka commented 1 year ago

Colleagues, hello! I have problems with using cpprest in my project caused by size of json that I try to send to server. I realized a small example that indicates the problem:

#include <iostream>
#include <string>

#include <cpprest/json.h>
#include <cpprest/http_client.h>
#include <cpprest/http_listener.h>
#include <cpprest/asyncrt_utils.h>
#include <cpprest/http_msg.h>

using utility::conversions::to_string_t;

int main(int argc, char * argv[]) {
    std::cerr << "Hello, cpprest bug example!" << std::endl;

    web::http::http_request request = web::http::http_request(web::http::methods::PUT);
    web::json::value json;

    std::string dataStr = "30 symbols here in this string";
    std::string dataStrToSend;
    for (int i = 0; i < 100000; i++)
        dataStrToSend += dataStr;

    json[to_string_t("data")] = web::json::value::string(to_string_t(dataStrToSend));

    web::uri dstUri = to_string_t("http://127.0.0.1:7000");
    request.set_request_uri(dstUri);
    request.set_body(json.serialize(), to_string_t("application/json"));

    web::http::client::http_client client(dstUri);

    try {
        auto future = client.request(request);
        web::http::http_response response = future.get();
    }
    catch (const web::http::http_exception &ex) {
        std::cerr << "Http exception occurred. Error code: " << ex.error_code() << " .Reason: `" << ex.what() << '`' << std::endl;
    }
    catch (const pplx::task_canceled&) { 
        std::cerr << "Task is canceled." << std::endl; 
    }
    catch (const std::exception& e) {
        std::cerr << "Can't create request: " << utility::conversions::to_utf8string(e.what()) << std::endl;
    }
    catch (...) { 
        std::cerr << "Unknown exception occurred" << std::endl;
    }

    std::cerr << "Bye, cpprest bug example!" << std::endl;
    return 0;
}

That is my server:

#!/usr/bin/env python3

from http.server import HTTPServer, BaseHTTPRequestHandler
from socketserver import ThreadingMixIn
import threading
import json

resp = json.dumps({'reply': {'status': 0, 'message': 'OK'}}).encode('utf-8')
print(resp)

class Handler(BaseHTTPRequestHandler):

    def do_PUT(self):
        content_len = int(self.headers.get('Content-Length'))
        print(self.headers)
        self.send_response(200)
        self.send_header('Content-Type', 'application/json')
        self.send_header('Content-Length', str(len(resp)))
        self.end_headers()
        self.wfile.write(resp)

class ThreadingSimpleServer(ThreadingMixIn, HTTPServer):
    pass

def run():
    server = ThreadingSimpleServer(('0.0.0.0', 7000), Handler)
    server.serve_forever()

if __name__ == '__main__':
    run()

So, the exception is thrown...

But! If you reduce the length of dataStrToSend string.... for (int i = 0; i < 1000; i++) dataStrToSend += dataStr; there are no exceptions.

Also exceptions disappear when you add to server string looking like self.rfile.read(int(self.headers.get('Content-Length')))

Thanks a lot for your help!

P.S.: As for me it looks like the server is responding before it has received the full request. The same looking like problem discribed at: https://github.com/dakrone/clj-http/issues/277