Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Send file POST C++

I am trying to send a text file through 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 upload directory exists in the same directory as upload.php (contents above).

Here is the code which I am 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 execute the upload.exe (contents above). I get 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'm a little confused as to what this means. Is this an error?

It appears everything goes through (note: the contents of test.txt are "test"). Though when I look in the upload directory. The test.txt file is not in there. The directory is empty. Can anyone help me understand what the problem is? Thank-you!

BUMP Does no one know how to do this or is it no possible? Because if it's not possible then just tell me so I can stop wasting my time searching.

like image 495
sysenter Avatar asked Feb 03 '26 23:02

sysenter


1 Answers

Testing your c++ client I found that the variable content which contains the content of the file doesn't end with a NULL so when you copy it with sprintf you are copying random bytes until a NULL appears.

Change the allocation to this:

 content = (char*) malloc (sizeof(char)*(lSize+1));

And after reading the contents of the file do this:

content[lSize] = '\0';

Also, I am quite sure that the BOUNDARY should start at a new line. So make this change too:

 sprintf(buffer,"%s\r\n--%s--\r\n",buffer,boundary);

Edit:

By comparing a regular HTML form request, I can see that the content should start after two lines, so change this too:

sprintf(buffer,"%s\r\n%s",buffer,content);

Edit2:

After testing with the PHP code, I found some more problems with the c++ code. (btw, there is a typo in the PHP code: missing ] in the if statement)

The boundary isn't setup correctly.

The format of the mime should be like this:

--BOUNDARY
Content-Disposition: form-data; name="file"; filename="test2.txt"
Content-Type: text/plain

test
--BOUNDARY

The HTTP header should be like this: Content-Type: multipart/form-data; boundary=BOUNDARY

So the sprintfs 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 of the fixes in this post, the code should work.

To sum up:

  1. I would recommend using a VM setup to debug these kind of problems more easily because then you can use Wireshark\Fidler\Burp. (You can also try configuring proxy for localhost as well, never tried that myself. Also you can try using your external Internet IP and configure your router for port forwarding, but that's too complicated for this kind of task).
  2. If that doesn't help, NetCat may help. Not as easy and friendly, but does the job.
  3. Simply comparing a working example with your request output shows exactly what is missing. I used Beyond Compare for this. Always work with a comparing software since the human eye can be tricked easily.
  4. The most obvious was to read the Mime specification and see exactly what is missing.
like image 156
SatA Avatar answered Feb 06 '26 11:02

SatA



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!