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 
00043 #include "HttpPostSocket.h"
00044 
00045 
00046 #ifdef SOCKETS_NAMESPACE
00047 namespace SOCKETS_NAMESPACE {
00048 #endif
00049 
00050 
00051 HttpPostSocket::HttpPostSocket(ISocketHandler& h) : HttpClientSocket(h)
00052 ,m_bMultipart(false)
00053 {
00054 }
00055 
00056 
00057 HttpPostSocket::HttpPostSocket(ISocketHandler& h,const std::string& url_in) : HttpClientSocket(h, url_in)
00058 ,m_bMultipart(false)
00059 {
00060         m_boundary = "----";
00061         for (int i = 0; i < 12; i++)
00062         {
00063                 char c = 0;
00064                 while (!isalnum(c))
00065                 {
00066                         c = (char)(Random() % 96 + 32);
00067                 }
00068                 m_boundary += c;
00069         }
00070 }
00071 
00072 
00073 HttpPostSocket::~HttpPostSocket()
00074 {
00075 }
00076 
00077 
00078 void HttpPostSocket::AddField(const std::string& name,const std::string& value)
00079 {
00080         std::list<std::string> vec;
00081         vec.push_back(value);
00082         AddMultilineField(name, vec);
00083 }
00084 
00085 
00086 void HttpPostSocket::AddMultilineField(const std::string& name,std::list<std::string>& values)
00087 {
00088         m_fields[name] = values;
00089 }
00090 
00091 
00092 void HttpPostSocket::AddFile(const std::string& name,const std::string& filename,const std::string& type)
00093 {
00094         struct stat st;
00095         if (!stat(filename.c_str(), &st))
00096         {
00097                 m_files[name] = filename;
00098                 m_content_length[filename] = st.st_size;
00099                 m_content_type[filename] = type;
00100                 m_bMultipart = true;
00101         }
00102         else
00103         {
00104                 Handler().LogError(this, "AddFile", Errno, StrError(Errno), LOG_LEVEL_FATAL);
00105                 SetCloseAndDelete();
00106         }
00107 }
00108 
00109 
00110 void HttpPostSocket::Open()
00111 {
00112         // why do I have to specify TcpSocket:: to get to the Open() method??
00113         TcpSocket::Open(GetUrlHost(), GetUrlPort());
00114 }
00115 
00116 
00117 void HttpPostSocket::OnConnect()
00118 {
00119         if (m_bMultipart)
00120         {
00121                 DoMultipartPost();
00122         }
00123         else
00124         {
00125                 std::string body;
00126 
00127                 // only fields, no files, add urlencoding
00128                 for (std::map<std::string,std::list<std::string> >::iterator it = m_fields.begin(); it != m_fields.end(); it++)
00129                 {
00130                         std::string name = (*it).first;
00131                         std::list<std::string>& ref = (*it).second;
00132                         if (body.size())
00133                         {
00134                                 body += '&';
00135                         }
00136                         body += name + "=";
00137                         bool first = true;
00138                         for (std::list<std::string>::iterator it = ref.begin(); it != ref.end(); it++)
00139                         {
00140                                 std::string value = *it;
00141                                 if (!first)
00142                                 {
00143                                         body += "%0d%0a"; // CRLF
00144                                 }
00145                                 body += Utility::rfc1738_encode(value);
00146                                 first = false;
00147                         }
00148                 }
00149 
00150                 // build header, send body
00151                 SetMethod("POST");
00152                 SetHttpVersion( "HTTP/1.1" );
00153                 AddResponseHeader( "Host", GetUrlHost() ); // oops - this is actually a request header that we're adding..
00154                 AddResponseHeader( "User-agent", MyUseragent());
00155                 AddResponseHeader( "Accept", "text/html, text/plain, */*;q=0.01" );
00156                 AddResponseHeader( "Connection", "close" );
00157                 AddResponseHeader( "Content-type", "application/x-www-form-urlencoded" );
00158                 AddResponseHeader( "Content-length", Utility::l2string((long)body.size()) );
00159                 SendRequest();
00160 
00161                 // send body
00162                 Send( body );
00163         }
00164 }
00165 
00166 
00167 void HttpPostSocket::DoMultipartPost()
00168 {
00169         long length = 0; // calculate content_length of our post body
00170         std::string tmp;
00171 
00172         // fields
00173         {
00174                 for (std::map<std::string,std::list<std::string> >::iterator it = m_fields.begin(); it != m_fields.end(); it++)
00175                 {
00176                         std::string name = (*it).first;
00177                         std::list<std::string>& ref = (*it).second;
00178                         tmp = "--" + m_boundary + "\r\n"
00179                                 "content-disposition: form-data; name=\"" + name + "\"\r\n"
00180                                 "\r\n";
00181                         for (std::list<std::string>::iterator it = ref.begin(); it != ref.end(); it++)
00182                         {
00183                                 std::string value = *it;
00184                                 tmp += value + "\r\n";
00185                         }
00186                         length += (long)tmp.size();
00187                 }
00188         }
00189 
00190         // files
00191         {
00192                 for (std::map<std::string,std::string>::iterator it = m_files.begin(); it != m_files.end(); it++)
00193                 {
00194                         std::string name = (*it).first;
00195                         std::string filename = (*it).second;
00196                         long content_length = m_content_length[filename];
00197                         std::string content_type = m_content_type[filename];
00198                         tmp = "--" + m_boundary + "\r\n"
00199                                 "content-disposition: form-data; name=\"" + name + "\"; filename=\"" + filename + "\"\r\n"
00200                                 "content-type: " + content_type + "\r\n"
00201                                 "\r\n";
00202                         length += (long)tmp.size();
00203                         length += content_length;
00204                         length += 2; // crlf after file
00205                 }
00206         }
00207 
00208         // end
00209         tmp = "--" + m_boundary + "--\r\n";
00210         length += (long)tmp.size();
00211 
00212         // build header, send body
00213         SetMethod("POST");
00214         SetHttpVersion( "HTTP/1.1" );
00215         AddResponseHeader( "Host", GetUrlHost() ); // oops - this is actually a request header that we're adding..
00216         AddResponseHeader( "User-agent", MyUseragent());
00217         AddResponseHeader( "Accept", "text/html, text/plain, */*;q=0.01" );
00218         AddResponseHeader( "Connection", "close" );
00219         AddResponseHeader( "Content-type", "multipart/form-data; boundary=" + m_boundary );
00220         AddResponseHeader( "Content-length", Utility::l2string(length) );
00221 
00222         SendRequest();
00223 
00224         // send fields
00225         {
00226                 for (std::map<std::string,std::list<std::string> >::iterator it = m_fields.begin(); it != m_fields.end(); it++)
00227                 {
00228                         std::string name = (*it).first;
00229                         std::list<std::string>& ref = (*it).second;
00230                         tmp = "--" + m_boundary + "\r\n"
00231                                 "content-disposition: form-data; name=\"" + name + "\"\r\n"
00232                                 "\r\n";
00233                         for (std::list<std::string>::iterator it = ref.begin(); it != ref.end(); it++)
00234                         {
00235                                 std::string value = *it;
00236                                 tmp += value + "\r\n";
00237                         }
00238                         Send( tmp );
00239                 }
00240         }
00241 
00242         // send files
00243         {
00244                 for (std::map<std::string,std::string>::iterator it = m_files.begin(); it != m_files.end(); it++)
00245                 {
00246                         std::string name = (*it).first;
00247                         std::string filename = (*it).second;
00248                         std::string content_type = m_content_type[filename];
00249                         tmp = "--" + m_boundary + "\r\n"
00250                                 "content-disposition: form-data; name=\"" + name + "\"; filename=\"" + filename + "\"\r\n"
00251                                 "content-type: " + content_type + "\r\n"
00252                                 "\r\n";
00253                         Send( tmp );
00254                         {
00255                                 FILE *fil = fopen(filename.c_str(),"rb");
00256                                 if (fil)
00257                                 {
00258                                         char slask[2000]; // for fread
00259                                         size_t n;
00260                                         while ((n = fread(slask, 1, 2000, fil)) > 0)
00261                                         {
00262                                                 SendBuf(slask, n);
00263                                         }
00264                                         fclose(fil);
00265                                 }
00266                         }
00267                         Send("\r\n");
00268                 }
00269         }
00270 
00271         // end of send
00272         Send("--" + m_boundary + "--\r\n");
00273 }
00274 
00275 
00276 void HttpPostSocket::SetMultipart()
00277 {
00278         m_bMultipart = true;
00279 }
00280 
00281 
00282 #ifdef SOCKETS_NAMESPACE
00283 }
00284 #endif
00285 
Page, code, and content Copyright (C) 2007 by Anders Hedström
Generated for C++ Sockets by  doxygen 1.4.4