00001
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029
00030
00031
00032 #ifdef _WIN32
00033 #ifdef _MSC_VER
00034 #pragma warning(disable:4786)
00035 #pragma warning(disable:4503)
00036 #endif
00037 #else
00038 #include <errno.h>
00039 #include <ctype.h>
00040 #endif
00041 #include "ISocketHandler.h"
00042 #include <sys/types.h>
00043 #include <sys/stat.h>
00044 #include "Lock.h"
00045 #include "File.h"
00046
00047 #include "HttpPostSocket.h"
00048
00049
00050 #ifdef SOCKETS_NAMESPACE
00051 namespace SOCKETS_NAMESPACE {
00052 #endif
00053
00054
00055 int HttpPostSocket::m_boundary_count = 0;
00056 Mutex HttpPostSocket::m_boundary_mutex;
00057
00058
00059 HttpPostSocket::HttpPostSocket(ISocketHandler& h) : HttpClientSocket(h)
00060 ,m_bMultipart(false)
00061 {
00062 }
00063
00064
00065 HttpPostSocket::HttpPostSocket(ISocketHandler& h,const std::string& url_in) : HttpClientSocket(h, url_in)
00066 ,m_bMultipart(false)
00067 {
00068 Lock lock(m_boundary_mutex);
00069
00070 m_boundary = "----";
00071 for (int i = 0; i < 12; i++)
00072 {
00073 char c = m_boundary_count++ % 128;
00074 while (!isalnum(c))
00075 c = m_boundary_count++ % 128;
00076 m_boundary += c;
00077 }
00078 m_boundary += "__" + Utility::l2string(m_boundary_count++);
00079 }
00080
00081
00082 HttpPostSocket::~HttpPostSocket()
00083 {
00084 }
00085
00086
00087 void HttpPostSocket::AddField(const std::string& name,const std::string& value)
00088 {
00089 std::list<std::string> vec;
00090 vec.push_back(value);
00091 AddMultilineField(name, vec);
00092 }
00093
00094
00095 void HttpPostSocket::AddMultilineField(const std::string& name,std::list<std::string>& values)
00096 {
00097 m_fields[name] = values;
00098 }
00099
00100
00101 void HttpPostSocket::AddFile(const std::string& name,const std::string& filename,const std::string& type)
00102 {
00103 struct stat st;
00104 if (!stat(filename.c_str(), &st))
00105 {
00106 m_files[name] = filename;
00107 m_content_length[filename] = st.st_size;
00108 m_content_type[filename] = type;
00109 m_bMultipart = true;
00110 }
00111 else
00112 {
00113 Handler().LogError(this, "AddFile", Errno, StrError(Errno), LOG_LEVEL_FATAL);
00114 SetCloseAndDelete();
00115 }
00116 }
00117
00118
00119 void HttpPostSocket::Open()
00120 {
00121
00122 TcpSocket::Open(GetUrlHost(), GetUrlPort());
00123 }
00124
00125
00126 void HttpPostSocket::OnConnect()
00127 {
00128 if (m_bMultipart)
00129 {
00130 DoMultipartPost();
00131 }
00132 else
00133 {
00134 std::string body;
00135
00136
00137 for (std::map<std::string,std::list<std::string> >::iterator it = m_fields.begin(); it != m_fields.end(); ++it)
00138 {
00139 std::string name = (*it).first;
00140 std::list<std::string>& ref = (*it).second;
00141 if (body.size())
00142 {
00143 body += '&';
00144 }
00145 body += name + "=";
00146 bool first = true;
00147 for (std::list<std::string>::iterator it = ref.begin(); it != ref.end(); ++it)
00148 {
00149 std::string value = *it;
00150 if (!first)
00151 {
00152 body += "%0d%0a";
00153 }
00154 body += Utility::rfc1738_encode(value);
00155 first = false;
00156 }
00157 }
00158
00159
00160 SetMethod("POST");
00161 SetHttpVersion( "HTTP/1.1" );
00162 AddResponseHeader( "Host", GetUrlHost() );
00163 AddResponseHeader( "User-agent", MyUseragent());
00164 AddResponseHeader( "Accept", "text/html, text/plain, */*;q=0.01" );
00165 AddResponseHeader( "Connection", "close" );
00166 AddResponseHeader( "Content-type", "application/x-www-form-urlencoded" );
00167 AddResponseHeader( "Content-length", Utility::l2string((long)body.size()) );
00168 SendRequest();
00169
00170
00171 Send( body );
00172 }
00173 }
00174
00175
00176 void HttpPostSocket::DoMultipartPost()
00177 {
00178 long length = 0;
00179 std::string tmp;
00180
00181
00182 {
00183 for (std::map<std::string,std::list<std::string> >::iterator it = m_fields.begin(); it != m_fields.end(); ++it)
00184 {
00185 std::string name = (*it).first;
00186 std::list<std::string>& ref = (*it).second;
00187 tmp = "--" + m_boundary + "\r\n"
00188 "content-disposition: form-data; name=\"" + name + "\"\r\n"
00189 "\r\n";
00190 for (std::list<std::string>::iterator it = ref.begin(); it != ref.end(); ++it)
00191 {
00192 std::string value = *it;
00193 tmp += value + "\r\n";
00194 }
00195 length += (long)tmp.size();
00196 }
00197 }
00198
00199
00200 {
00201 for (std::map<std::string,std::string>::iterator it = m_files.begin(); it != m_files.end(); ++it)
00202 {
00203 std::string name = (*it).first;
00204 std::string filename = (*it).second;
00205 long content_length = m_content_length[filename];
00206 std::string content_type = m_content_type[filename];
00207 tmp = "--" + m_boundary + "\r\n"
00208 "content-disposition: form-data; name=\"" + name + "\"; filename=\"" + filename + "\"\r\n"
00209 "content-type: " + content_type + "\r\n"
00210 "\r\n";
00211 length += (long)tmp.size();
00212 length += content_length;
00213 length += 2;
00214 }
00215 }
00216
00217
00218 tmp = "--" + m_boundary + "--\r\n";
00219 length += (long)tmp.size();
00220
00221
00222 SetMethod("POST");
00223 SetHttpVersion( "HTTP/1.1" );
00224 AddResponseHeader( "Host", GetUrlHost() );
00225 AddResponseHeader( "User-agent", MyUseragent());
00226 AddResponseHeader( "Accept", "text/html, text/plain, */*;q=0.01" );
00227 AddResponseHeader( "Connection", "close" );
00228 AddResponseHeader( "Content-type", "multipart/form-data; boundary=" + m_boundary );
00229 AddResponseHeader( "Content-length", Utility::l2string(length) );
00230
00231 SendRequest();
00232
00233
00234 {
00235 for (std::map<std::string,std::list<std::string> >::iterator it = m_fields.begin(); it != m_fields.end(); ++it)
00236 {
00237 std::string name = (*it).first;
00238 std::list<std::string>& ref = (*it).second;
00239 tmp = "--" + m_boundary + "\r\n"
00240 "content-disposition: form-data; name=\"" + name + "\"\r\n"
00241 "\r\n";
00242 for (std::list<std::string>::iterator it = ref.begin(); it != ref.end(); ++it)
00243 {
00244 std::string value = *it;
00245 tmp += value + "\r\n";
00246 }
00247 Send( tmp );
00248 }
00249 }
00250
00251
00252 {
00253 for (std::map<std::string,std::string>::iterator it = m_files.begin(); it != m_files.end(); ++it)
00254 {
00255 std::string name = (*it).first;
00256 std::string filename = (*it).second;
00257 std::string content_type = m_content_type[filename];
00258 tmp = "--" + m_boundary + "\r\n"
00259 "content-disposition: form-data; name=\"" + name + "\"; filename=\"" + filename + "\"\r\n"
00260 "content-type: " + content_type + "\r\n"
00261 "\r\n";
00262 Send( tmp );
00263 {
00264 std::auto_ptr<IFile> fil = std::auto_ptr<IFile>(new File);
00265 if (fil -> fopen(filename, "rb"))
00266 {
00267 char slask[2000];
00268 size_t n;
00269 while ((n = fil -> fread(slask, 1, 2000)) > 0)
00270 {
00271 SendBuf(slask, n);
00272 }
00273 fil -> fclose();
00274 }
00275 }
00276 Send("\r\n");
00277 }
00278 }
00279
00280
00281 Send("--" + m_boundary + "--\r\n");
00282 }
00283
00284
00285 void HttpPostSocket::SetMultipart()
00286 {
00287 m_bMultipart = true;
00288 }
00289
00290
00291 #ifdef SOCKETS_NAMESPACE
00292 }
00293 #endif
00294
00295