I'm trying to make an HTTP POST request to a server with a large binary payload (100kb). I cannot make this work because the client fails to write more than ~6000 bytes.
Here are the experiments I did:
#define NUM_SAMPLES 32000
int16_t samples[NUM_SAMPLES];
WiFiClient client;
// ...other parts omitted...
// no body, goes ok
client.println("POST /api HTTP/1.1");
client.println("Host: salernosimone.com");
client.println("Connection: close");
client.println("Content-Type: application/octect-stream");
client.println();
// short body, goes ok
client.println("POST /api HTTP/1.1");
client.println("Host: salernosimone.com");
client.println("Connection: close");
client.println("Content-Type: application/octect-stream");
client.println("Content-Length: 4096");
client.println();
client.write((uint8_t*) samples, 4096);
// large body, single write, not received by the server
client.println("POST /api HTTP/1.1");
client.println("Host: salernosimone.com");
client.println("Connection: close");
client.println("Content-Type: application/octect-stream");
client.println("Content-Length: 8192");
client.println();
client.write((uint8_t*) samples, 8192);
// large body, chunked write, still not received by the server
client.println("POST /api HTTP/1.1");
client.println("Host: salernosimone.com");
client.println("Connection: close");
client.println("Content-Type: application/octect-stream");
client.println("Content-Length: 8192");
client.println();
client.write((uint8_t*) samples, 4096);
client.write((uint8_t*) samples, 4096); // this actually writes < 2000 bytes
Anyone knows what's going on? How can I make the request succeed?
No. If the content length is < 6000, the request goes fine and I get a response from the server. Otherwise, the request does not complete.
I guess it is because I set Content-Length=100k, but only send ~6k bytes, so the NGINX server discards the request as malformed (or something in the like).
I made an error in the first code. ContentLength == length(samples). Since samples is made of uint16_t values, each value is made up of 2 bytes. I'm looping i from 0 to number of samples, thus the data I have to upload is 2 * the current chunk size.
That said, you're not suggesting any improvement so far.
write returns size_t, so you can check how much was actually written. That's the basic contract for these low-level read and write functions: "try this many; how many got through?" You have to do the math accordingly. For example, WiFiNINA doesn't support writing a Stream, but here is how ESP32 does it
That loop works without a delay between each block, but you might need one.
If the buffer is around 6000, then that makes sense. And you're setting Content-Length, so the server will wait until it gets that much. If you're short, that will timeout.
You restated the problem, which I already know. But you did not suggested a solution.
How do I empty the internal buffer, if that's the problem?
Even considering the actually written bytes (e.g. 2000 in the second call), if I write a third time it returns 0.
A mixture of chunkSize and delay did the job. Depending on how much data you want to send, you have to configure those 2 values.
E.g.
8k body => chunkSize = 2048 + delay 10ms works fine
70k body => same config doesn't work
70k body => chunkSize 2048 + delay 50ms works fine (most of the times)
For future reference, here's the code I used to send 130k of data.