Tengo un programa C ++ que intenta cargar un archivo usando una aplicación PHP que se ejecuta en un servidor web Apache2. Estoy teniendo un problema muy extraño sobre el que no estoy seguro de qué hacer. Así que creo la solicitud HTTP usando la función httpSendRequest () y parece estar formateada correctamente cuando se ve en Wireshark Wireshark image. Sin embargo, el archivo no se carga y cuando veo el archivo access.log para Apache, no muestra ningún agente de usuario o longitud del contenido a pesar de que ambos existen claramente en la captura de paquetes. imagen de error de Apache

Como referencia, las solicitudes que devolvieron un estado 200 son el mismo paquete enviado usando burp suite en lugar de mi programa usando httpSendRequest, y también puedo cargar con éxito un archivo usando un navegador web.

Aquí está el código para crear la solicitud usando httpSendRequest, la mayor parte del cual se tomó directamente de esta publicación de codeguru.

#include <windows.h>
#include <wininet.h>
#include <iostream>


#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 *type       = "image/jpg";
   static char boundary[]  = "PaulRules";            //Header boundary
   static char nameForm[]  = "fileToUpload";     //Input form name
   static char iaddr[]     = "192.168.0.105";        //IP address
   static char url[]       = "upload.php";         //URL

   char hdrs[255];                  //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 ( filename , "rb" );
   if (pFile==NULL) return ERROR_OPEN_FILE;

   // 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);
   if (content == NULL) return ERROR_MEMORY;

   // copy the file into the buffer:
   result = fread (content,1,lSize,pFile);
   if (result != lSize) return ERROR_SIZE;

   // terminate
   fclose (pFile);

   //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=\"fileToUpload\"; filename=\"test.bmp\"\r\n",boundary,nameForm,filename);
   sprintf(buffer,"%sContent-Type: %s\r\n\r\n",buffer,type);

   int cb = strlen(buffer);
   char * bp = buffer + cb;
   memcpy(bp, content, lSize);
   bp += lSize;
   int cw = sprintf(bp,"\r\n--%s--\r\n",boundary);

   //Open internet connection
   HINTERNET hSession = InternetOpen("Paul was here :)",INTERNET_OPEN_TYPE_PRECONFIG, NULL, NULL, 0);
   if(hSession==NULL) return ERROR_INTERNET_OPEN;

   HINTERNET hConnect = InternetConnect(hSession, iaddr,INTERNET_DEFAULT_HTTP_PORT, NULL, NULL, INTERNET_SERVICE_HTTP, 0, 1);
   if(hConnect==NULL) return ERROR_INTERNET_CONN;

   HINTERNET hRequest = HttpOpenRequest(hConnect, (const char*)"POST",url, NULL, NULL, (const char**)"*/*", 0, 1);
   if(hRequest==NULL) return ERROR_INTERNET_REQ;

   BOOL sent= HttpSendRequest(hRequest, hdrs, strlen(hdrs), buffer, cb + lSize + cw);
   if(!sent) return ERROR_INTERNET_SEND;

   //close any valid internet-handles
   InternetCloseHandle(hSession);
   InternetCloseHandle(hConnect);
   InternetCloseHandle(hRequest);

   return 0;
}

Y aquí está el script PHP en el lado del servidor.

<?php
$target_dir = "recvFile/";
$target_file = $target_dir . basename($_FILES["fileToUpload"]["name"]);
$uploadOk = 1;
$imageFileType = pathinfo($target_file,PATHINFO_EXTENSION);

// Check if file already exists
if (file_exists($target_file)) {
    echo "File already exists";
    $uploadOk = 0;
}

// Check file size
if ($_FILES["fileToUpload"]["size"] > 500000) {
    echo "File to large";
    $uploadOk = 0;
}

// Check if $uploadOk is set to 0 by an error
if ($uploadOk == 0) {
    echo "ERROR File not uploaded";
}

//attempt to upload the file
else {
    if (move_uploaded_file($_FILES["fileToUpload"]["tmp_name"], $target_file)) {
        //echo "The file ". basename( $_FILES["fileToUpload"]["name"]). " has been uploaded.";
        echo "Command:1";
    }
    else {
        echo $_FILES["fileToUpload"]["tmp_name"];
        echo "ERROR uploading file";
    }
}
?>
1
pchihak 11 nov. 2017 a las 23:47

2 respuestas

La mejor respuesta

Su archivo de origen es "test.txt" pero lo está cargando en "test.bmp". Haz que tengan la misma extensión.

type = "image/jpg";

Cambie type a "image/*" o "text/*" si se supone que es texto.

Su operación probablemente sea exitosa al ver que imprime "Command 1". Probablemente el archivo esté ahí, pero no es el que esperaba. Si no es así, vea qué error puede extraer del lado de PHP.

sprintf(buffer,"--%s\r\nContent-Disposition: form-data; \
name=\"fileToUpload\"; filename=\"test.bmp\"\r\n",
boundary,nameForm,filename);

Tiene un especificador de formato "%s" y 4 parámetros. Elimina los dos últimos parámetros.

Utilice HttpOpenRequest la forma en que se recomienda:

