![]() |
HttpPostSocket Class ReferenceGenerate a http post request, get response.
More...
|
Public Member Functions | |
HttpPostSocket (ISocketHandler &) | |
HttpPostSocket (ISocketHandler &, const std::string &url_in) | |
~HttpPostSocket () | |
void | AddField (const std::string &name, const std::string &value) |
Add field to post. | |
void | AddMultilineField (const std::string &name, std::list< std::string > &values) |
Add multiline field to post. | |
void | AddFile (const std::string &name, const std::string &filename, const std::string &type) |
Add file to post. | |
void | SetMultipart () |
use this to post with content-type multipart/form-data. | |
void | Open () |
connect to host:port derived from url in constructor | |
void | OnConnect () |
http put client implemented in OnConnect | |
Protected Attributes | |
std::map< std::string, std::list< std::string > > | m_fields |
Private Member Functions | |
HttpPostSocket (const HttpPostSocket &s) | |
HttpPostSocket & | operator= (const HttpPostSocket &) |
void | DoMultipartPost () |
Private Attributes | |
std::map< std::string, std::string > | m_files |
std::string | m_boundary |
std::map< std::string, long > | m_content_length |
Content-length header received from remote. | |
std::map< std::string, std::string > | m_content_type |
Content-type: header from response. | |
bool | m_bMultipart |
Static Private Attributes | |
static int | m_boundary_count = 0 |
static Mutex | m_boundary_mutex |
Definition at line 48 of file HttpPostSocket.h.
HttpPostSocket::HttpPostSocket | ( | ISocketHandler & | h | ) |
Definition at line 59 of file HttpPostSocket.cpp.
00059 : HttpClientSocket(h) 00060 ,m_bMultipart(false) 00061 { 00062 }
HttpPostSocket::HttpPostSocket | ( | ISocketHandler & | h, | |
const std::string & | url_in | |||
) |
Definition at line 65 of file HttpPostSocket.cpp.
References Utility::l2string(), m_boundary, m_boundary_count, and m_boundary_mutex.
00065 : 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 }
HttpPostSocket::~HttpPostSocket | ( | ) |
HttpPostSocket::HttpPostSocket | ( | const HttpPostSocket & | s | ) | [inline, private] |
void HttpPostSocket::AddField | ( | const std::string & | name, | |
const std::string & | value | |||
) |
Add field to post.
Definition at line 87 of file HttpPostSocket.cpp.
References AddMultilineField().
00088 { 00089 std::list<std::string> vec; 00090 vec.push_back(value); 00091 AddMultilineField(name, vec); 00092 }
void HttpPostSocket::AddMultilineField | ( | const std::string & | name, | |
std::list< std::string > & | values | |||
) |
Add multiline field to post.
Definition at line 95 of file HttpPostSocket.cpp.
References m_fields.
Referenced by AddField().
00096 { 00097 m_fields[name] = values; 00098 }
void HttpPostSocket::AddFile | ( | const std::string & | name, | |
const std::string & | filename, | |||
const std::string & | type | |||
) |
Add file to post.
Definition at line 101 of file HttpPostSocket.cpp.
References Errno, Socket::Handler(), LOG_LEVEL_FATAL, ISocketHandler::LogError(), m_bMultipart, m_content_length, m_content_type, m_files, Socket::SetCloseAndDelete(), and StrError.
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 }
void HttpPostSocket::SetMultipart | ( | ) |
use this to post with content-type multipart/form-data.
when adding a file to the post, this is the default and only content-type
Definition at line 285 of file HttpPostSocket.cpp.
References m_bMultipart.
00286 { 00287 m_bMultipart = true; 00288 }
void HttpPostSocket::Open | ( | ) |
connect to host:port derived from url in constructor
Definition at line 119 of file HttpPostSocket.cpp.
References HttpClientSocket::GetUrlHost(), HttpClientSocket::GetUrlPort(), and TcpSocket::Open().
00120 { 00121 // why do I have to specify TcpSocket:: to get to the Open() method?? 00122 TcpSocket::Open(GetUrlHost(), GetUrlPort()); 00123 }
void HttpPostSocket::OnConnect | ( | ) | [virtual] |
http put client implemented in OnConnect
Reimplemented from Socket.
Definition at line 126 of file HttpPostSocket.cpp.
References HTTPSocket::AddResponseHeader(), DoMultipartPost(), HttpClientSocket::GetUrlHost(), Utility::l2string(), m_bMultipart, m_fields, HTTPSocket::MyUseragent(), Utility::rfc1738_encode(), TcpSocket::Send(), HTTPSocket::SendRequest(), HTTPSocket::SetHttpVersion(), and HTTPSocket::SetMethod().
00127 { 00128 if (m_bMultipart) 00129 { 00130 DoMultipartPost(); 00131 } 00132 else 00133 { 00134 std::string body; 00135 00136 // only fields, no files, add urlencoding 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"; // CRLF 00153 } 00154 body += Utility::rfc1738_encode(value); 00155 first = false; 00156 } 00157 } 00158 00159 // build header, send body 00160 SetMethod("POST"); 00161 SetHttpVersion( "HTTP/1.1" ); 00162 AddResponseHeader( "Host", GetUrlHost() ); // oops - this is actually a request header that we're adding.. 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 // send body 00171 Send( body ); 00172 } 00173 }
HttpPostSocket& HttpPostSocket::operator= | ( | const HttpPostSocket & | ) | [inline, private] |
void HttpPostSocket::DoMultipartPost | ( | ) | [private] |
Definition at line 176 of file HttpPostSocket.cpp.
References HTTPSocket::AddResponseHeader(), HttpClientSocket::GetUrlHost(), Utility::l2string(), m_boundary, m_content_length, m_content_type, m_fields, m_files, HTTPSocket::MyUseragent(), TcpSocket::Send(), TcpSocket::SendBuf(), HTTPSocket::SendRequest(), HTTPSocket::SetHttpVersion(), and HTTPSocket::SetMethod().
Referenced by OnConnect().
00177 { 00178 long length = 0; // calculate content_length of our post body 00179 std::string tmp; 00180 00181 // fields 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 // files 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; // crlf after file 00214 } 00215 } 00216 00217 // end 00218 tmp = "--" + m_boundary + "--\r\n"; 00219 length += (long)tmp.size(); 00220 00221 // build header, send body 00222 SetMethod("POST"); 00223 SetHttpVersion( "HTTP/1.1" ); 00224 AddResponseHeader( "Host", GetUrlHost() ); // oops - this is actually a request header that we're adding.. 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 // send fields 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 // send files 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]; // for fread 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 // end of send 00281 Send("--" + m_boundary + "--\r\n"); 00282 }
std::map<std::string,std::list<std::string> > HttpPostSocket::m_fields [protected] |
Definition at line 76 of file HttpPostSocket.h.
Referenced by AddMultilineField(), DoMultipartPost(), and OnConnect().
std::map<std::string,std::string> HttpPostSocket::m_files [private] |
std::string HttpPostSocket::m_boundary [private] |
Definition at line 84 of file HttpPostSocket.h.
Referenced by DoMultipartPost(), and HttpPostSocket().
std::map<std::string,long> HttpPostSocket::m_content_length [private] |
Content-length header received from remote.
Reimplemented from HttpClientSocket.
Definition at line 85 of file HttpPostSocket.h.
Referenced by AddFile(), and DoMultipartPost().
std::map<std::string,std::string> HttpPostSocket::m_content_type [private] |
Content-type: header from response.
Reimplemented from HttpClientSocket.
Definition at line 86 of file HttpPostSocket.h.
Referenced by AddFile(), and DoMultipartPost().
bool HttpPostSocket::m_bMultipart [private] |
Definition at line 87 of file HttpPostSocket.h.
Referenced by AddFile(), OnConnect(), and SetMultipart().
int HttpPostSocket::m_boundary_count = 0 [static, private] |
Mutex HttpPostSocket::m_boundary_mutex [static, private] |