- Main Page
- Namespaces
- Classes
- Files

- File List

# Http.cpp

    00001
    00002 //
    00003 // SFML - Simple and Fast Multimedia Library
    00004 // Copyright (C) 2007-2009 Laurent Gomila (laurent.gom@gmail.com)
    00005 //
    00006 // This software is provided 'as-is', without any express or implied warranty.
    00007 // In no event will the authors be held liable for any damages arising from the use of this software.
    00008 //
    00009 // Permission is granted to anyone to use this software for any purpose,
    00010 // including commercial applications, and to alter it and redistribute it freely,
    00011 // subject to the following restrictions:
    00012 //
    00013 // 1. The origin of this software must not be misrepresented;
    00014 //    you must not claim that you wrote the original software.
    00015 //    If you use this software in a product, an acknowledgment
    00016 //    in the product documentation would be appreciated but is not required.
    00017 //
    00018 // 2. Altered source versions must be plainly marked as such,
    00019 //    and must not be misrepresented as being the original software.
    00020 //
    00021 // 3. This notice may not be removed or altered from any source distribution.
    00022 //
    00024
    00026 // Headers
    00028 #include <SFML/Network/Http.hpp>
    00029 #include <ctype.h>
    00030 #include <algorithm>
    00031 #include <iterator>
    00032 #include <sstream>
    00033
    00034
    00035 namespace
    00036 {
    00038     // Convenience function to convert a string to lower case
    00040     std::string ToLower(const std::string& Str)
    00041     {
    00042         std::string Ret = Str;
    00043         for (std::string::iterator i = Ret.begin(); i != Ret.end(); ++i)
    00044             *i = static_cast<char>(tolower(*i));
    00045
    00046         return Ret;
    00047     }
    00048 }
    00049
    00050
    00051 namespace sf
    00052 {
    00056 Http::Request::Request(Method RequestMethod, const std::string& URI, const std::string& Body)
    00057 {
    00058     SetMethod(RequestMethod);
    00059     SetURI(URI);
    00060     SetHttpVersion(1, 0);
    00061     SetBody(Body);
    00062 }
    00063
    00064
    00068 void Http::Request::SetField(const std::string& Field, const std::string& Value)
    00069 {
    00070     myFields[ToLower(Field)] = Value;
    00071 }
    00072
    00073
    00078 void Http::Request::SetMethod(Http::Request::Method RequestMethod)
    00079 {
    00080     myMethod = RequestMethod;
    00081 }
    00082
    00083
    00088 void Http::Request::SetURI(const std::string& URI)
    00089 {
    00090     myURI = URI;
    00091
    00092     // Make sure it starts with a '/'
    00093     if (myURI.empty() || (myURI[0] != '/'))
    00094         myURI.insert(0, "/");
    00095 }
    00096
    00097
    00102 void Http::Request::SetHttpVersion(unsigned int Major, unsigned int Minor)
    00103 {
    00104     myMajorVersion = Major;
    00105     myMinorVersion = Minor;
    00106 }
    00107
    00108
    00114 void Http::Request::SetBody(const std::string& Body)
    00115 {
    00116     myBody = Body;
    00117 }
    00118
    00119
    00123 std::string Http::Request::ToString() const
    00124 {
    00125     std::ostringstream Out;
    00126
    00127     // Convert the method to its string representation
    00128     std::string RequestMethod;
    00129     switch (myMethod)
    00130     {
    00131         default :
    00132         case Get :  RequestMethod = "GET";  break;
    00133         case Post : RequestMethod = "POST"; break;
    00134         case Head : RequestMethod = "HEAD"; break;
    00135     }
    00136
    00137     // Write the first line containing the request type
    00138     Out << RequestMethod << " " << myURI << " ";
    00139     Out << "HTTP/" << myMajorVersion << "." << myMinorVersion << "\r\n";
    00140
    00141     // Write fields
    00142     for (FieldTable::const_iterator i = myFields.begin(); i != myFields.end(); ++i)
    00143     {
    00144         Out << i->first << ": " << i->second << "\r\n";
    00145     }
    00146
    00147     // Use an extra \r\n to separate the header from the body
    00148     Out << "\r\n";
    00149
    00150     // Add the body
    00151     Out << myBody;
    00152
    00153     return Out.str();
    00154 }
    00155
    00156
    00160 bool Http::Request::HasField(const std::string& Field) const
    00161 {
    00162     return myFields.find(Field) != myFields.end();
    00163 }
    00164
    00165
    00169 Http::Response::Response() :
    00170 myStatus      (ConnectionFailed),
    00171 myMajorVersion(0),
    00172 myMinorVersion(0)
    00173 {
    00174
    00175 }
    00176
    00177
    00181 const std::string& Http::Response::GetField(const std::string& Field) const
    00182 {
    00183     FieldTable::const_iterator It = myFields.find(ToLower(Field));
    00184     if (It != myFields.end())
    00185     {
    00186         return It->second;
    00187     }
    00188     else
    00189     {
    00190         static const std::string Empty = "";
    00191         return Empty;
    00192     }
    00193 }
    00194
    00195
    00199 Http::Response::Status Http::Response::GetStatus() const
    00200 {
    00201     return myStatus;
    00202 }
    00203
    00204
    00208 unsigned int Http::Response::GetMajorHttpVersion() const
    00209 {
    00210     return myMajorVersion;
    00211 }
    00212
    00213
    00217 unsigned int Http::Response::GetMinorHttpVersion() const
    00218 {
    00219     return myMinorVersion;
    00220 }
    00221
    00222
    00230 const std::string& Http::Response::GetBody() const
    00231 {
    00232     return myBody;
    00233 }
    00234
    00235
    00239 void Http::Response::FromString(const std::string& Data)
    00240 {
    00241     std::istringstream In(Data);
    00242
    00243     // Extract the HTTP version from the first line
    00244     std::string Version;
    00245     if (In >> Version)
    00246     {
    00247         if ((Version.size() >= 8) && (Version[6] == '.') &&
    00248             (ToLower(Version.substr(0, 5)) == "http/")   &&
    00249              isdigit(Version[5]) && isdigit(Version[7]))
    00250         {
    00251             myMajorVersion = Version[5] - '0';
    00252             myMinorVersion = Version[7] - '0';
    00253         }
    00254         else
    00255         {
    00256             // Invalid HTTP version
    00257             myStatus = InvalidResponse;
    00258             return;
    00259         }
    00260     }
    00261
    00262     // Extract the status code from the first line
    00263     int StatusCode;
    00264     if (In >> StatusCode)
    00265     {
    00266         myStatus = static_cast<Status>(StatusCode);
    00267     }
    00268     else
    00269     {
    00270         // Invalid status code
    00271         myStatus = InvalidResponse;
    00272         return;
    00273     }
    00274
    00275     // Ignore the end of the first line
    00276     In.ignore(10000, '\n');
    00277
    00278     // Parse the other lines, which contain fields, one by one
    00279     std::string Line;
    00280     while (std::getline(In, Line) && (Line.size() > 2))
    00281     {
    00282         std::string::size_type Pos = Line.find(": ");
    00283         if (Pos != std::string::npos)
    00284         {
    00285             // Extract the field name and its value
    00286             std::string Field = Line.substr(0, Pos);
    00287             std::string Value = Line.substr(Pos + 2);
    00288
    00289             // Remove any trailing \r
    00290             if (!Value.empty() && (*Value.rbegin() == '\r'))
    00291                 Value.erase(Value.size() - 1);
    00292
    00293             // Add the field
    00294             myFields[ToLower(Field)] = Value;
    00295         }
    00296     }
    00297
    00298     // Finally extract the body
    00299     myBody.clear();
    00300     std::copy(std::istreambuf_iterator<char>(In), std::istreambuf_iterator<char>(), std::back_inserter(myBody));
    00301 }
    00302
    00303
    00307 Http::Http() :
    00308 myHost(),
    00309 myPort(0)
    00310 {
    00311
    00312 }
    00313
    00314
    00318 Http::Http(const std::string& Host, unsigned short Port)
    00319 {
    00320     SetHost(Host, Port);
    00321 }
    00322
    00323
    00327 void Http::SetHost(const std::string& Host, unsigned short Port)
    00328 {
    00329     // Detect the protocol used
    00330     std::string Protocol = ToLower(Host.substr(0, 8));
    00331     if (Protocol.substr(0, 7) == "http://")
    00332     {
    00333         // HTTP protocol
    00334         myHostName = Host.substr(7);
    00335         myPort     = (Port != 0 ? Port : 80);
    00336     }
    00337     else if (Protocol == "https://")
    00338     {
    00339         // HTTPS protocol
    00340         myHostName = Host.substr(8);
    00341         myPort     = (Port != 0 ? Port : 443);
    00342     }
    00343     else
    00344     {
    00345         // Undefined protocol - use HTTP
    00346         myHostName = Host;
    00347         myPort     = (Port != 0 ? Port : 80);
    00348     }
    00349
    00350     // Remove any trailing '/' from the host name
    00351     if (!myHostName.empty() && (*myHostName.rbegin() == '/'))
    00352         myHostName.erase(myHostName.size() - 1);
    00353
    00354     myHost = sf::IPAddress(myHostName);
    00355 }
    00356
    00357
    00366 Http::Response Http::SendRequest(const Http::Request& Req, float Timeout)
    00367 {
    00368     // First make sure the request is valid -- add missing mandatory fields
    00369     Request ToSend(Req);
    00370     if (!ToSend.HasField("From"))
    00371     {
    00372         ToSend.SetField("From", "user@sfml-dev.org");
    00373     }
    00374     if (!ToSend.HasField("User-Agent"))
    00375     {
    00376         ToSend.SetField("User-Agent", "libsfml-network/1.x");
    00377     }
    00378     if (!ToSend.HasField("Host"))
    00379     {
    00380         ToSend.SetField("Host", myHostName);
    00381     }
    00382     if (!ToSend.HasField("Content-Length"))
    00383     {
    00384         std::ostringstream Out;
    00385         Out << ToSend.myBody.size();
    00386         ToSend.SetField("Content-Length", Out.str());
    00387     }
    00388     if ((ToSend.myMethod == Request::Post) && !ToSend.HasField("Content-Type"))
    00389     {
    00390         ToSend.SetField("Content-Type", "application/x-www-form-urlencoded");
    00391     }
    00392     if ((ToSend.myMajorVersion * 10 + ToSend.myMinorVersion >= 11) && !ToSend.HasField("Connection"))
    00393     {
    00394         ToSend.SetField("Connection", "close");
    00395     }
    00396
    00397     // Prepare the response
    00398     Response Received;
    00399
    00400     // Connect the socket to the host
    00401     if (myConnection.Connect(myPort, myHost, Timeout) == Socket::Done)
    00402     {
    00403         // Convert the request to string and send it through the connected socket
    00404         std::string RequestStr = ToSend.ToString();
    00405
    00406         if (!RequestStr.empty())
    00407         {
    00408             // Send it through the socket
    00409             if (myConnection.Send(RequestStr.c_str(), RequestStr.size()) == sf::Socket::Done)
    00410             {
    00411                 // Wait for the server's response
    00412                 std::string ReceivedStr;
    00413                 std::size_t Size = 0;
    00414                 char Buffer[1024];
    00415                 while (myConnection.Receive(Buffer, sizeof(Buffer), Size) == sf::Socket::Done)
    00416                 {
    00417                     ReceivedStr.append(Buffer, Buffer + Size);
    00418                 }
    00419
    00420                 // Build the Response object from the received data
    00421                 Received.FromString(ReceivedStr);
    00422             }
    00423         }
    00424
    00425         // Close the connection
    00426         myConnection.Close();
    00427     }
    00428
    00429     return Received;
    00430 }
    00431
    00432 } // namespace sf

:: Copyright © 2007-2008 Laurent Gomila, all rights reserved :: Documentation generated by doxygen 1.5.2 ::