I have a CPPCMS (V1.1.0) server (sample code below) and a C# (.NET 4.0) client (sample code below) and I'm trying to POST a file from the C# client to the CPPCMS server.
The server works if I POST to it from PaleMoon or a CURL (V7.56.1) client (sample code below), so I don't think the problem is in the server code.
The client works if I POST from it to http://posttestserver.com, so I don't think the problem is in the client code.
However, when I try my "working" CPPCMS server against my "working" C# client, I get a 400 Bad Request response. The response is generated by CPPCMS (my first server log is never written as application::main is not called), though CPPCMS does not show or throw any error on the server, even with debug logging enabled.
So I have a client and a server that both work on their own, but not together. Looking at the network trace in Microsoft Network Monitor 3.4 and TCPDUMP, I cannot see what's functionally different between a working request and a failing one. The trace suggests that CPPCMS fails on the very first packet of the POST (of a multi-packet POST request), though this may be a timing issue in the trace, I don't know.
Notes
- The CPPCMS server is running on Ubuntu 16.04
- The C# client is running on Windows 7
- The working CURL test was done from the server machine
- The working PaleMoon test was done from the client machine
- I copied the code from Ubuntu into this post by hand, so I may have errors in their samples below
CPPCMS web-server : main.cpp
#include <cppcms/service.h> #include <cppcms/applications_pool.h> #include <cppcms/application.h> #include <cppcms/http_request.h> #include <iostream> #include <string> class Application : public cppcms::application { public: Application ( cppcms::service & service ): cppcms::application(service) { } virtual void main ( std::string url ){ std::cout << "Request for " << url << std::endl << " Uploaded file count " << request().files().size() << std::endl; }; int main(int argc, char * * args) { cppcms::service service(argc, args); service.applications_pool().mount ( cppcms::applications_factory<Application>() ); service.run(); return 0; } // g++ -o test main.cpp -lcppcms -lbooster -std=c++11 // ./test -c config.js CPPCMS web-server : config.js
{ "service": { "api": "http" , "port": 8080 , "ip": "10.0.0.4" } , "http": { "script": "/" } , "logging": { "level": "debug" } } C# client : main.cs
using System; using System.Net.Http; namespace CPPCMSTest { class Program { static void Main(string[] args) { using(var client = new HttpClient()) using(var content = new MultipartFormDataContent()) { content.Add(new StringContent("test"), "name", "filename"); Console.WriteLine ( client . PostAsync("http://10.0.0.4:8080", content) . Result . Content . ReadAsStringAsync() . Result ); } } } } // Output is: // <html> // <body> // <h1>400 Bad Request</h1> // </body> // </html> // // CPPCMS output is: // 2018-01-19 12:34:56; cppcms_http, info: POST / (http_api.cpp:249) // // That is, CPPCMS doesn't show an error and doesn't reach the application::main CURL client : main.cpp
#include <curl/curl.h> #include <iostream> int main(int argc, char * * args) { curl_global_init(CURL_GLOBAL_DEFAULT); CURL * curl(curl_easy_init()); curl_mime * mime(curl_mime_init(curl)); curl_mime_filedata(curl_mime_addpart(mime), "main.cpp"); curl_easy_setopt(curl, CURLOPT_MIMEPOST, mime); curl_easy_setopt(curl, CURLOPT_URL, "http://10.0.0.4:8080"); curl_easy_perform(curl); curl_mime_free(mime); long responseCode; curl_easy_getinfo(curl, CURLINFO_RESPONSE_CODE, &responseCode); curl_easy_cleanup(curl); std::cout << "Response code is " << responseCode << std::endl; return 0; } // g++ -o test main.cpp -lcurl -std=c++11 // ./test // Response code is 200 // // CPPCMS output is: // 2018-01-19 12:34:56; cppcms_http, info: POST / (http_api.cpp:249) // Request for // Uploaded file count 1