Logo
~Sockets~
~Examples~
~Contact~


HttpPostSocket.cpp

Go to the documentation of this file.
00001 
00005 /*
00006 Copyright (C) 2004-2007  Anders Hedstrom
00007 
00008 This library is made available under the terms of the GNU GPL.
00009 
00010 If you would like to use this library in a closed-source application,
00011 a separate license agreement is available. For information about 
00012 the closed-source license agreement for the C++ sockets library,
00013 please visit http://www.alhem.net/Sockets/license.html and/or
00014 email license@alhem.net.
00015 
00016 This program is free software; you can redistribute it and/or
00017 modify it under the terms of the GNU General Public License
00018 as published by the Free Software Foundation; either version 2
00019 of the License, or (at your option) any later version.
00020 
00021 This program is distributed in the hope that it will be useful,
00022 but WITHOUT ANY WARRANTY; without even the implied warranty of
00023 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00024 GNU General Public License for more details.
00025 
00026 You should have received a copy of the GNU General Public License
00027 along with this program; if not, write to the Free Software
00028 Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
00029 */
00030 #ifdef _WIN32
00031 #pragma warning(disable:4786)
00032 #pragma warning(disable:4503)
00033 #else
00034 #include <errno.h>
00035 #include <ctype.h>
00036 #endif
00037 #include "ISocketHandler.h"
00038 #include <sys/types.h>
00039 #include <sys/stat.h>
00040 #include "Parse.h"
00041 #include "Utility.h"
00042 #include "Lock.h"
00043 
00044 #include "HttpPostSocket.h"
00045 
00046 
00047 #ifdef SOCKETS_NAMESPACE
00048 namespace SOCKETS_NAMESPACE {
00049 #endif
00050 
00051 
00052 int HttpPostSocket::m_boundary_count = 0;
00053 Mutex HttpPostSocket::m_boundary_mutex;
00054 
00055 
00056 HttpPostSocket::HttpPostSocket(ISocketHandler& h) : HttpClientSocket(h)
00057 ,m_bMultipart(false)
00058 {
00059 }
00060 
00061 
00062 HttpPostSocket::HttpPostSocket(ISocketHandler& h,const std::string& url_in) : HttpClientSocket(h, url_in)
00063 ,m_bMultipart(false)
00064 {
00065         Lock lock(m_boundary_mutex);
00066 
00067         m_boundary = "----";
00068         for (int i = 0; i < 12; i++)
00069         {
00070                 char c = m_boundary_count++ % 128;
00071                 while (!isalnum(c))
00072                         c = m_boundary_count++ % 128;
00073                 m_boundary += c;
00074         }
00075         m_boundary += "__" + Utility::l2string(m_boundary_count++);
00076 }
00077 
00078 
00079 HttpPostSocket::~HttpPostSocket()
00080 {
00081 }
00082 
00083 
00084 void HttpPostSocket::AddField(const std::string& name,const std::string& value)
00085 {
00086         std::list<std::string> vec;
00087         vec.push_back(value);
00088         AddMultilineField(name, vec);
00089 }
00090 
00091 
00092 void HttpPostSocket::AddMultilineField(const std::string& name,std::list<std::string>& values)
00093 {
00094         m_fields[name] = values;
00095 }
00096 
00097 
00098 void HttpPostSocket::AddFile(const std::string& name,const std::string& filename,const std::string& type)
00099 {
00100         struct stat st;
00101         if (!stat(filename.c_str(), &st))
00102         {
00103                 m_files[name] = filename;
00104                 m_content_length[filename] = st.st_size;
00105                 m_content_type[filename] = type;
00106                 m_bMultipart = true;
00107         }
00108         else
00109         {
00110                 Handler().LogError(this, "AddFile", Errno, StrError(Errno), LOG_LEVEL_FATAL);
00111                 SetCloseAndDelete();
00112         }
00113 }
00114 
00115 
00116 void HttpPostSocket::Open()
00117 {
00118         // why do I have to specify TcpSocket:: to get to the Open() method??
00119         TcpSocket::Open(GetUrlHost(), GetUrlPort());
00120 }
00121 
00122 
00123 void HttpPostSocket::OnConnect()
00124 {
00125         if (m_bMultipart)
00126         {
00127                 DoMultipartPost();
00128         }
00129         else
00130         {
00131                 std::string body;
00132 
00133                 // only fields, no files, add urlencoding
00134                 for (std::map<std::string,std::list<std::string> >::iterator it = m_fields.begin(); it != m_fields.end(); it++)
00135                 {
00136                         std::string name = (*it).first;
00137                         std::list<std::string>& ref = (*it).second;
00138                         if (body.size())
00139                         {
00140                                 body += '&';
00141                         }
00142                         body += name + "=";
00143                         bool first = true;
00144                         for (std::list<std::string>::iterator it = ref.begin(); it != ref.end(); it++)
00145                         {
00146                                 std::string value = *it;
00147                                 if (!first)
00148                                 {
00149                                         body += "%0d%0a"; // CRLF
00150                                 }
00151                                 body += Utility::rfc1738_encode(value);
00152                                 first = false;
00153                         }
00154                 }
00155 
00156                 // build header, send body
00157                 SetMethod("POST");
00158                 SetHttpVersion( "HTTP/1.1" );
00159                 AddResponseHeader( "Host", GetUrlHost() ); // oops - this is actually a request header that we're adding..
00160                 AddResponseHeader( "User-agent", MyUseragent());
00161                 AddResponseHeader( "Accept", "text/html, text/plain, */*;q=0.01" );
00162                 AddResponseHeader( "Connection", "close" );
00163                 AddResponseHeader( "Content-type", "application/x-www-form-urlencoded" );
00164                 AddResponseHeader( "Content-length", Utility::l2string((long)body.size()) );
00165                 SendRequest();
00166 
00167                 // send body
00168                 Send( body );
00169         }
00170 }
00171 
00172 
00173 void HttpPostSocket::DoMultipartPost()
00174 {
00175         long length = 0; // calculate content_length of our post body
00176         std::string tmp;
00177 
00178         // fields
00179         {
00180                 for (std::map<std::string,std::list<std::string> >::iterator it = m_fields.begin(); it != m_fields.end(); it++)
00181                 {
00182                         std::string name = (*it).first;
00183                         std::list<std::string>& ref = (*it).second;
00184                         tmp = "--" + m_boundary + "\r\n"
00185                                 "content-disposition: form-data; name=\"" + name + "\"\r\n"
00186                                 "\r\n";
00187                         for (std::list<std::string>::iterator it = ref.begin(); it != ref.end(); it++)
00188                         {
00189                                 std::string value = *it;
00190                                 tmp += value + "\r\n";
00191                         }
00192                         length += (long)tmp.size();
00193                 }
00194         }
00195 
00196         // files
00197         {
00198                 for (std::map<std::string,std::string>::iterator it = m_files.begin(); it != m_files.end(); it++)
00199                 {
00200                         std::string name = (*it).first;
00201                         std::string filename = (*it).second;
00202                         long content_length = m_content_length[filename];
00203                         std::string content_type = m_content_type[filename];
00204                         tmp = "--" + m_boundary + "\r\n"
00205                                 "content-disposition: form-data; name=\"" + name + "\"; filename=\"" + filename + "\"\r\n"
00206                                 "content-type: " + content_type + "\r\n"
00207                                 "\r\n";
00208                         length += (long)tmp.size();
00209                         length += content_length;
00210                         length += 2; // crlf after file
00211                 }
00212         }
00213 
00214         // end
00215         tmp = "--" + m_boundary + "--\r\n";
00216         length += (long)tmp.size();
00217 
00218         // build header, send body
00219         SetMethod("POST");
00220         SetHttpVersion( "HTTP/1.1" );
00221         AddResponseHeader( "Host", GetUrlHost() ); // oops - this is actually a request header that we're adding..
00222         AddResponseHeader( "User-agent", MyUseragent());
00223         AddResponseHeader( "Accept", "text/html, text/plain, */*;q=0.01" );
00224         AddResponseHeader( "Connection", "close" );
00225         AddResponseHeader( "Content-type", "multipart/form-data; boundary=" + m_boundary );
00226         AddResponseHeader( "Content-length", Utility::l2string(length) );
00227 
00228         SendRequest();
00229 
00230         // send fields
00231         {
00232                 for (std::map<std::string,std::list<std::string> >::iterator it = m_fields.begin(); it != m_fields.end(); it++)
00233                 {
00234                         std::string name = (*it).first;
00235                         std::list<std::string>& ref = (*it).second;
00236                         tmp = "--" + m_boundary + "\r\n"
00237                                 "content-disposition: form-data; name=\"" + name + "\"\r\n"
00238                                 "\r\n";
00239                         for (std::list<std::string>::iterator it = ref.begin(); it != ref.end(); it++)
00240                         {
00241                                 std::string value = *it;
00242                                 tmp += value + "\r\n";
00243                         }
00244                         Send( tmp );
00245                 }
00246         }
00247 
00248         // send files
00249         {
00250                 for (std::map<std::string,std::string>::iterator it = m_files.begin(); it != m_files.end(); it++)
00251                 {
00252                         std::string name = (*it).first;
00253                         std::string filename = (*it).second;
00254                         std::string content_type = m_content_type[filename];
00255                         tmp = "--" + m_boundary + "\r\n"
00256                                 "content-disposition: form-data; name=\"" + name + "\"; filename=\"" + filename + "\"\r\n"
00257                                 "content-type: " + content_type + "\r\n"
00258                                 "\r\n";
00259                         Send( tmp );
00260                         {
00261                                 FILE *fil = fopen(filename.c_str(),"rb");
00262                                 if (fil)
00263                                 {
00264                                         char slask[2000]; // for fread
00265                                         size_t n;
00266                                         while ((n = fread(slask, 1, 2000, fil)) > 0)
00267                                         {
00268                                                 SendBuf(slask, n);
00269                                         }
00270                                         fclose(fil);
00271                                 }
00272                         }
00273                         Send("\r\n");
00274                 }
00275         }
00276 
00277         // end of send
00278         Send("--" + m_boundary + "--\r\n");
00279 }
00280 
00281 
00282 void HttpPostSocket::SetMultipart()
00283 {
00284         m_bMultipart = true;
00285 }
00286 
00287 
00288 #ifdef SOCKETS_NAMESPACE
00289 }
00290 #endif
00291 
Page, code, and content Copyright (C) 2007 by Anders Hedström
Generated for C++ Sockets by  doxygen 1.4.4