embedded C POST support

Stephan Erickson <[email protected]> 26 Dec 2003 15:29:04 -0800
Newsgroups gmane.network.mathopd
Message-ID <[email protected]>
Hello,

I'm using mathopd embedded within a larger C++ program on a Windows Cygwin 
platform. I needed C access to mathopd POST requests, so I modified a few 
snippets from different open source projects to produce this functionality. 
Here is the result. I thought these might be useful.

- Stephan

 
#include <sys/types.h>
#include <sys/wait.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <unistd.h>
#include <errno.h>
#include <signal.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <fcntl.h>
#include "mathopd.h"

/* Function from Paul Phillips <paulp <at> go2net.com>
  * Modified to not use global mathopd_tempfile
  Stephan Erickson 
*/

int create_temporary_file(short want_unlink, char *storage, int size)
{
  int fd;
  char *mathopd_tempfile = malloc(PATHLEN+1);
  char *tempdir = "/tmp";

  mathopd_tempfile[0]=0; 
  strcat(mathopd_tempfile, tempdir); // use strcat for constants only
  strcat(mathopd_tempfile, "/mathopd-temp.XXXXXX");
 
  // open temp file 
  fd = mkstemp(mathopd_tempfile);
  if (fd == -1) {
    log_d("mkstemp");
    return 0;
  }

  if (storage != NULL) {
    int len = strlen(mathopd_tempfile);
    if (len < size) {
      memcpy(storage, mathopd_tempfile, len + 1);
    } else {
      close(fd);
      fd = 0;
      log_d("not enough memory for memcpy in storage\n");
      want_unlink = 1;
    }   
  }
 
  if (want_unlink) {
    if (unlink(mathopd_tempfile) == -1) {
      close(fd);
      fd = 0;
      log_d("unlink temp file\n");
    } 
  }
  return (fd);
}

/*
From: Toby DiPasquale <anany <at> ece.villanova.edu>
NOTE: This function must be called AFTER process_headers(), preferably in
it's own code module, similar to how imap.c, dump.c, dummy.c, redirect.c
and cgi.c are set up.

Modified to 
  - write to temporary file
  -  use recv for multiple reads to handle large size uploads
  -  not use MSG_SEEK which is incorrectly implemented on Windows platforms. 
Stephan Erickson

*/
/* get the POST body from the stream */
int get_post_file (struct request *r, char *tempfile, int maxsize)
{
	int rv, size;
	char *input_buffer;
	int fd = 0;
	int pagesize = 100000;
	int loopcount = 0;
      
	if (r->in_content_length==0) { 
	  tempfile[0]=0;
	  return 0; 
	}
	size = atoi (r->in_content_length);
        input_buffer = malloc (pagesize+1);
        fcntl (r->cn->fd, F_SETFL, 0);

        do {   
        	rv = recv (r->cn->fd, input_buffer, pagesize, 0);
		size -= rv; 
        	if (rv == -1)
        	{
                	switch (errno) {
                	default:
				log_d (
			  	"get_post_file: error reading from fd"
			  	);
				lerror ("recv");
			case ECONNRESET:
                		r->cn->action = HC_CLOSING;
                	case EAGAIN:
                		return 0;
                	}
        	}
        	if (rv == 0)
        	{
                	log_d ("get_post_file: body empty");
                	r->cn->action = HC_CLOSING;
                	return 0;
        	}
        	if (loopcount==0) {
	  		fd = create_temporary_file(0, tempfile, maxsize);
		}
		if (fd) {
	  		write(fd, input_buffer, rv);
		}
		loopcount++; 
   	} while (size>0); 

 	free(input_buffer);
	if (fd) {
	  close(fd);
	}
	fcntl (r->cn->fd, F_SETFL, O_NONBLOCK);
	return 0;
}