Tag Archives: cgi file upload

C/C++ CGI File Upload

A long time ago when I still had (some) hair and hadn’t bitten the PHP bullet I played around with C++ CGIs. Owing to a lack of then available HOW-TO docs I went on to write a (badly written and error-filled) CGI in C/C++ HOW-TO and also a CGI Variable Wrapper. The HOW-TO did what it said on the tin and the wrapper provided an easy API to read/write GET and POST variables as well as cookies.

Surprisingly both the HOW-TO and the wrapper are still in use and I get contacted form time to time with queries. The most common query regards file upload which the wrapper doesn’t support. To illustrate a simple file upload I cobbled together a quick and dirty C example which I’ve provided via email ever since.

So here, for general reference, is my demonstration C code. Please note this is very untested and unrobust, even dodgier than my usual fare. I keep meddling with the idea of finding time to do a proper job either of a standalone file upload API or integrating support into the CGI wrapper. All of this is really just for kicks though as there are better solutions available.

/** Very rough-and-ready CGI file upload in C/C++
    This is demonstration code only really and, of course,
    no liability accepted for anything!

    David Cutting
    http://www.purplepixie.org/dave/
    http://blog.purplepixie.org/
    dcutting [at] purplepixie [dot] org

    Code Copyright DMC 22/05/2011
**/

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

int main(void)
{
FILE *out;
char *rawdata; // pointer for rawdata
char *data; // will be an offset of rawdata after the two newlines
unsigned long length; // length of data to be read used for malloc
unsigned long writelength; // use for the length of the write
char *pos; // used in the loop

printf("Content-type: text/html\n\n<HTML><PRE>"); // for debug output
// Various bits of debug output are included - comment out for live
// and replace with whatever output you'd like to send to the client

out=fopen("/var/www/test.jpg","wb+"); // open the output file

length=atol(getenv("CONTENT_LENGTH"));
writelength=length;

printf("Content Length: %u\n",length);

rawdata=malloc(length+1); // malloc required buffer

fread(rawdata, length, 1, stdin); // read into buffer

// now comes the loop, there are better ways but not that I can find quickly enough
for (pos=rawdata; pos<(rawdata+length-4); pos++)
{
 writelength--; // decrement the write length
 printf("%c %d\n",pos[0],pos[0]); // used for debug output (comment out for live)
 if ( (pos[0]==13) && (pos[1]==10) && (pos[2]==13) && (pos[3]==10) && ( (pos[4]<32)||(pos[4]>127) ) ) // pattern to find two double-newlines
 {
  data=pos+4; // move data pointer forward 4 to start of actual data
  pos=rawdata+length+2; // break loop
  printf("Found\n"); // another debug line - comment out for live
  writelength-=3; // decrement writelength by three (done one already above for this loop)
 }
}

printf("Writelength: %u\n",writelength); // yet another debug

// write the data to the file
fwrite(data, 1, writelength, out);

// close the file
fclose(out);

free(rawdata); // free memory

printf("Upload Complete"); // debug - comment out for live

return 0; // exit
}