Upload files using POCO C++ Libraries

I have recently worked on uploading files using POCO and it gave me a hard time to get it work properly. I dint get much working tutorials on client side programming to upload a binary file to a upload link using POCO. So I thought of writing one by myself to help others who are facing the same problem.

Below is the code to upload any file as multipart form data by reading the entire data of file as binary :

Note that this may not work for large files as reading the entire data (1GB or more) in a variable will take a lot of memory and will slow down the system. You must consider chunked upload for this case by reading the file data in a fixed size buffer and uploading in chunks.

void uploadFile(const char* uploadLink, const char* filePath, const char* filename)
{
   try
   {
      //Prepare request
      Poco::URI uri(uploadLink);

      Poco::Net::HTTPClientSession session(uri.getHost(), uri.getPort());

      session.setKeepAlive(true);

      // prepare path
      std::string path(uri.getPathAndQuery());
      if (path.empty())
      {
         path = "/";
      }

      Poco::Net::HTTPRequest req(Poco::Net::HTTPRequest::HTTP_POST, path, Poco::Net::HTTPMessage::HTTP_1_1);

      // Set headers
      // Set Multipart type and some boundary value 
      req.setContentType("multipart/form-data; boundary=-------------------------87142694621188");

     // Append boundary, content type and disposition to file data

      std::string boundary = "-------------------------87142694621188";
      std::string data1("---------------------------87142694621188\r\nContent-Disposition: form-data; name=\"data\"; filename=\"");
      std::string data2(filename);
      std::string data3("\";\r\nContent-Type: application/octet-stream\r\n\r\n");

      std::string data4("\r\n---------------------------87142694621188--\r\n");
  
    // Read File Data in binary
      std::ifstream file (filePath,std::ios::binary);
      std::ostringstream ostrm;
      ostrm << file.rdbuf();

      std::string reqBody;
      reqBody.append(data1);
      reqBody.append(data2);
      reqBody.append(data3);
      reqBody.append(ostrm.str());
      reqBody.append(data4);

      req.setContentLength(reqBody.length());

      req.setKeepAlive(true);
      
      // sends request, returns open stream
      std::ostream& myOStream = session.sendRequest(req);
      // sends the body
      myOStream << reqBody;

      Poco::Net::HTTPResponse res;

      std::istream& rs = session.receiveResponse(res);

      //Get status code
      int statusCode = (int)res.getStatus();

      //Get status
      std::string status = res.getReason();

      std::string response;
      while(rs)
      {
         response.push_back(char(rs.get()));
      }
      std::cout<<"\nStatusCode: "<<statusCode<<"\nStatus: "<<status<<"\nResponse: "<<response;
  }
  catch(Poco::Exception& exception)
  {
       //Set Response for Exception
       std::cout<<"\nException occurred while uploading: "<<exception.displayText();
  }
}

The above method accepts the file name, upload link and complete file path (path along with file name) as parameters. Then we read the entire file data as binary and send the HTTP POST request to the server with the complete file data and boundaries appended. This uploads the file to server and we get the response received and the Http Status code.

Written By: Neha Gupta