- 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 <sstream>
    00031
    00032
    00033 namespace
    00034 {
    00036     // Convenience function to convert a string to lower case
    00038     std::string ToLower(const std::string& Str)
    00039     {
    00040         std::string Ret = Str;
    00041         for (std::string::iterator i = Ret.begin(); i != Ret.end(); ++i)
    00042             *i = static_cast<char>(tolower(*i));
    00043
    00044         return Ret;
    00045     }
    00046 }
    00047
    00048
    00049 namespace sf
    00050 {
    00054 Http::Request::Request(Method RequestMethod, const std::string& URI, const std::string& Body) :
    00055 myMethod      (RequestMethod),
    00056 myURI         (URI),
    00057 myMajorVersion(1),
    00058 myMinorVersion(0),
    00059 myBody        (Body)
    00060 {
    00061
    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(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     while (std::getline(In, Line))
    00301         myBody += Line + "\n";
    00302 }
    00303
    00304
    00308 Http::Http() :
    00309 myHost(),
    00310 myPort(0)
    00311 {
    00312
    00313 }
    00314
    00315
    00319 Http::Http(const std::string& Host, unsigned short Port)
    00320 {
    00321     SetHost(Host, Port);
    00322 }
    00323
    00324
    00328 void Http::SetHost(const std::string& Host, unsigned short Port)
    00329 {
    00330     // Detect the protocol used
    00331     std::string Protocol = ToLower(Host.substr(0, 8));
    00332     if (Protocol.substr(0, 7) == "http://")
    00333     {
    00334         // HTTP protocol
    00335         myHostName = Host.substr(7);
    00336         myPort     = (Port != 0 ? Port : 80);
    00337     }
    00338     else if (Protocol == "https://")
    00339     {
    00340         // HTTPS protocol
    00341         myHostName = Host.substr(8);
    00342         myPort     = (Port != 0 ? Port : 443);
    00343     }
    00344     else
    00345     {
    00346         // Undefined protocol - use HTTP
    00347         myHostName = Host;
    00348         myPort     = (Port != 0 ? Port : 80);
    00349     }
    00350
    00351     // Remove any trailing '/' from the host name
    00352     if (!myHostName.empty() && (*myHostName.rbegin() == '/'))
    00353         myHostName.erase(myHostName.size() - 1);
    00354
    00355     myHost = sf::IPAddress(myHostName);
    00356 }
    00357
    00358
    00367 Http::Response Http::SendRequest(const Http::Request& Req, float Timeout)
    00368 {
    00369     // First make sure the request is valid -- add missing mandatory fields
    00370     Request ToSend(Req);
    00371     if (!ToSend.HasField("From"))
    00372     {
    00373         ToSend.SetField("From", "user@sfml-dev.org");
    00374     }
    00375     if (!ToSend.HasField("User-Agent"))
    00376     {
    00377         ToSend.SetField("User-Agent", "libsfml-network/1.x");
    00378     }
    00379     if (!ToSend.HasField("Host"))
    00380     {
    00381         ToSend.SetField("Host", myHostName);
    00382     }
    00383     if (!ToSend.HasField("Content-Length"))
    00384     {
    00385         std::ostringstream Out;
    00386         Out << ToSend.myBody.size();
    00387         ToSend.SetField("Content-Length", Out.str());
    00388     }
    00389
    00390     // Prepare the response
    00391     Response Received;
    00392
    00393     // Connect the socket to the host
    00394     if (myConnection.Connect(myPort, myHost, Timeout) == Socket::Done)
    00395     {
    00396         // Convert the request to string and send it through the connected socket
    00397         std::string RequestStr = ToSend.ToString();
    00398
    00399         if (!RequestStr.empty())
    00400         {
    00401             // Send it through the socket
    00402             if (myConnection.Send(RequestStr.c_str(), RequestStr.size()) == sf::Socket::Done)
    00403             {
    00404                 // Wait for the server's response
    00405                 std::string ReceivedStr;
    00406                 std::size_t Size = 0;
    00407                 char Buffer[1024];
    00408                 while (myConnection.Receive(Buffer, sizeof(Buffer), Size) == sf::Socket::Done)
    00409                 {
    00410                     ReceivedStr.append(Buffer, Buffer + Size);
    00411                 }
    00412
    00413                 // Build the Response object from the received data
    00414                 Received.FromString(ReceivedStr);
    00415             }
    00416         }
    00417
    00418         // Close the connection
    00419         myConnection.Close();
    00420     }
    00421
    00422     return Received;
    00423 }
    00424
    00425 } // namespace sf

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