const char *accept[] = { "image/*", NULL }; // or `"text/*"`
HttpOpenRequest(hConnect, "POST",url, NULL, NULL, accept, 0, 1);

#include <Windows.h>
#include <Wininet.h>
#include <iostream>
#include <fstream>
#include <sstream>
#include <string>

#pragma comment(lib, "wininet.lib")

int main()
{
    HINTERNET hsession = NULL;
    HINTERNET hconnect = NULL;
    HINTERNET hrequest = NULL;

    const char* server = "localhost";
    const char* url = "upload.php";
    const char* type = "image/*";
    std::string filename = "test.bmp";

    std::ifstream infile("c:\\test\\test.bmp", std::ios::binary);
    if(!infile) 
        return 0;

    std::ostringstream oss;
    oss << infile.rdbuf();

    std::string headers = "Content-type: multipart/form-data, boundary=uniquestring";

    std::string data = "--uniquestring\r\n\
Content-Disposition: form-data; name=\"fileToUpload\"; filename=\"%1\"\r\n\
Content-Type: %2\r\n\
\r\n\
%3\r\n\
--uniquestring--";

    data.replace(data.find("%1"), 2, filename);
    data.replace(data.find("%2"), 2, type);
    data.replace(data.find("%3"), 2, oss.str());

    hsession = InternetOpen("appname", INTERNET_OPEN_TYPE_PRECONFIG, NULL, NULL, 0);
    if(!hsession) 
        goto cleanup;

    hconnect = InternetConnect(hsession, server, INTERNET_DEFAULT_HTTP_PORT,
        NULL, NULL, INTERNET_SERVICE_HTTP, 0, 1);
    if(!hconnect)
        goto cleanup;

    const char *accept[] = { type, NULL };
    hrequest = HttpOpenRequest(hconnect, "POST", url, NULL, NULL, accept, 0, 1);
    if(!hrequest)
        goto cleanup;

    BOOL sent = HttpSendRequest(hrequest, headers.data(), headers.size(), 
        &data[0], data.size());
    if(sent)
    {
        DWORD bufsize = 4096;
        std::string read(bufsize, 0);
        InternetReadFile(hrequest, &read[0], bufsize, &bufsize);
        read.resize(bufsize);
        std::cout << read << "\n";
    }
    else
    {
        goto cleanup;
    }

cleanup:
    if(hrequest) InternetCloseHandle(hrequest);
    if(hconnect) InternetCloseHandle(hconnect);
    if(hsession) InternetCloseHandle(hsession);
    return 0;
}
1
Barmak Shemirani 13 nov. 2017 a las 01:43

En aras de la integridad, aquí está el código completamente operativo

#include <windows.h>
#include <wininet.h>
#include <iostream>

using namespace std;
int main()
{
   // Local variables
   static char *filename   = "Desert.jpg";   //Filename to be loaded
   static char *type       = "multipart/form-data";
   static char boundary[]  = "PaulRules";            //Header boundary
   static char nameForm[]  = "fileToUpload";     //Input form name
   static char iaddr[]     = "192.168.0.105";        //IP address
   static char url[]       = "upload.php";         //URL

   char hdrs[255];                  //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 ( filename , "rb" );

   // 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);

   // copy the file into the buffer:
   result = fread (content,1,lSize,pFile);

   // terminate
   fclose (pFile);

   //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=\"fileToUpload\"; filename=\"%s\"\r\n",boundary, filename);
   sprintf(buffer,"%sContent-Type: %s\r\n\r\n",buffer,type);

   int cb = strlen(buffer);
   char * bp = buffer + cb;
   memcpy(bp, content, lSize);
   bp += lSize;
   int cw = sprintf(bp,"\r\n--%s--\r\n",boundary);

   //Open internet connection
   HINTERNET hSession = InternetOpen("Winsock",INTERNET_OPEN_TYPE_PRECONFIG, NULL, NULL, 0);

   HINTERNET hConnect = InternetConnect(hSession, iaddr,INTERNET_DEFAULT_HTTP_PORT, NULL, NULL, INTERNET_SERVICE_HTTP, 0, 1);

   const char* accept[] = {"*/*", NULL};
   HINTERNET hRequest = HttpOpenRequest(hConnect, (const char*)"POST",url, NULL, NULL, accept, 0, 1);

   BOOL sent= HttpSendRequest(hRequest, hdrs, strlen(hdrs), buffer, cb + lSize + cw);

   DWORD dwSize, dwRead;
   CHAR szBuffer[1024];
   if(!InternetQueryDataAvailable(hRequest, &dwSize, 0, 0)){
      std::cout << "QUERYDATA ERROR: " << GetLastError() << std::endl;
   }
   else{
      while(InternetReadFile(hRequest, szBuffer, sizeof(szBuffer)-1, &dwRead) && dwRead) {
        szBuffer[dwRead] = 0;
        dwRead=0;
      }
      cout << szBuffer;
   }

   //close any valid internet-handles
   InternetCloseHandle(hSession);
   InternetCloseHandle(hConnect);
   InternetCloseHandle(hRequest);

   return 0;
}
1
pchihak 12 nov. 2017 a las 19:44