I'm trying to POST a binary file to a web server with a client program written in C (Windows). I'm pretty new to socket programming, so tried POST requests using multipart/form-data
with plain text messages, and text-based files (.txt, .html, .xml). Those seem to work fine. But when trying to send a PNG file, I'm running into some problems.
The following is how I read the binary file
FILE *file;
char *fileName = "download.png";
long int fileLength;
//Open file, get its size
file = fopen(fileName, "rb");
fseek(file, 0, SEEK_END);
fileLength = ftell(file);
rewind(file);
//Allocate buffer and read the file
void *fileData = malloc(fileLength);
memset(fileData, 0, fileLength);
int n = fread(fileData, 1, fileLength, file);
fclose(file);
I confirmed that all the bytes are getting read properly.
This is how I form my message header and body
//Prepare message body and header
message_body = malloc((int)1000);
sprintf(message_body, "--myboundary\r\n"
"Content-Type: application/octet-stream\r\n"
"Content-Disposition: form-data; name=\"myFile\"; filename=\"%s\"\r\n\r\n"
"%s\r\n--myboundary--", fileName, fileData);
printf("\nSize of message_body is %d and message_body is \n%s\n", strlen(message_body), message_body);
message_header = malloc((int)1024);
sprintf(message_header, "POST %s HTTP/1.1\r\n"
"Host: %s\r\n"
"Content-Type: multipart/form-data; boundary=myboundary\r\n"
"Content-Length: %d\r\n\r\n", path, host, strlen(message_body));
printf("Size of message_header is %d and message_header is \n%s\n", strlen(message_header), message_header);
The connection and sending part also works fine as the request is received properly. But, the received png file is ill-formatted.
The terminal prints out the following for fileData
if I use %s
in printf
ëPNG
I searched around and came to know that binary data doesn't behave like strings and thus printf/ sprintf/ strcat etc. cannot be used on them. As binary files have embedded null characters, %s
won't print properly. It looks like that is the reason fileData
only printed the PNG header.
Currently, I send two send()
requests to server. One with the header and the other with body and footer combined. That was working for text-based files. To avoid using sprintf
for binary data, I tried sending one request for header, one for binary data (body) & one for footer. That doesn't seem to work either.
Also, found that memcpy
could be used to append binary data to normal string. That didn't work either. Here is how I tried that (Not sure whether my implementation is correct or not).
sprintf(message_body, "--myboundary\r\n"
"Content-Disposition: form-data; name=\"text1\"\r\n\r\n"
"text default\r\n"
"--myboundary\r\n"
"Content-Type: application/octet-stream\r\n"
"Content-Disposition: form-data; name=\"myFile\"; filename=\"%s\"\r\n\r\n", fileName);
char *message_footer = "\r\n--myboundary--";
char *message = (char *)malloc(strlen(message_body) + strlen(message_footer) + fileLength);
strcat(message, message_body);
memcpy(message, fileData, fileLength);
memcpy(message, message_footer, strlen(message_footer));
I'm stuck at how I could send my payload which requires appending of string (headers), binary data (payload), string (footer).
Any advice/ pointers/ reference links for sending the whole file would be appreciated. Thank You!