Как получить значения ключа из HTTP-запроса post с использованием C ++ и Boost Asio - PullRequest
1 голос
/ 09 января 2020

Мне было дано задание, которое включает в себя написание веб-сервера с использованием c ++ и библиотеки Boost Asio.

Я собрал рабочий сервер, который может отправлять html файлы обратно в браузер клиента с помощью книги называется "Boost.Asio C ++ Network Programming Cookbook", но я борюсь с обработкой запросов POST от клиента.

Когда клиент подключается к серверу, ему предоставляется простая форма HTML, состоящая из поля имени пользователя и пароля для входа на сервер, которая затем отправляется на сервер с помощью запроса POST.

Я вывел содержимое полученного POST-запроса на консоль, и я могу видеть всю информацию заголовка, но не могу увидеть данные формы. Я использовал Wireshark для проверки пакетов, и данные отправляются по сети.

Данные принимаются сервером в виде потокового буфера Boost Asio, и я анализирую его, чтобы получить запрошенный файл HTML читая его в векторе, а затем беря соответствующие элементы, такие как метод или цель.

Есть ли у кого-нибудь какие-либо предложения относительно того, где искать учебники о том, как анализировать данные формы?

Приведенный ниже код является частью файла cpp, который анализирует запрос POST и обрабатывает ответ на основе содержимого запроса. параметр '& request' - Boost Asio streambuf

У меня очень мало опыта в веб-программировании, и я был бы благодарен за любые советы!

Код для разбора запросов

// Prepare and return the response message.
// Parse the request from the client to find requested document 
std::istream buffer(&request);
std::vector<std::string> parsed((std::istream_iterator<std::string>(buffer)), std::istream_iterator<std::string>() );   

Обработка POST-запросов


else if (parsed.size() >= 3 && parsed[0] == "POST") {

            htmlFile = "/files.html";

            // Retrieve files from server file system. The second element in 'parsed' vector is file name
            std::ifstream fileStream(".\\directory" + htmlFile);

            // If the file exists then iterate it and assign the value to the content string variable, else return 404.
            if (fileStream.good()) {
                std::string fileContents((std::istreambuf_iterator<char>(fileStream)), std::istreambuf_iterator<char>());
                content = fileContents;
                code = "200 ok";
            }
            else {
                std::ifstream fileStream(".\\directory\\404.html");
                std::string fileContents((std::istreambuf_iterator<char>(fileStream)), std::istreambuf_iterator<char>());
                content = fileContents;
                code = "404";
            }// End of nested if-else statement 

        }// End of else-if statement
        else {
            std::ifstream fileStream(".\\directory\\401.html");
            std::string fileContents((std::istreambuf_iterator<char>(fileStream)), std::istreambuf_iterator<char>());
            content = fileContents;
            code = "401";
            // Write bad request to log file for security audits if not "GET" request
            logging.logAction("Illegal request by client IP " + m_sock->remote_endpoint().address().to_string());

        }//End of if-else statement

        std::ostringstream oss;
        oss << "GET HTTP/1.1 " << code << " \r\n";
        oss << "Cache-Control: no-cache, private" << "\r\n";
        oss << "Content-Type: text/html" << "\r\n";
        oss << "Content-Length: " << content.size() << "\r\n";
        oss << "\r\n\r\n";
        oss << content;

        response = oss.str().c_str();

1 Ответ

1 голос
/ 09 января 2020

HTTP является протоколом линии. Образцы: https://www.tutorialspoint.com/http/http_requests.htm

POST /cgi-bin/process.cgi HTTP/1.1
User-Agent: Mozilla/4.0 (compatible; MSIE5.01; Windows NT)
Host: www.tutorialspoint.com
Content-Type: application/x-www-form-urlencoded
Content-Length: length
Accept-Language: en-us
Accept-Encoding: gzip, deflate
Connection: Keep-Alive

licenseID=string&content=string&/paramsXML=string

Вы должны быть более точными c при разборе, чем помещать каждое разделенное пробелами слово в вектор.

Начните примерно так:

Live On Coliru

#include <iostream>
#include <iomanip>
#include <boost/asio.hpp>

int main() {
    boost::asio::streambuf request;
    {
        std::ostream sample(&request);
        sample <<
            "POST /cgi-bin/process.cgi HTTP/1.1\r\n"
            "User-Agent: Mozilla/4.0 (compatible; MSIE5.01; Windows NT)\r\n"
            "Host: www.tutorialspoint.com\r\n"
            "Content-Type: application/x-www-form-urlencoded\r\n"
            "Content-Length: 49\r\n"
            "Accept-Language: en-us\r\n"
            "Accept-Encoding: gzip, deflate\r\n"
            "Connection: Keep-Alive\r\n"
            "\r\n"
            "licenseID=string&content=string&/paramsXML=string"
            ;
    }

    std::istream buffer(&request);
    std::string line;

    // parsing the headers
    while (getline(buffer, line, '\n')) {
        if (line.empty() || line == "\r") {
            break; // end of headers reached
        }
        if (line.back() == '\r') {
            line.resize(line.size()-1);
        }
        // simply ignoring headers for now
        std::cout << "Ignore header: " << std::quoted(line) << "\n";
    }

    std::string const body(std::istreambuf_iterator<char>{buffer}, {});

    std::cout << "Parsed content: " << std::quoted(body) << "\n";
}

Печать

Ignore header: "POST /cgi-bin/process.cgi HTTP/1.1"
Ignore header: "User-Agent: Mozilla/4.0 (compatible; MSIE5.01; Windows NT)"
Ignore header: "Host: www.tutorialspoint.com"
Ignore header: "Content-Type: application/x-www-form-urlencoded"
Ignore header: "Content-Length: 49"
Ignore header: "Accept-Language: en-us"
Ignore header: "Accept-Encoding: gzip, deflate"
Ignore header: "Connection: Keep-Alive"
Parsed content: "licenseID=string&content=string&/paramsXML=string"
...