big svn cleanup
[anytun.git] / src / Sockets / HttpPostSocket.cpp
bloba72b8cfdc2697b735704af009d7fb8c7cb23461c
1 /** \file HttpPostSocket.cpp
2 ** \date 2004-10-30
3 ** \author grymse@alhem.net
4 **/
5 /*
6 Copyright (C) 2004-2007 Anders Hedstrom
8 This library is made available under the terms of the GNU GPL.
10 If you would like to use this library in a closed-source application,
11 a separate license agreement is available. For information about
12 the closed-source license agreement for the C++ sockets library,
13 please visit http://www.alhem.net/Sockets/license.html and/or
14 email license@alhem.net.
16 This program is free software; you can redistribute it and/or
17 modify it under the terms of the GNU General Public License
18 as published by the Free Software Foundation; either version 2
19 of the License, or (at your option) any later version.
21 This program is distributed in the hope that it will be useful,
22 but WITHOUT ANY WARRANTY; without even the implied warranty of
23 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
24 GNU General Public License for more details.
26 You should have received a copy of the GNU General Public License
27 along with this program; if not, write to the Free Software
28 Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
30 #ifdef _WIN32
31 #ifdef _MSC_VER
32 #pragma warning(disable:4786)
33 #pragma warning(disable:4503)
34 #endif
35 #else
36 #include <errno.h>
37 #include <ctype.h>
38 #endif
39 #include "ISocketHandler.h"
40 #include <sys/types.h>
41 #include <sys/stat.h>
42 #include "Parse.h"
43 #include "Utility.h"
44 #include "Lock.h"
46 #include "HttpPostSocket.h"
49 #ifdef SOCKETS_NAMESPACE
50 namespace SOCKETS_NAMESPACE {
51 #endif
54 int HttpPostSocket::m_boundary_count = 0;
55 Mutex HttpPostSocket::m_boundary_mutex;
58 HttpPostSocket::HttpPostSocket(ISocketHandler& h) : HttpClientSocket(h)
59 ,m_bMultipart(false)
64 HttpPostSocket::HttpPostSocket(ISocketHandler& h,const std::string& url_in) : HttpClientSocket(h, url_in)
65 ,m_bMultipart(false)
67 Lock lock(m_boundary_mutex);
69 m_boundary = "----";
70 for (int i = 0; i < 12; i++)
72 char c = m_boundary_count++ % 128;
73 while (!isalnum(c))
74 c = m_boundary_count++ % 128;
75 m_boundary += c;
77 m_boundary += "__" + Utility::l2string(m_boundary_count++);
81 HttpPostSocket::~HttpPostSocket()
86 void HttpPostSocket::AddField(const std::string& name,const std::string& value)
88 std::list<std::string> vec;
89 vec.push_back(value);
90 AddMultilineField(name, vec);
94 void HttpPostSocket::AddMultilineField(const std::string& name,std::list<std::string>& values)
96 m_fields[name] = values;
100 void HttpPostSocket::AddFile(const std::string& name,const std::string& filename,const std::string& type)
102 struct stat st;
103 if (!stat(filename.c_str(), &st))
105 m_files[name] = filename;
106 m_content_length[filename] = st.st_size;
107 m_content_type[filename] = type;
108 m_bMultipart = true;
110 else
112 Handler().LogError(this, "AddFile", Errno, StrError(Errno), LOG_LEVEL_FATAL);
113 SetCloseAndDelete();
118 void HttpPostSocket::Open()
120 // why do I have to specify TcpSocket:: to get to the Open() method??
121 TcpSocket::Open(GetUrlHost(), GetUrlPort());
125 void HttpPostSocket::OnConnect()
127 if (m_bMultipart)
129 DoMultipartPost();
131 else
133 std::string body;
135 // only fields, no files, add urlencoding
136 for (std::map<std::string,std::list<std::string> >::iterator it = m_fields.begin(); it != m_fields.end(); it++)
138 std::string name = (*it).first;
139 std::list<std::string>& ref = (*it).second;
140 if (body.size())
142 body += '&';
144 body += name + "=";
145 bool first = true;
146 for (std::list<std::string>::iterator it = ref.begin(); it != ref.end(); it++)
148 std::string value = *it;
149 if (!first)
151 body += "%0d%0a"; // CRLF
153 body += Utility::rfc1738_encode(value);
154 first = false;
158 // build header, send body
159 SetMethod("POST");
160 SetHttpVersion( "HTTP/1.1" );
161 AddResponseHeader( "Host", GetUrlHost() ); // oops - this is actually a request header that we're adding..
162 AddResponseHeader( "User-agent", MyUseragent());
163 AddResponseHeader( "Accept", "text/html, text/plain, */*;q=0.01" );
164 AddResponseHeader( "Connection", "close" );
165 AddResponseHeader( "Content-type", "application/x-www-form-urlencoded" );
166 AddResponseHeader( "Content-length", Utility::l2string((long)body.size()) );
167 SendRequest();
169 // send body
170 Send( body );
175 void HttpPostSocket::DoMultipartPost()
177 long length = 0; // calculate content_length of our post body
178 std::string tmp;
180 // fields
182 for (std::map<std::string,std::list<std::string> >::iterator it = m_fields.begin(); it != m_fields.end(); it++)
184 std::string name = (*it).first;
185 std::list<std::string>& ref = (*it).second;
186 tmp = "--" + m_boundary + "\r\n"
187 "content-disposition: form-data; name=\"" + name + "\"\r\n"
188 "\r\n";
189 for (std::list<std::string>::iterator it = ref.begin(); it != ref.end(); it++)
191 std::string value = *it;
192 tmp += value + "\r\n";
194 length += (long)tmp.size();
198 // files
200 for (std::map<std::string,std::string>::iterator it = m_files.begin(); it != m_files.end(); it++)
202 std::string name = (*it).first;
203 std::string filename = (*it).second;
204 long content_length = m_content_length[filename];
205 std::string content_type = m_content_type[filename];
206 tmp = "--" + m_boundary + "\r\n"
207 "content-disposition: form-data; name=\"" + name + "\"; filename=\"" + filename + "\"\r\n"
208 "content-type: " + content_type + "\r\n"
209 "\r\n";
210 length += (long)tmp.size();
211 length += content_length;
212 length += 2; // crlf after file
216 // end
217 tmp = "--" + m_boundary + "--\r\n";
218 length += (long)tmp.size();
220 // build header, send body
221 SetMethod("POST");
222 SetHttpVersion( "HTTP/1.1" );
223 AddResponseHeader( "Host", GetUrlHost() ); // oops - this is actually a request header that we're adding..
224 AddResponseHeader( "User-agent", MyUseragent());
225 AddResponseHeader( "Accept", "text/html, text/plain, */*;q=0.01" );
226 AddResponseHeader( "Connection", "close" );
227 AddResponseHeader( "Content-type", "multipart/form-data; boundary=" + m_boundary );
228 AddResponseHeader( "Content-length", Utility::l2string(length) );
230 SendRequest();
232 // send fields
234 for (std::map<std::string,std::list<std::string> >::iterator it = m_fields.begin(); it != m_fields.end(); it++)
236 std::string name = (*it).first;
237 std::list<std::string>& ref = (*it).second;
238 tmp = "--" + m_boundary + "\r\n"
239 "content-disposition: form-data; name=\"" + name + "\"\r\n"
240 "\r\n";
241 for (std::list<std::string>::iterator it = ref.begin(); it != ref.end(); it++)
243 std::string value = *it;
244 tmp += value + "\r\n";
246 Send( tmp );
250 // send files
252 for (std::map<std::string,std::string>::iterator it = m_files.begin(); it != m_files.end(); it++)
254 std::string name = (*it).first;
255 std::string filename = (*it).second;
256 std::string content_type = m_content_type[filename];
257 tmp = "--" + m_boundary + "\r\n"
258 "content-disposition: form-data; name=\"" + name + "\"; filename=\"" + filename + "\"\r\n"
259 "content-type: " + content_type + "\r\n"
260 "\r\n";
261 Send( tmp );
263 FILE *fil = fopen(filename.c_str(),"rb");
264 if (fil)
266 char slask[2000]; // for fread
267 size_t n;
268 while ((n = fread(slask, 1, 2000, fil)) > 0)
270 SendBuf(slask, n);
272 fclose(fil);
275 Send("\r\n");
279 // end of send
280 Send("--" + m_boundary + "--\r\n");
284 void HttpPostSocket::SetMultipart()
286 m_bMultipart = true;
290 #ifdef SOCKETS_NAMESPACE
292 #endif