Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Parse HTTP request without using regexp

I'm using a regex to separate the fields of an HTTP request:

GET /index.asp?param1=hello&param2=128 HTTP/1.1

This way:

smatch m;
try 
{ 
    regex re1("(GET|POST) (.+) HTTP"); 
    regex_search(query, m, re1); 
} 
catch (regex_error e) 
{ 
    printf("Regex 1 Error: %d\n", e.code()); 
}
string method = m[1]; 
string path = m[2];

try 
{ 
    regex re2("/(.+)?\\?(.+)?"); 
    if (regex_search(path, m, re2)) 
    { 
        document = m[1]; 
        querystring = m[2];
    }
} 
catch (regex_error e) 
{ 
    printf("Regex 2 Error: %d\n", e.code()); 
}

Unfortunately this code works in MSVC but not with GCC 4.8.2 (which I have on Ubuntu Server 14.04). Can you suggest a different method of splitting that string using maybe normal std::string operators?

I don't know how to split the URL in different elements since the query string separator '?' may or may not be present in the string.

like image 510
Mark Miles Avatar asked Dec 24 '22 23:12

Mark Miles


1 Answers

You might use std::istringstream to parse this:

int main()
{
    std::string request = "GET /index.asp?param1=hello&param2=128 HTTP/1.1";

    // separate the 3 main parts

    std::istringstream iss(request);

    std::string method;
    std::string query;
    std::string protocol;

    if(!(iss >> method >> query >> protocol))
    {
        std::cout << "ERROR: parsing request\n";
        return 1;
    }

    // reset the std::istringstream with the query string

    iss.clear();
    iss.str(query);

    std::string url;

    if(!std::getline(iss, url, '?')) // remove the URL part
    {
        std::cout << "ERROR: parsing request url\n";
        return 1;
    }

    // store query key/value pairs in a map
    std::map<std::string, std::string> params;

    std::string keyval, key, val;

    while(std::getline(iss, keyval, '&')) // split each term
    {
        std::istringstream iss(keyval);

        // split key/value pairs
        if(std::getline(std::getline(iss, key, '='), val))
            params[key] = val;
    }

    std::cout << "protocol: " << protocol << '\n';
    std::cout << "method  : " << method << '\n';
    std::cout << "url     : " << url << '\n';

    for(auto const& param: params)
        std::cout << "param   : " << param.first << " = " << param.second << '\n';
}

Output:

protocol: HTTP/1.1
method  : GET
url     : /index.asp
param   : param1 = hello
param   : param2 = 128
like image 121
Galik Avatar answered Jan 07 '23 19:01

Galik