PageRenderTime 53ms CodeModel.GetById 24ms RepoModel.GetById 0ms app.codeStats 0ms

/Externals/SFML/src/SFML/Network/Http.cpp

https://bitbucket.org/delroth/dolphin-llvm-dsp
C++ | 432 lines | 236 code | 67 blank | 129 comment | 52 complexity | 7b11430329ded54e1b9eed51947ff06d MD5 | raw file
  1. ////////////////////////////////////////////////////////////
  2. //
  3. // SFML - Simple and Fast Multimedia Library
  4. // Copyright (C) 2007-2009 Laurent Gomila (laurent.gom@gmail.com)
  5. //
  6. // This software is provided 'as-is', without any express or implied warranty.
  7. // In no event will the authors be held liable for any damages arising from the use of this software.
  8. //
  9. // Permission is granted to anyone to use this software for any purpose,
  10. // including commercial applications, and to alter it and redistribute it freely,
  11. // subject to the following restrictions:
  12. //
  13. // 1. The origin of this software must not be misrepresented;
  14. // you must not claim that you wrote the original software.
  15. // If you use this software in a product, an acknowledgment
  16. // in the product documentation would be appreciated but is not required.
  17. //
  18. // 2. Altered source versions must be plainly marked as such,
  19. // and must not be misrepresented as being the original software.
  20. //
  21. // 3. This notice may not be removed or altered from any source distribution.
  22. //
  23. ////////////////////////////////////////////////////////////
  24. ////////////////////////////////////////////////////////////
  25. // Headers
  26. ////////////////////////////////////////////////////////////
  27. #include <SFML/Network/Http.hpp>
  28. #include <ctype.h>
  29. #include <algorithm>
  30. #include <iterator>
  31. #include <sstream>
  32. namespace
  33. {
  34. ////////////////////////////////////////////////////////////
  35. // Convenience function to convert a string to lower case
  36. ////////////////////////////////////////////////////////////
  37. std::string ToLower(const std::string& Str)
  38. {
  39. std::string Ret = Str;
  40. for (std::string::iterator i = Ret.begin(); i != Ret.end(); ++i)
  41. *i = static_cast<char>(tolower(*i));
  42. return Ret;
  43. }
  44. }
  45. namespace sf
  46. {
  47. ////////////////////////////////////////////////////////////
  48. /// Default constructor
  49. ////////////////////////////////////////////////////////////
  50. Http::Request::Request(Method RequestMethod, const std::string& URI, const std::string& Body)
  51. {
  52. SetMethod(RequestMethod);
  53. SetURI(URI);
  54. SetHttpVersion(1, 0);
  55. SetBody(Body);
  56. }
  57. ////////////////////////////////////////////////////////////
  58. /// Set the value of a field; the field is added if it doesn't exist
  59. ////////////////////////////////////////////////////////////
  60. void Http::Request::SetField(const std::string& Field, const std::string& Value)
  61. {
  62. myFields[ToLower(Field)] = Value;
  63. }
  64. ////////////////////////////////////////////////////////////
  65. /// Set the request method.
  66. /// This parameter is Get by default
  67. ////////////////////////////////////////////////////////////
  68. void Http::Request::SetMethod(Http::Request::Method RequestMethod)
  69. {
  70. myMethod = RequestMethod;
  71. }
  72. ////////////////////////////////////////////////////////////
  73. /// Set the target URI of the request.
  74. /// This parameter is "/" by default
  75. ////////////////////////////////////////////////////////////
  76. void Http::Request::SetURI(const std::string& URI)
  77. {
  78. myURI = URI;
  79. // Make sure it starts with a '/'
  80. if (myURI.empty() || (myURI[0] != '/'))
  81. myURI.insert(0, "/");
  82. }
  83. ////////////////////////////////////////////////////////////
  84. /// Set the HTTP version of the request.
  85. /// This parameter is 1.0 by default
  86. ////////////////////////////////////////////////////////////
  87. void Http::Request::SetHttpVersion(unsigned int Major, unsigned int Minor)
  88. {
  89. myMajorVersion = Major;
  90. myMinorVersion = Minor;
  91. }
  92. ////////////////////////////////////////////////////////////
  93. /// Set the body of the request. This parameter is optional and
  94. /// makes sense only for POST requests.
  95. /// This parameter is empty by default
  96. ////////////////////////////////////////////////////////////
  97. void Http::Request::SetBody(const std::string& Body)
  98. {
  99. myBody = Body;
  100. }
  101. ////////////////////////////////////////////////////////////
  102. /// Get the string representation of a request header
  103. ////////////////////////////////////////////////////////////
  104. std::string Http::Request::ToString() const
  105. {
  106. std::ostringstream Out;
  107. // Convert the method to its string representation
  108. std::string RequestMethod;
  109. switch (myMethod)
  110. {
  111. default :
  112. case Get : RequestMethod = "GET"; break;
  113. case Post : RequestMethod = "POST"; break;
  114. case Head : RequestMethod = "HEAD"; break;
  115. }
  116. // Write the first line containing the request type
  117. Out << RequestMethod << " " << myURI << " ";
  118. Out << "HTTP/" << myMajorVersion << "." << myMinorVersion << "\r\n";
  119. // Write fields
  120. for (FieldTable::const_iterator i = myFields.begin(); i != myFields.end(); ++i)
  121. {
  122. Out << i->first << ": " << i->second << "\r\n";
  123. }
  124. // Use an extra \r\n to separate the header from the body
  125. Out << "\r\n";
  126. // Add the body
  127. Out << myBody;
  128. return Out.str();
  129. }
  130. ////////////////////////////////////////////////////////////
  131. /// Check if the given field has been defined
  132. ////////////////////////////////////////////////////////////
  133. bool Http::Request::HasField(const std::string& Field) const
  134. {
  135. return myFields.find(Field) != myFields.end();
  136. }
  137. ////////////////////////////////////////////////////////////
  138. /// Default constructor
  139. ////////////////////////////////////////////////////////////
  140. Http::Response::Response() :
  141. myStatus (ConnectionFailed),
  142. myMajorVersion(0),
  143. myMinorVersion(0)
  144. {
  145. }
  146. ////////////////////////////////////////////////////////////
  147. /// Get the value of a field
  148. ////////////////////////////////////////////////////////////
  149. const std::string& Http::Response::GetField(const std::string& Field) const
  150. {
  151. FieldTable::const_iterator It = myFields.find(ToLower(Field));
  152. if (It != myFields.end())
  153. {
  154. return It->second;
  155. }
  156. else
  157. {
  158. static const std::string Empty = "";
  159. return Empty;
  160. }
  161. }
  162. ////////////////////////////////////////////////////////////
  163. /// Get the header's status code
  164. ////////////////////////////////////////////////////////////
  165. Http::Response::Status Http::Response::GetStatus() const
  166. {
  167. return myStatus;
  168. }
  169. ////////////////////////////////////////////////////////////
  170. /// Get the major HTTP version number of the response
  171. ////////////////////////////////////////////////////////////
  172. unsigned int Http::Response::GetMajorHttpVersion() const
  173. {
  174. return myMajorVersion;
  175. }
  176. ////////////////////////////////////////////////////////////
  177. /// Get the major HTTP version number of the response
  178. ////////////////////////////////////////////////////////////
  179. unsigned int Http::Response::GetMinorHttpVersion() const
  180. {
  181. return myMinorVersion;
  182. }
  183. ////////////////////////////////////////////////////////////
  184. /// Get the body of the response. The body can contain :
  185. /// - the requested page (for GET requests)
  186. /// - a response from the server (for POST requests)
  187. /// - nothing (for HEAD requests)
  188. /// - an error message (in case of an error)
  189. ////////////////////////////////////////////////////////////
  190. const std::string& Http::Response::GetBody() const
  191. {
  192. return myBody;
  193. }
  194. ////////////////////////////////////////////////////////////
  195. /// Construct the header from a response string
  196. ////////////////////////////////////////////////////////////
  197. void Http::Response::FromString(const std::string& Data)
  198. {
  199. std::istringstream In(Data);
  200. // Extract the HTTP version from the first line
  201. std::string Version;
  202. if (In >> Version)
  203. {
  204. if ((Version.size() >= 8) && (Version[6] == '.') &&
  205. (ToLower(Version.substr(0, 5)) == "http/") &&
  206. isdigit(Version[5]) && isdigit(Version[7]))
  207. {
  208. myMajorVersion = Version[5] - '0';
  209. myMinorVersion = Version[7] - '0';
  210. }
  211. else
  212. {
  213. // Invalid HTTP version
  214. myStatus = InvalidResponse;
  215. return;
  216. }
  217. }
  218. // Extract the status code from the first line
  219. int StatusCode = 0;
  220. if (In >> StatusCode)
  221. {
  222. myStatus = static_cast<Status>(StatusCode);
  223. }
  224. else
  225. {
  226. // Invalid status code
  227. myStatus = InvalidResponse;
  228. return;
  229. }
  230. // Ignore the end of the first line
  231. In.ignore(10000, '\n');
  232. // Parse the other lines, which contain fields, one by one
  233. std::string Line;
  234. while (std::getline(In, Line) && (Line.size() > 2))
  235. {
  236. std::string::size_type Pos = Line.find(": ");
  237. if (Pos != std::string::npos)
  238. {
  239. // Extract the field name and its value
  240. std::string Field = Line.substr(0, Pos);
  241. std::string Value = Line.substr(Pos + 2);
  242. // Remove any trailing \r
  243. if (!Value.empty() && (*Value.rbegin() == '\r'))
  244. Value.erase(Value.size() - 1);
  245. // Add the field
  246. myFields[ToLower(Field)] = Value;
  247. }
  248. }
  249. // Finally extract the body
  250. myBody.clear();
  251. std::copy(std::istreambuf_iterator<char>(In), std::istreambuf_iterator<char>(), std::back_inserter(myBody));
  252. }
  253. ////////////////////////////////////////////////////////////
  254. /// Default constructor
  255. ////////////////////////////////////////////////////////////
  256. Http::Http() :
  257. myHost(),
  258. myPort(0)
  259. {
  260. }
  261. ////////////////////////////////////////////////////////////
  262. /// Construct the Http instance with the target host
  263. ////////////////////////////////////////////////////////////
  264. Http::Http(const std::string& Host, unsigned short Port)
  265. {
  266. SetHost(Host, Port);
  267. }
  268. ////////////////////////////////////////////////////////////
  269. /// Set the target host
  270. ////////////////////////////////////////////////////////////
  271. void Http::SetHost(const std::string& Host, unsigned short Port)
  272. {
  273. // Detect the protocol used
  274. std::string Protocol = ToLower(Host.substr(0, 8));
  275. if (Protocol.substr(0, 7) == "http://")
  276. {
  277. // HTTP protocol
  278. myHostName = Host.substr(7);
  279. myPort = (Port != 0 ? Port : 80);
  280. }
  281. else if (Protocol == "https://")
  282. {
  283. // HTTPS protocol
  284. myHostName = Host.substr(8);
  285. myPort = (Port != 0 ? Port : 443);
  286. }
  287. else
  288. {
  289. // Undefined protocol - use HTTP
  290. myHostName = Host;
  291. myPort = (Port != 0 ? Port : 80);
  292. }
  293. // Remove any trailing '/' from the host name
  294. if (!myHostName.empty() && (*myHostName.rbegin() == '/'))
  295. myHostName.erase(myHostName.size() - 1);
  296. myHost = sf::IPAddress(myHostName);
  297. }
  298. ////////////////////////////////////////////////////////////
  299. /// Send a HTTP request and return the server's response.
  300. /// You must be connected to a host before sending requests.
  301. /// Any missing mandatory header field will be added with an appropriate value.
  302. /// Warning : this function waits for the server's response and may
  303. /// not return instantly; use a thread if you don't want to block your
  304. /// application.
  305. ////////////////////////////////////////////////////////////
  306. Http::Response Http::SendRequest(const Http::Request& Req, float Timeout)
  307. {
  308. // First make sure the request is valid -- add missing mandatory fields
  309. Request ToSend(Req);
  310. if (!ToSend.HasField("From"))
  311. {
  312. ToSend.SetField("From", "user@sfml-dev.org");
  313. }
  314. if (!ToSend.HasField("User-Agent"))
  315. {
  316. ToSend.SetField("User-Agent", "libsfml-network/1.x");
  317. }
  318. if (!ToSend.HasField("Host"))
  319. {
  320. ToSend.SetField("Host", myHostName);
  321. }
  322. if (!ToSend.HasField("Content-Length"))
  323. {
  324. std::ostringstream Out;
  325. Out << ToSend.myBody.size();
  326. ToSend.SetField("Content-Length", Out.str());
  327. }
  328. if ((ToSend.myMethod == Request::Post) && !ToSend.HasField("Content-Type"))
  329. {
  330. ToSend.SetField("Content-Type", "application/x-www-form-urlencoded");
  331. }
  332. if ((ToSend.myMajorVersion * 10 + ToSend.myMinorVersion >= 11) && !ToSend.HasField("Connection"))
  333. {
  334. ToSend.SetField("Connection", "close");
  335. }
  336. // Prepare the response
  337. Response Received;
  338. // Connect the socket to the host
  339. if (myConnection.Connect(myPort, myHost, Timeout) == Socket::Done)
  340. {
  341. // Convert the request to string and send it through the connected socket
  342. std::string RequestStr = ToSend.ToString();
  343. if (!RequestStr.empty())
  344. {
  345. // Send it through the socket
  346. if (myConnection.Send(RequestStr.c_str(), RequestStr.size()) == sf::Socket::Done)
  347. {
  348. // Wait for the server's response
  349. std::string ReceivedStr;
  350. std::size_t Size = 0;
  351. char Buffer[1024];
  352. while (myConnection.Receive(Buffer, sizeof(Buffer), Size) == sf::Socket::Done)
  353. {
  354. ReceivedStr.append(Buffer, Buffer + Size);
  355. }
  356. // Build the Response object from the received data
  357. Received.FromString(ReceivedStr);
  358. }
  359. }
  360. // Close the connection
  361. myConnection.Close();
  362. }
  363. return Received;
  364. }
  365. } // namespace sf