413 lines
8.1 KiB
C++
Executable File
413 lines
8.1 KiB
C++
Executable File
/*
|
|
** JNetLib
|
|
** Copyright (C) Joshua Teitelbaum, sergent first class, 1014 army.
|
|
** Author: Joshua Teitelbaum
|
|
** File: httppost.cpp
|
|
** License: see jnetlib.h
|
|
*/
|
|
|
|
#ifdef _WIN32
|
|
#include <windows.h>
|
|
#include <malloc.h>
|
|
#endif
|
|
#include "netinc.h"
|
|
#include "util.h"
|
|
#include "httppost.h"
|
|
|
|
#include <malloc/malloc.h>
|
|
#include <sys/stat.h>
|
|
|
|
static char *PREFIX = "--";
|
|
static char *NEWLINE = "\r\n";
|
|
|
|
/*
|
|
** Joshua Teitelbaum 1/15/2006
|
|
** 1014 Army, Sergent First Class
|
|
** HTTP Post implementation employing HTTPGet as base class.
|
|
*/
|
|
/*
|
|
** _endstack
|
|
** when building the POST stack for a FORM, need a postamble
|
|
*/
|
|
void JNL_HTTPPost::_endstack()
|
|
{
|
|
std::string cd;
|
|
cd = PREFIX;
|
|
cd += m_boundary;
|
|
cd += PREFIX;
|
|
cd += NEWLINE;
|
|
|
|
FILEStackObject fso;
|
|
fso.m_otype = 2;
|
|
fso.m_str = cd;
|
|
m_filestack.push_back(fso);
|
|
|
|
}
|
|
/*
|
|
** prepares one field and puts it on the stack
|
|
*/
|
|
void JNL_HTTPPost::_preparefield(std::string &name)
|
|
{
|
|
std::string cd;
|
|
|
|
cd = PREFIX;
|
|
cd += m_boundary;
|
|
cd += NEWLINE;
|
|
cd += "content-disposition: form-data; name=\"";
|
|
cd += name;
|
|
cd += "\"";
|
|
cd += NEWLINE;
|
|
cd += NEWLINE;
|
|
cd += m_fields[name];
|
|
cd += "\r\n";
|
|
|
|
FILEStackObject fso;
|
|
|
|
fso.m_otype = 3;
|
|
fso.m_str = cd;
|
|
m_filestack.push_back(fso);
|
|
|
|
}
|
|
/*
|
|
** prepare all the fields, and push them on the stack
|
|
*/
|
|
void JNL_HTTPPost::_preparefieldstack()
|
|
{
|
|
std::map<std::string, std::string>::iterator it;
|
|
|
|
for(it = m_fields.begin(); it != m_fields.end(); it++)
|
|
{
|
|
std::string str = (*it).first;
|
|
_preparefield(str);
|
|
}
|
|
}
|
|
/*
|
|
** prepare files and put them on the stack
|
|
*/
|
|
void JNL_HTTPPost::_preparefilestack()
|
|
{
|
|
std::map<std::string, std::string>::iterator it;
|
|
|
|
for(it = m_paths.begin(); it != m_paths.end(); it++)
|
|
{
|
|
/*
|
|
--boundary\r\n
|
|
Content-Disposition: form-data; name="<fieldName>"; filename="<filename>"\r\n
|
|
Content-Type: <mime-type>\r\n
|
|
\r\n
|
|
<file-data>\r\n
|
|
*/
|
|
|
|
std::string cd ;
|
|
|
|
cd = PREFIX;
|
|
cd += m_boundary;
|
|
cd += NEWLINE;
|
|
cd += "content-disposition: form-data; name=\"";
|
|
cd += (*it).first;
|
|
cd += "\"; filename=\"";
|
|
cd += m_filenames[(*it).first];
|
|
cd += "\"";
|
|
cd += NEWLINE;
|
|
cd += "content-type: ";
|
|
cd += m_content_type[(*it).first];
|
|
cd += NEWLINE;
|
|
cd += NEWLINE;
|
|
|
|
|
|
FILEStackObject fso;
|
|
|
|
fso.m_otype = 0;
|
|
fso.m_str = cd;
|
|
m_filestack.push_back(fso);
|
|
|
|
fso.m_otype = 1;
|
|
fso.m_str = (*it).first;
|
|
m_filestack.push_back(fso);
|
|
|
|
cd = NEWLINE;
|
|
|
|
fso.m_otype = 2;
|
|
fso.m_str = cd;
|
|
m_filestack.push_back(fso);
|
|
}
|
|
|
|
}
|
|
/*
|
|
** payload function, run.
|
|
** the tactic is this:
|
|
** if we can't write, do normal run.
|
|
**
|
|
** while there is stuff on the POST stack
|
|
** pop and item
|
|
** write to the buffers as much as we can
|
|
** if we can't write more, stop
|
|
** end while
|
|
** do normal run
|
|
*/
|
|
int JNL_HTTPPost::run()
|
|
{
|
|
bool stop = 0;
|
|
std::map<std::string, std::string>::iterator it;
|
|
int ntowrite;
|
|
int retval;
|
|
do
|
|
{
|
|
if(m_con->send_bytes_available() <= 0)
|
|
{
|
|
/*
|
|
** rut roh, no buffa
|
|
*/
|
|
break;
|
|
}
|
|
|
|
if(m_filestack.size() <= 0)
|
|
{
|
|
/*
|
|
** Nothing to do
|
|
*/
|
|
break;
|
|
}
|
|
/*
|
|
** Get the current object off the stack
|
|
*/
|
|
switch(m_filestack.front().m_otype)
|
|
{
|
|
case 0: /*preamble*/
|
|
case 2: /*postamble*/
|
|
case 3: /*plain jane field*/
|
|
{
|
|
ntowrite = m_filestack.front().m_str.length() - m_filestack.front().nwritten;
|
|
|
|
if(m_con->send_bytes_available() < ntowrite)
|
|
{
|
|
ntowrite = m_con->send_bytes_available();
|
|
}
|
|
if(ntowrite>0)
|
|
{
|
|
retval = m_con->send(m_filestack.front().m_str.c_str() + m_filestack.front().nwritten,ntowrite);
|
|
|
|
if(retval < 0)
|
|
{
|
|
break;
|
|
}
|
|
|
|
m_filestack.front().nwritten += ntowrite;
|
|
m_nwritten += ntowrite;
|
|
|
|
if( m_filestack.front().nwritten == m_filestack.front().m_str.length())
|
|
{
|
|
/*
|
|
** all done with this object
|
|
*/
|
|
m_filestack.pop_front();
|
|
}
|
|
}
|
|
else
|
|
{
|
|
retval = 0;
|
|
stop = true;
|
|
}
|
|
}
|
|
break;
|
|
case 1: /*MEAT*/
|
|
{
|
|
FILE *fp;
|
|
int sresult;
|
|
fp = fopen(m_paths[m_filestack.front().m_str].c_str(),"rb");
|
|
|
|
if(fp == NULL)
|
|
{
|
|
/*
|
|
** someone gave this process a hot foot?
|
|
*/
|
|
return -1;
|
|
}
|
|
sresult = fseek(fp,m_filestack.front().nwritten,SEEK_SET);
|
|
|
|
if(sresult < 0)
|
|
{
|
|
/*
|
|
** someone gave this process a hot foot?
|
|
*/
|
|
fclose(fp);
|
|
return -1;
|
|
}
|
|
|
|
if(((m_content_length[m_filestack.front().m_str] - m_filestack.front().nwritten)) > (unsigned long)m_con->send_bytes_available())
|
|
{
|
|
ntowrite = m_con->send_bytes_available();
|
|
}
|
|
else
|
|
{
|
|
ntowrite = (m_content_length[m_filestack.front().m_str] - m_filestack.front().nwritten);
|
|
}
|
|
|
|
char *b=NULL;
|
|
|
|
b = (char *)malloc(ntowrite);
|
|
|
|
if(b == NULL)
|
|
{
|
|
return -1;
|
|
/*
|
|
** whiskey tango foxtrot
|
|
*/
|
|
}
|
|
/*
|
|
** read from where we left off
|
|
*/
|
|
sresult = fread(b,1,ntowrite,fp);
|
|
|
|
if(sresult != ntowrite)
|
|
{
|
|
/*
|
|
** hot foot with matches again
|
|
*/
|
|
if(b)
|
|
{
|
|
free(b);
|
|
}
|
|
fclose(fp);
|
|
return -1;
|
|
}
|
|
|
|
fclose(fp);
|
|
|
|
retval = m_con->send(b,ntowrite);
|
|
|
|
free(b);
|
|
|
|
if(retval < 0)
|
|
{
|
|
return retval;
|
|
}
|
|
|
|
m_filestack.front().nwritten += ntowrite;
|
|
|
|
m_nwritten += ntowrite;
|
|
|
|
if(m_filestack.front().nwritten == m_content_length[m_filestack.front().m_str])
|
|
{
|
|
m_filestack.pop_front();
|
|
}
|
|
}
|
|
break;
|
|
}
|
|
} while(!stop);
|
|
|
|
return JNL_HTTPGet::run();
|
|
}
|
|
/*
|
|
** addfield, adds field
|
|
*/
|
|
int JNL_HTTPPost::addfield(char *name, char *val)
|
|
{
|
|
if(name == NULL || val == NULL)
|
|
{
|
|
return -1;
|
|
}
|
|
m_fields[name]=val;
|
|
|
|
return 0;
|
|
}
|
|
/*
|
|
** addfile, adds file
|
|
*/
|
|
int JNL_HTTPPost::addfile(char *name, char *mimetype, char *filename, char *filepath)
|
|
{
|
|
struct stat buffer;
|
|
|
|
FILE *fp=NULL;
|
|
if(name==NULL || filepath == NULL || mimetype == NULL || filename == NULL || (!(fp=fopen(filepath,"rb"))))
|
|
{
|
|
return -1;
|
|
}
|
|
|
|
m_content_type[name] = mimetype;
|
|
m_paths[name] = filepath;
|
|
m_filenames[name] = filename;
|
|
|
|
fstat(fileno(fp),&buffer);
|
|
fclose(fp);
|
|
m_content_length[name] = buffer.st_size;
|
|
|
|
return 0;
|
|
}
|
|
/*
|
|
** After adding fields and files, get the content length
|
|
*/
|
|
int JNL_HTTPPost::contentlength()
|
|
{
|
|
std::map<std::string,std::string>::iterator it;
|
|
std::string tmp;
|
|
int length = 0;
|
|
// fields
|
|
{
|
|
for (it = m_fields.begin(); it != m_fields.end(); it++)
|
|
{
|
|
std::string name = (*it).first;
|
|
std::string value = (*it).second;
|
|
|
|
tmp = "--" + m_boundary + "\r\n"
|
|
"content-disposition: form-data; name=\"" + name + "\"\r\n"
|
|
"\r\n";
|
|
tmp += value + "\r\n";
|
|
|
|
length += tmp.size();
|
|
}
|
|
}
|
|
|
|
// files
|
|
{
|
|
for (it = m_filenames.begin(); it != m_filenames.end(); it++)
|
|
{
|
|
std::string name = (*it).first;
|
|
std::string filename = (*it).second;
|
|
long content_length = m_content_length[name];
|
|
std::string content_type = m_content_type[name];
|
|
tmp = "--" + m_boundary + "\r\n"
|
|
"content-disposition: form-data; name=\"" + name + "\"; filename=\"" + filename + "\"\r\n"
|
|
"content-type: " + content_type + "\r\n"
|
|
"\r\n";
|
|
length += tmp.size();
|
|
length += content_length;
|
|
length += 2; // crlf after file
|
|
}
|
|
}
|
|
|
|
// end
|
|
tmp = "--" + m_boundary + "--\r\n";
|
|
length += tmp.size();
|
|
|
|
return length;
|
|
|
|
}
|
|
void JNL_HTTPPost::_addformheader()
|
|
{
|
|
char *h;
|
|
#ifdef _WIN32
|
|
srand(GetTickCount());
|
|
#else
|
|
srand(time(NULL));
|
|
#endif
|
|
|
|
int x;
|
|
char *preamble = "content-type:multipart/form-data; boundary=";
|
|
char *dashes = "----";
|
|
|
|
char *post_boundary = (char*)alloca(10+strlen(dashes));
|
|
memcpy(post_boundary,dashes,strlen(dashes));
|
|
|
|
for(x=strlen(dashes); x < (int)strlen(dashes)+9; x++)
|
|
{
|
|
post_boundary[x] = (char)(rand() % 9) + '0';
|
|
}
|
|
post_boundary[x] = 0;
|
|
|
|
h = (char *)alloca(strlen(preamble) + strlen(post_boundary) + 1);
|
|
sprintf(h,"%s%s",preamble,post_boundary);
|
|
addheader(h);
|
|
m_boundary = post_boundary;
|
|
}
|