Send POST file C ++
I am trying to post a text file via POST to my upload.php form in php on my localhost webserver using C ++.
Here is my PHP code for the request:
<?php
$uploaddir = 'upload/';
if (is_uploaded_file(isset($_FILES['file']['tmp_name'])?($_FILES['file'['tmp_name']):0))
{
$uploadfile = $uploaddir . basename($_FILES['file']['name']);
echo "File ". $_FILES['file']['name'] ." uploaded successfully. ";
if (move_uploaded_file($_FILES['file']['tmp_name'], $uploadfile))
{
echo "File was moved! ";
}
else
{
print_r($_FILES);
}
}
else
{
print_r($_FILES);
}
?>
The directory upload
exists in the same directory as upload.php (content above).
Here is the code I'm using to prepare the http request and send it:
#include <windows.h>
#include <wininet.h>
#include <iostream>
#include <tchar.h>
#pragma comment(lib,"wininet.lib")
#define ERROR_OPEN_FILE 10
#define ERROR_MEMORY 11
#define ERROR_SIZE 12
#define ERROR_INTERNET_OPEN 13
#define ERROR_INTERNET_CONN 14
#define ERROR_INTERNET_REQ 15
#define ERROR_INTERNET_SEND 16
using namespace std;
int main()
{
// Local variables
static char *filename = "test.txt"; //Filename to be loaded
static char *filepath = "C:\\wamp\\www\\post\\test.txt"; //Filename to be loaded
static char *type = "text/plain";
static char boundary[] = "--BOUNDARY---"; //Header boundary
static char nameForm[] = "file"; //Input form name
static char iaddr[] = "localhost"; //IP address
static char url[] = "/post/upload.php"; //URL
char hdrs[512]={'-'}; //Headers
char * buffer; //Buffer containing file + headers
char * content; //Buffer containing file
FILE * pFile; //File pointer
long lSize; //File size
size_t result;
// Open file
pFile = fopen ( filepath , "rb" );
if (pFile==NULL)
{
printf("ERROR_OPEN_FILE");
getchar();
return ERROR_OPEN_FILE;
}
printf("OPEN_FILE\n");
// obtain file size:
fseek (pFile , 0 , SEEK_END);
lSize = ftell (pFile);
rewind (pFile);
// allocate memory to contain the whole file:
content = (char*) malloc (sizeof(char)*(lSize+1));
if (content == NULL)
{
printf("ERROR_MEMORY");
getchar();
return ERROR_OPEN_FILE;
}
printf("MEMORY_ALLOCATED\t \"%d\" \n",&lSize);
// copy the file into the buffer:
result = fread (content,1,lSize,pFile);
if (result != lSize)
{
printf("ERROR_SIZE");
getchar();
return ERROR_OPEN_FILE;
}
printf("SIZE_OK\n");
content[lSize] = '\0';
// terminate
fclose (pFile);
printf("FILE_CLOSE\n");
//allocate memory to contain the whole file + HEADER
buffer = (char*) malloc (sizeof(char)*lSize + 2048);
//print header
sprintf(hdrs,"Content-Type: multipart/form-data; boundary=%s",boundary);
sprintf(buffer,"%s\r\nContent-Disposition: form-data; name=\"%s\"; filename=\"%s\"\r\n",boundary,nameForm,filename);
sprintf(buffer,"%sContent-Type: %s\r\n",buffer,type);
sprintf(buffer,"%s\r\n%s",buffer,content);
sprintf(buffer,"%s\r\n--%s--\r\n",buffer,boundary);
printf("%s", buffer);
//Open internet connection
HINTERNET hSession = InternetOpen("WINDOWS",INTERNET_OPEN_TYPE_PRECONFIG, NULL, NULL, 0);
if(hSession==NULL)
{
printf("ERROR_INTERNET_OPEN");
getchar();
return ERROR_OPEN_FILE;
}
printf("INTERNET_OPENED\n");
HINTERNET hConnect = InternetConnect(hSession, iaddr,INTERNET_DEFAULT_HTTP_PORT, NULL, NULL, INTERNET_SERVICE_HTTP, 0, 1);
if(hConnect==NULL)
{
printf("ERROR_INTERNET_CONN");
getchar();
return ERROR_INTERNET_CONN;
}
printf("INTERNET_CONNECTED\n");
HINTERNET hRequest = HttpOpenRequest(hConnect, (const char*)"POST",_T(url),NULL, NULL, NULL,INTERNET_FLAG_RELOAD, 1);
if(hRequest==NULL)
{
printf("ERROR_INTERNET_REQ");
getchar();
}
printf("INTERNET_REQ_OPEN\n");
BOOL sent= HttpSendRequest(hRequest, hdrs, strlen(hdrs), buffer, strlen(buffer));
if(!sent)
{
printf("ERROR_INTERNET_SEND");
getchar();
return ERROR_INTERNET_CONN;
}
printf("INTERNET_SEND_OK\n");
InternetCloseHandle(hSession);
InternetCloseHandle(hConnect);
InternetCloseHandle(hRequest);
getchar();
return 0;
}
When I run upload.exe (content above). I am getting the following output:
OPEN_FILE
MEMORY_ALLOCATED "1832340"
SIZE_OK
FILE_CLOSE
---BOUNDARY---
Content Disposition: form-data; name="file"; filename="test.txt"
Content-Type: text/plain
test
---BOUNDARY---
INTERNET_OPENED
INTERNET_CONNECTED
INTERNET_REQ_OPEN
INTERNET_SEND_OK
Here is the PHP error log:
[12-Nov-2014 20:09:58 Europe/Paris] PHP Stack trace:
[12-Nov-2014 20:09:58 Europe/Paris] PHP 1. {main}() C:\wamp\www\post\upload.php:0
I am a little confused what this means. This is mistake?
Everything seems to pass (note: the content of test.txt is a "test"). Although when I look at the catalog upload
. The test.txt file is missing. The directory is empty. Can anyone help me understand what is the problem? Thanks you!
BUMP Nobody knows how to do this, or is it impossible? Because if that's not possible, just tell me so I can stop wasting time searching.
source to share
Testing your client in C ++ I found that the variable content
that contains the contents of the file does not end with a character NULL
, so when you copy with it sprintf
, you copy random bytes as long as it NULL
appears.
Change the selection to this:
content = (char*) malloc (sizeof(char)*(lSize+1));
And after reading the contents of the file, do the following:
content[lSize] = '\0';
Also, I'm pretty sure I BOUNDARY
should start on a new line. So make this change too:
sprintf(buffer,"%s\r\n--%s--\r\n",buffer,boundary);
Edit:
Comparing a normal HTML form request, I can see that the content should start after two lines, so change that as well:
sprintf(buffer,"%s\r\n%s",buffer,content);
Edit2:
After testing with PHP code, I found some more issues with C ++ code. (By the way, there is a typo in the PHP code: missing ]
in the if statement)
The border is not configured correctly.
The mime format should be as follows:
--BOUNDARY
Content-Disposition: form-data; name="file"; filename="test2.txt"
Content-Type: text/plain
test
--BOUNDARY
The HTTP header should look like this: Content-Type: multipart / form-data; border = BORDERS
So it sprintf
should look like this:
sprintf(hdrs,"Content-Type: multipart/form-data; boundary=%s",boundary);
sprintf(buffer,"--%s\r\nContent-Disposition: form-data; name=\"%s\"; filename=\"%s\"\r\n",boundary,nameForm,filename);
sprintf(buffer,"%sContent-Type: %s\r\n",buffer,type);
sprintf(buffer,"%s\r\n%s",buffer,content);
sprintf(buffer,"%s\r\n--%s\r\n",buffer,boundary);
After doing all the fixes in this post, the code should work.
Summarizing:
- I would recommend using a virtual machine setup to debug these problems more easily because then you can use Wireshark \ Fidler \ Burp. (You can also try configuring a proxy for localhost, never tried this yourself. You can also try using your external Internet IP and configure your router for port forwarding, but it's too complicated for this kind of task).
- If that doesn't help, NetCat can help. Not so easy and friendly, but does the job.
- Just comparing the working example to your query will output exactly what is missing. For this I used Beyond Compare. Always work with comparison software as the human eye can deceive easily.
- The most obvious one was to read the Mime spec and see what exactly is missing.
source to share