#include "setup.h"
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <stdarg.h>
#include <time.h>
#include <curl/curl.h>
#include "formdata.h"
#include "strequal.h"
#ifdef MALLOCDEBUG
#include "memdebug.h"
#endif
#define BOUNDARY_LENGTH 32
#define HTTPPOST_CONTENTTYPE_DEFAULT "text/plain"
static void GetStr(char **string,
char *value)
{
if(*string)
free(*string);
*string = strdup(value);
}
#define FORM_FILE_SEPARATOR ','
#define FORM_TYPE_SEPARATOR ';'
static
int FormParse(char *input,
struct HttpPost **httppost,
struct HttpPost **last_post)
{
char name[256];
char contents[4096]="";
char major[128];
char minor[128];
long flags = 0;
char *contp;
char *type = NULL;
char *prevtype = NULL;
char *sep;
char *sep2;
struct HttpPost *post;
struct HttpPost *subpost;
unsigned int i;
if(1 <= sscanf(input, "%255[^ =] = %4095[^\n]", name, contents)) {
contp = contents;
if('@' == contp[0]) {
flags = HTTPPOST_FILENAME;
contp++;
post=NULL;
do {
sep=strchr(contp, FORM_TYPE_SEPARATOR);
sep2=strchr(contp, FORM_FILE_SEPARATOR);
if(sep2 && (sep2 < sep)) {
sep = sep2;
}
if(sep) {
if(FORM_FILE_SEPARATOR != *sep)
type = strstr(sep+1, "type=");
else
type=NULL;
*sep=0;
if(type) {
type += strlen("type=");
if(2 != sscanf(type, "%127[^/]/%127[^,\n]",
major, minor)) {
fprintf(stderr, "Illegally formatted content-type field!\n");
return 2;
}
sep = type + strlen(major)+strlen(minor)+1;
sep=strchr(sep, FORM_FILE_SEPARATOR);
}
}
else {
type=NULL;
sep=strchr(contp, FORM_FILE_SEPARATOR);
}
if(sep) {
*sep =0;
sep++;
}
if(!type) {
struct ContentType {
char *extension;
char *type;
};
static struct ContentType ctts[]={
{".gif", "image/gif"},
{".jpg", "image/jpeg"},
{".jpeg", "image/jpeg"},
{".txt", "text/plain"},
{".html", "text/plain"}
};
if(prevtype)
type = prevtype;
else
type = HTTPPOST_CONTENTTYPE_DEFAULT;
for(i=0; i<sizeof(ctts)/sizeof(ctts[0]); i++) {
if(strlen(contp) >= strlen(ctts[i].extension)) {
if(strequal(contp +
strlen(contp) - strlen(ctts[i].extension),
ctts[i].extension)) {
type = ctts[i].type;
break;
}
}
}
}
if(NULL == post) {
post = (struct HttpPost *)malloc(sizeof(struct HttpPost));
if(post) {
memset(post, 0, sizeof(struct HttpPost));
GetStr(&post->name, name);
GetStr(&post->contents, contp);
post->flags = flags;
if(type) {
GetStr(&post->contenttype, type);
prevtype=post->contenttype;
}
if(*last_post)
(*last_post)->next = post;
else
(*httppost) = post;
(*last_post) = post;
}
}
else {
subpost =(struct HttpPost *)malloc(sizeof(struct HttpPost));
if(subpost) {
memset(subpost, 0, sizeof(struct HttpPost));
GetStr(&subpost->name, name);
GetStr(&subpost->contents, contp);
subpost->flags = flags;
if(type) {
GetStr(&subpost->contenttype, type);
prevtype=subpost->contenttype;
}
subpost->more = post->more;
post->more = subpost;
}
}
contp = sep;
} while(sep && *sep);
}
else {
post = (struct HttpPost *)malloc(sizeof(struct HttpPost));
if(post) {
memset(post, 0, sizeof(struct HttpPost));
GetStr(&post->name, name);
if( contp[0]=='<' ) {
GetStr(&post->contents, contp+1);
post->flags = HTTPPOST_READFILE;
}
else {
GetStr(&post->contents, contp);
post->flags = 0;
}
if(*last_post)
(*last_post)->next = post;
else
(*httppost) = post;
(*last_post) = post;
}
}
}
else {
fprintf(stderr, "Illegally formatted input field!\n");
return 1;
}
return 0;
}
int curl_formparse(char *input,
struct HttpPost **httppost,
struct HttpPost **last_post)
{
return FormParse(input, httppost, last_post);
}
static int AddFormData(struct FormData **formp,
void *line,
long length)
{
struct FormData *newform = (struct FormData *)
malloc(sizeof(struct FormData));
newform->next = NULL;
if(!length)
length = strlen((char *)line);
newform->line = (char *)malloc(length+1);
memcpy(newform->line, line, length+1);
newform->length = length;
newform->line[length]=0;
if(*formp) {
(*formp)->next = newform;
*formp = newform;
}
else
*formp = newform;
return length;
}
static int AddFormDataf(struct FormData **formp,
char *fmt, ...)
{
char s[4096];
va_list ap;
va_start(ap, fmt);
vsprintf(s, fmt, ap);
va_end(ap);
return AddFormData(formp, s, 0);
}
char *Curl_FormBoundary(void)
{
char *retstring;
static int randomizer=0;
int i;
static char table64[]=
"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
retstring = (char *)malloc(BOUNDARY_LENGTH);
if(!retstring)
return NULL;
srand(time(NULL)+randomizer++);
strcpy(retstring, "curl");
for(i=4; i<(BOUNDARY_LENGTH-1); i++) {
retstring[i] = table64[rand()%64];
}
retstring[BOUNDARY_LENGTH-1]=0;
return retstring;
}
void Curl_FormFree(struct FormData *form)
{
struct FormData *next;
do {
next=form->next;
free(form->line);
free(form);
} while((form=next));
}
void curl_formfree(struct HttpPost *form)
{
struct HttpPost *next;
if(!form)
return;
do {
next=form->next;
if(form->more)
curl_formfree(form->more);
if(form->name)
free(form->name);
if(form->contents)
free(form->contents);
if(form->contenttype)
free(form->contenttype);
free(form);
} while((form=next));
}
struct FormData *Curl_getFormData(struct HttpPost *post,
int *sizep)
{
struct FormData *form = NULL;
struct FormData *firstform;
struct HttpPost *file;
int size =0;
char *boundary;
char *fileboundary=NULL;
if(!post)
return NULL;
boundary = Curl_FormBoundary();
AddFormDataf(&form,
"Content-Type: multipart/form-data;"
" boundary=%s\r\n",
boundary);
firstform = form;
do {
size += AddFormDataf(&form, "\r\n--%s\r\n", boundary);
size += AddFormDataf(&form,
"Content-Disposition: form-data; name=\"%s\"",
post->name);
if(post->more) {
fileboundary = Curl_FormBoundary();
size += AddFormDataf(&form,
"\r\nContent-Type: multipart/mixed,"
" boundary=%s\r\n",
fileboundary);
}
file = post;
do {
if(post->more) {
size += AddFormDataf(&form,
"\r\n--%s\r\nContent-Disposition: attachment; filename=\"%s\"",
fileboundary, file->contents);
}
else if(post->flags & HTTPPOST_FILENAME) {
size += AddFormDataf(&form,
"; filename=\"%s\"",
post->contents);
}
if(file->contenttype) {
size += AddFormDataf(&form,
"\r\nContent-Type: %s",
file->contenttype);
}
#if 0
if(file->contenttype &&
!strnequal("text/", file->contenttype, 5)) {
size += AddFormData(&form, "\r\nContent-Transfer-Encoding: binary", 0);
}
#endif
size += AddFormData(&form, "\r\n\r\n", 0);
if((post->flags & HTTPPOST_FILENAME) ||
(post->flags & HTTPPOST_READFILE)) {
FILE *fileread;
char buffer[1024];
int nread;
fileread = strequal("-", file->contents)?stdin:
fopen(file->contents, "rb");
if(fileread) {
while((nread = fread(buffer, 1, 1024, fileread))) {
size += AddFormData(&form,
buffer,
nread);
}
if(fileread != stdin)
fclose(fileread);
} else {
size += AddFormData(&form, "[File wasn't found by client]", 0);
}
} else {
size += AddFormData(&form, post->contents, 0);
}
} while((file = file->more));
if(post->more) {
size += AddFormDataf(&form,
"\r\n--%s--",
fileboundary);
free(fileboundary);
}
} while((post=post->next));
size += AddFormDataf(&form,
"\r\n--%s--\r\n",
boundary);
*sizep = size;
free(boundary);
return firstform;
}
int Curl_FormInit(struct Form *form, struct FormData *formdata )
{
if(!formdata)
return 1;
form->data = formdata;
form->sent = 0;
return 0;
}
int Curl_FormReader(char *buffer,
size_t size,
size_t nitems,
FILE *mydata)
{
struct Form *form;
int wantedsize;
int gotsize;
form=(struct Form *)mydata;
wantedsize = size * nitems;
if(!form->data)
return -1;
do {
if( (form->data->length - form->sent ) > wantedsize ) {
memcpy(buffer, form->data->line + form->sent, wantedsize);
form->sent += wantedsize;
return wantedsize;
}
memcpy(buffer,
form->data->line + form->sent,
gotsize = (form->data->length - form->sent) );
form->sent = 0;
form->data = form->data->next;
} while(!gotsize && form->data);
return gotsize;
}
#ifdef _FORM_DEBUG
int main(int argc, char **argv)
{
#if 0
char *testargs[]={
"name1 = data in number one",
"name2 = number two data",
"test = @upload"
};
#endif
int i;
char *nextarg;
struct HttpPost *httppost=NULL;
struct HttpPost *last_post=NULL;
struct HttpPost *post;
int size;
int nread;
char buffer[4096];
struct FormData *form;
struct Form formread;
for(i=1; i<argc; i++) {
if( FormParse( argv[i],
&httppost,
&last_post)) {
fprintf(stderr, "Illegally formatted input field: '%s'!\n",
argv[i]);
return 1;
}
}
form=Curl_getFormData(httppost, &size);
FormInit(&formread, form);
while(nread = FormReader(buffer, 1, sizeof(buffer), (FILE *)&formread)) {
fwrite(buffer, nread, 1, stderr);
}
fprintf(stderr, "size: %d\n", size);
return 0;
}
#endif