Requêtes web avec HTTP

Introduction

SFML fournit une classe de client HTTP simple, pour vous permettre de communiquer avec des serveurs web. "Simple" signifie qu'elle supporte uniquement les fonctionnalités les plus basiques de HTTP : les requêtes POST, GET et HEAD, l'accès aux champs d'en-tête, et la lecture/écriture du corps des pages.

S'il vous faut des fonctionnalités plus complexes, comme par exemple le support de HTTP sécurisé (HTTPS), vous devriez plutôt chercher une bibliothèque complètement dédiée à HTTP, comme libcurl ou cpp-netlib.

Mais pour une interaction simple entre un programme et un serveur web, ce sera largement suffisant.

sf::Http

Pour communiquer avec un serveur HTTP, il faut utiliser la classe sf::Http.

#include <SFML/Network.hpp>

sf::Http http;
http.setHost("http://www.some-server.org/");

// ou bien
sf::Http http("http://www.some-server.org/");

Notez bien que le fait de renseigner l'hôte ne déclenche pas de connection : une connection temporaire avec le serveur sera faite plus tard pour chaque requête.

Il n'y a plus qu'une autre fonction à voir dans la classe sf::Http, et c'est la plus importante car elle envoie les requêtes. Et... c'est en gros tout ce que contient cette classe.

sf::Http::Request request;
// paramétrage de la requête...
sf::Http::Response response = http.sendRequest(request);

Les requêtes

Une requête HTTP, représentée par la classe sf::Http::Request, contient les information suivantes :

sf::Http::Request request;
request.setMethod(sf::Http::Request::Post);
request.setUri("/page.html");
request.setHttpVersion(1, 1); // HTTP 1.1
request.setField("From", "me");
request.setField("Content-Type", "application/x-www-form-urlencoded");
request.setBody("para1=value1&param2=value2");

sf::Http::Response response = http.sendRequest(request);

SFML définit automatiquement les champs d'en-tête obligatoires, comme par exemple "Host" ou "Content-Length". Vous pouvez donc envoyer vos requêtes sans vous soucier de cela, SFML fera toujours de son mieux pour les rendre valides.

Les réponses

Si la classe sf::Http a pu se connecter à l'hôte et envoyer la requête, alors une réponse est renvoyée par le serveur et retournée à l'utilisateur, encapsulée dans une instance de sf::Http::Response. Les réponses contiennent les membres suivants :

sf::Http::Response response = http.sendRequest(request);
std::cout << "status: " << response.getStatus() << std::endl;
std::cout << "HTTP version: " << response.getMajorHttpVersion() << "." << response.getMinorHttpVersion() << std::endl;
std::cout << "Content-Type header:" << response.getField("Content-Type") << std::endl;
std::cout << "body: " << response.getBody() << std::endl;

Le code de statut peut être utilisé pour vérifier si la requête a été traitée avec succès ou non : les codes 2xx informent que tout s'est bien passé, les codes 3xx informent d'une redirection, les codes 4xx représentent des erreurs côté client, les codes 5xx sont des erreurs du serveur, et enfin les codes 10xx sont des erreurs spécifiques à SFML, qui ne font pas partie du standard HTTP.

Exemple : envoyer des scores à une base de donnée en ligne

Voici un petit exemple qui montre comment réaliser une tâche assez courante : envoyer un score à une base de donnée en ligne.

#include <SFML/Network.hpp>
#include <sstream>

void sendScore(int score, const std::string& name)
{
    // préparation de la requête
    sf::Http::Request request("/send-score.php", sf::Http::Request::Post);

    // encodage des paramètres dans le corps de la requête
    std::ostringstream stream;
    stream << "name=" << name << "&score=" << score;
    request.setBody(stream.str());

    // envoi de la requête au serveur
    sf::Http http("http://www.myserver.com/");
    sf::Http::Response response = http.sendRequest(request);

    // vérification du statut
    if (response.getStatus() == sf::Http::Response::Ok)
    {
        // affichage de la réponse du serveur
        std::cout << response.getBody() << std::endl;
    }
    else
    {
        std::cout << "request failed" << std::endl;
    }
}

Bien entendu, ceci est une façon très simple de gérer des scores en ligne. Il n'y a aucune protection : n'importe qui pourrait envoyer un faux score facilement. Une approche plus robuste impliquerait certainement d'utiliser en paramètre supplémentaire un code de hachage, qui permettrait au serveur de s'assurer que le score provient bien du logiciel qui est censé l'envoyer, plutôt que d'une requête d'un petit malin. Mais ceci dépasse le cadre de ce tutoriel.

Et, enfin, voici une version très simpliste de ce à quoi pourrait ressembler la page PHP côté serveur.

<?php
    $name = $_POST['name'];
    $score = $_POST['score'];
    
    if (write_to_database($name, $score)) // peu importe... ce n'est pas un tutoriel de PHP :)
    {
        echo "name and score added!";
    }
    else
    {
        echo "failed to write name and score to database...";
    }
?>