Finally I had the time to revisit it again. Many moons ago I tried to understand how Multipart file upload works and kinda didn't succeed, but then again I didn't put that much effort into it. I did it now because I have a project on my hands which requires this, whole theory didn't seem very hard and I was able to produce working code for client and server sides in a few hours.
Sending multipart requests is great for file uploading and other large quantities of data. I won't go about and write a tutorial on how to send these requests, instead I will point you to an
awesome RFC and
this tutorial.
While browsing I had found a working example done in Python. Cannot remember where I found it or to who it belongs, but anyway, that example code can be found
in my projects folder here.
And so based on the docs and that example code I was able to produce a CPP project for my own needs. I tried to make it very simple to adapt for other projects. The project can be
found here, and along with it I made a
simple PHP script that receives the commands and acts upon them, it's also a part of other bigger project...
Here's a C++ code I produced:
/*
Author: Kulverstukas
Date: 2014.02.23
Website: http://9v.lt; Evilzone.org
Description:
Simple prototype of Multipart POST sending in C++
*/
#include <iostream>
#include <winsock2.h>
#include <string>
#include <fstream>
#include "windows.h"
#include "stdio.h"
using namespace std;
#define PORT 80
#define IP "127.0.0.1"
#define HOST "locahost"
#define RECEIVER "/receive_data.php"
#define COMPNAME "compname"
#define PROGRAM "program"
#define FILENAME "file"
#define BOUNDARY "----------Evil_B0uNd4Ry_$"
#define DUMMY_DATA "c2FzYXNhc2FzZGRmZGZkY2Q="
#define DUMMY_FILE "dummy.txt"
//------------------------------------
string constructBody(string args[2], string file[2]);
string readFile(string fileName);
//------------------------------------
int main() {
// initiate the socket!
SOCKET dataSock;
WSADATA wsaData;
int error = WSAStartup(0x0202, &wsaData);
if (error != 0) {
WSACleanup();
exit(1); // oh shit, this shouldn't happen!
}
// all internets, engage!
SOCKADDR_IN target;
target.sin_family = AF_INET;
target.sin_port = htons(PORT);
target.sin_addr.s_addr = inet_addr(IP);
dataSock = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
if (dataSock == INVALID_SOCKET) {
exit(1); // Houston, we have a problem!
}
connect(dataSock, (SOCKADDR*)&target, sizeof(target));
string programNames[5][2] = {{"KULVERTOP", "Chrome"}, {"KULVERTOP", "Firefox"}, {"KULVERTOP", "InternetExplorer"}, {"KULVERTOP", "Opera"}, {"KULVERTOP", "Skype"}};
string file[2] = {FILENAME, "Default.txt"};
int a = sizeof(programNames)/sizeof(programNames[0]);
for (int i = 0; i < a; i++) {
printf("Sending data for %s\n", (programNames[i][1]).c_str());
string body = constructBody(programNames[i], file);
char header[1024];
sprintf(header, "POST %s HTTP 1.1\r\n"
"Host: %s\r\n"
"Content-Length: %d\r\n"
"Connection: Keep-Alive\r\n"
"Content-Type: multipart/form-data; boundary=%s\r\n"
"Accept-Charset: utf-8\r\n\r\n", RECEIVER, IP, strlen(body.c_str()), BOUNDARY);
// printf("%s\n\n", header);
int p = send(dataSock, header, strlen(header), 0);
// printf("p == %d\n", p);
int k = send(dataSock, body.c_str(), strlen(body.c_str()), 0);
// printf("k == %d\n", k);
// char buff[1024];
// recv(dataSock, buff, 1024, 0);
// printf("%s\n\n", buff);
}
closesocket(dataSock);
WSACleanup();
}
string readFile(string fileName) {
string fileContents;
ifstream tmp(fileName.c_str());
getline(tmp, fileContents);
tmp.close();
return fileContents;
}
string constructBody(string args[2], string file[2]) {
string body;
string CRLF = "\r\n";
// first we add the args
body.append("--"+string(BOUNDARY)+CRLF);
body.append("Content-Disposition: form-data; name=\""+string(COMPNAME)+"\""+CRLF);
body.append(CRLF);
body.append(args[0]+CRLF);
body.append("--"+string(BOUNDARY)+CRLF);
body.append("Content-Disposition: form-data; name=\""+string(PROGRAM)+"\""+CRLF);
body.append(CRLF);
body.append(args[1]+CRLF);
// now we add the file
body.append("--"+string(BOUNDARY)+CRLF);
body.append("Content-Disposition: form-data; name=\""+string(FILENAME)+"\"; filename=\""+string(DUMMY_FILE)+"\""+CRLF);
body.append("Content-Type: text/plain"+CRLF);
body.append(CRLF);
body.append(DUMMY_DATA+CRLF);
body.append("--"+string(BOUNDARY)+"--"+CRLF);
body.append(CRLF);
// printf(body.c_str()); exit(0);
return body;
}