I've got a simple C socket server listening at localhost:8080
that continuously read
s from the client socket until it encounters quit
at the end of the message.
I tested this on Chrome (Android) and Firefox (Android). I sent a POST
request as follows:
<form
action="http://localhost:8080"
method="POST" >
<input type="hidden" name="MAX_FILE_SIZE" value="100000"/>
Choose a file to upload: <input name="uploadedfile" type="file"/><br/>
<input type="submit" value="Upload File"/>
</form>
On the server side, I could only see that it recieved the request headers. No file data was recieved.
Req from Chrome:
POST / HTTP/1.1 Host: localhost:8080 Connection: keep-alive Content-Length: 52 Cache-Control: max-age=0 sec-ch-ua: "Not?A_Brand";v="8", "Chromium";v="108", "Google Chrome";v="108" sec-ch-ua-mobile: ?0 sec-ch-ua-platform: "Linux" Origin: http://localhost:5000 DNT: 1 Upgrade-Insecure-Requests: 1 Content-Type: application/x-www-form-urlencoded User-Agent: Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/108.0.0.0 Safari/537.36 Accept: text/html,application/xhtml xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.9 Sec-Fetch-Site: same-site Sec-Fetch-Mode: navigate Sec-Fetch-User: ?1 Sec-Fetch-Dest: document Referer: http://localhost:5000/ Accept-Encoding: gzip, deflate, br Accept-Language: en-GB,en-US;q=0.9,en;q=0.8,bn;q=0.7
When I added enctype="multipart/form-data"
to the above form
's attribute though, the full data and file with multiple boundaries was recieved.
Afterwards I tried the following POST with and without multipart:
<form
action="http://localhost:8080"
method="POST" >
<input name="test" value="foobar"/>
<input type="submit" value="Submit"/>
</form>
Results were same, only headers were recieved with urlencoded data. Full data was sent with multipart.
My question is why this is happening, and does the browser expect a response in the first case before it continues sending further data?
My aim is to recieve the POST data at once. Is that not possible?
On a side note, I noticed that after the multipart POST request, the request didn't end with two CR LFs, instead just one.
Edit: Just noticed that when I reload the browser it closes the connection and atbthat moment the remaining POST data shows up (without any CR LF ending after the POST).
Serve code
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <stdbool.h>
#include <netdb.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <sys/socket.h>
#include <unistd.h>
int main (int argc, char *argv[]) {
int portno = argc == 2 ? atoi(argv[1]) : 8080;
int srvfd = socket(AF_INET, SOCK_STREAM, 0);
int option = 1;
setsockopt(srvfd, SOL_SOCKET, SO_REUSEADDR, &option, sizeof(option));
struct sockaddr_in serv_addr;
memset(&serv_addr, 0, sizeof(serv_addr));
serv_addr.sin_family = AF_INET;
serv_addr.sin_addr.s_addr = INADDR_ANY;
serv_addr.sin_port = htons(portno);
if (bind(srvfd, (struct sockaddr*) &serv_addr, sizeof(serv_addr)) < 0) {
perror("server: error binding");
exit(1);
}
listen(srvfd, 1000);
printf("server: listening at port %d\n\n", portno);
struct sockaddr_in cli_addr;
socklen_t clilen = sizeof(cli_addr);
int clifd = accept(srvfd, (struct sockaddr*) &cli_addr, &clilen);
while (true) {
char buffer[256];
int n = read(clifd, buffer, 255);
if (n == 0) {
fprintf(stderr, "server: error: connection closed\n");
exit(1);
} else if (n < 0) {
perror("server: error reading from socket");
exit(1);
}
buffer[n] = 0;
printf("%s", buffer);
if (!strncmp(buffer, "quit", 4))
exit(0);
}
return 0;
}
CodePudding user response:
After printing some data, call fflush(stdout);
to make sure it is not buffered.
There is not an extra CRLF after the end of the POST data. The server knows the end of the POST data because of the Content-Length header. Because the browser specifies Content-Length: 52
the server knows the POST data is exactly 52 bytes.