HiveBrain v1.2.0
Get Started
← Back to all entries
patterncppMinor

Parsing httpline

Submitted by: @import:stackexchange-codereview··
0
Viewed 0 times
parsinghttplinestackoverflow

Problem

I have an HTTP server class (.hpp & cpp). I am trying to improve reserve data from the socket class because I have s.getline() to get HTTP call. My s.RecvData() gets data line by line in an infinite loop to build HTTP struct.

This is my old code:

while (1) {
    line = s.RecvData();
    //httpline  = s.Getline();
    if (line.empty()) break;
    //find location of tab"\t"
    int location_tab_char = line.find_first_of(" ");
    int loacation_End_chars = line.find_first_of("\r\n");
    if (loacation_End_chars == 0)
    {
        break;
    }
    if ("Host:" == line.substr(0, location_tab_char))
    {
        req.hostName_ = line.substr(0, loacation_End_chars);
    }
    else if ("Connection:" == line.substr(0, location_tab_char))
    {
        req.conn_ = line.substr(0, loacation_End_chars);
    }
    else    if ("Accept:" == line.substr(0, location_tab_char))
    {
        req.accept_ = line.substr(0, loacation_End_chars);
    }
    else if ("Accept-Language:" == line.substr(0, location_tab_char))
    {
        req.acceptLanguage_ = line.substr(0, loacation_End_chars);
    }
    else if ("Accept-Encoding:" == line.substr(0, location_tab_char))
    {
        req.acceptEncoding_ = line.substr(0, loacation_End_chars);
    }
    else if ("User-Agent:" == line.substr(0, location_tab_char))
    {
        req.userAgent_ = line.substr(0, loacation_End_chars);
    }
}


I just need a way to improve it because getting data from the socket line by line is too much calling. Also, when I pass to struct, I pass this string "Host: 169.254.80.80:8080"


"Host: 169.254.80.80:8080\r\nConnection: keep-alive\r\nAccept:
text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,/;q=0.8\r\nUser-Agent:
Mozilla/5.0 (Windows NT 6.3; WOW64)
AppleWebKit/537.36\r\nAccept-Encoding: gzip,deflate,sdch\r\n
Accept-Language: en-US,en;q=0.8,ar;q=0.6 ";

Solution

Your code can be made smaller and without repeated constructs, by mapping your keys to values in a map:

// #include 

std::map headers;

while(true) { // better use true instead of 1

    line = s.RecvData();

    if (line.empty() || line == "\r\n\r\n")
        break;
    auto key_value_sep = line.find(":"); // do not split by space

    // you could stop here in case of an exception in the data
    // if(0 == key_value_sep || std::string::npos == key_value_sep)
    //     throw std::runtime_error{"..."}; // or break, or whatever

    // line is a single line; as such, end chars location not needed
    // int loacation_End_chars = line.find_first_of("\r\n");

    auto key = line.substr(0, key_value_separator);

    auto value = line.substr(key_value_separator + 2, // skip ": "
                             line.size() - key.size() - 4); // size less key,
                                                            // separator and
                                                            // "\r\n"
    // you could break here in case of an exception in the data
    // if (value.empty() || key.empty()) || ...)
    //     throw std::runtime_error{"..."}; // or break, or whatever

    // set header 
    headers[key] += value;
}

// set headers (or use directly from map)
req.hostName_ = headers["Host"];
req.conn_ = headers["Connection"];
req.accept_ = headers["Accept"];
req.acceptLanguage_ = headers["Accept-Language"];
req.acceptEncoding_ = headers["Accept-Encoding"];
req.userAgent_ = headers["User-Agent"];

Code Snippets

// #include <map>

std::map<std::string,std::string> headers;

while(true) { // better use true instead of 1

    line = s.RecvData();

    if (line.empty() || line == "\r\n\r\n")
        break;
    auto key_value_sep = line.find(":"); // do not split by space

    // you could stop here in case of an exception in the data
    // if(0 == key_value_sep || std::string::npos == key_value_sep)
    //     throw std::runtime_error{"..."}; // or break, or whatever

    // line is a single line; as such, end chars location not needed
    // int loacation_End_chars = line.find_first_of("\r\n");

    auto key = line.substr(0, key_value_separator);

    auto value = line.substr(key_value_separator + 2, // skip ": "
                             line.size() - key.size() - 4); // size less key,
                                                            // separator and
                                                            // "\r\n"
    // you could break here in case of an exception in the data
    // if (value.empty() || key.empty()) || ...)
    //     throw std::runtime_error{"..."}; // or break, or whatever

    // set header 
    headers[key] += value;
}

// set headers (or use directly from map)
req.hostName_ = headers["Host"];
req.conn_ = headers["Connection"];
req.accept_ = headers["Accept"];
req.acceptLanguage_ = headers["Accept-Language"];
req.acceptEncoding_ = headers["Accept-Encoding"];
req.userAgent_ = headers["User-Agent"];

Context

StackExchange Code Review Q#47416, answer score: 6

Revisions (0)

No revisions yet.