I'm writing some C++ unit tests with Catch2 for a library which includes a dependency on a HTTP parser. (In this particular case, llhttp
.)
As part of my unit tests, I have a directory containing test data. For example, one of the most simple tests contains the following file which specifies an input to the test.
POST /api/example HTTP/1.1
Host: example
Content-Type: application/json
{
"body": "BODY"
}
This is a set of HTTP headers, and a JSON Content body, which is intended to be used as input to test the parsing logic.
However, the line endings are variable depending on the OS.
I saved the file from a Linux OS. Therefore the line endings are \n
. (New line, no carriage return.)
This is incompatiable with HTTP, as the standard requires \r\n
. (Carriage return, followed by new line.)
I'm looking for some advice on how best to proceed here.
While I could write a function to convert the data read from file into a std::string
containing the correct line ending characters, this has some isses.
- Firstly I have to write the function, and I can't immediatly think of an elegant implementation. This feels a bit like a code smell, maybe this isn't the best approach.
- Possibly more importantly, this function is unlikely to be cross platform compatiable. If someone re-saves the same file from a Windows system, the logic will be broken. (Unless I were to implement something more complex which first scans the file to detect the line ending format.)
Something about this doesn't feel quite right. Perhaps someone has some advice on the best way to proceed?
To illustrate why I don't think I have a good solution to this problem, here's the current implementation I am using.
std::ifstream ifile("http_data.txt", std::ios::binary);
std::string line; // input
std::ostringstream oss; // output
while(std::getline(ifile, line)) // line ending agonstic
{
oss.write(line.c_str(), line.size());
oss.write("\r\n", 2); // line ending specific
}
In short - I don't think my approach is particuarly good. Is there a smarter way to do this?
I'm writing some C++ unit tests with Catch2 for a library which includes a dependency on a HTTP parser. (In this particular case, llhttp
.)
As part of my unit tests, I have a directory containing test data. For example, one of the most simple tests contains the following file which specifies an input to the test.
POST /api/example HTTP/1.1
Host: example
Content-Type: application/json
{
"body": "BODY"
}
This is a set of HTTP headers, and a JSON Content body, which is intended to be used as input to test the parsing logic.
However, the line endings are variable depending on the OS.
I saved the file from a Linux OS. Therefore the line endings are \n
. (New line, no carriage return.)
This is incompatiable with HTTP, as the standard requires \r\n
. (Carriage return, followed by new line.)
I'm looking for some advice on how best to proceed here.
While I could write a function to convert the data read from file into a std::string
containing the correct line ending characters, this has some isses.
- Firstly I have to write the function, and I can't immediatly think of an elegant implementation. This feels a bit like a code smell, maybe this isn't the best approach.
- Possibly more importantly, this function is unlikely to be cross platform compatiable. If someone re-saves the same file from a Windows system, the logic will be broken. (Unless I were to implement something more complex which first scans the file to detect the line ending format.)
Something about this doesn't feel quite right. Perhaps someone has some advice on the best way to proceed?
To illustrate why I don't think I have a good solution to this problem, here's the current implementation I am using.
std::ifstream ifile("http_data.txt", std::ios::binary);
std::string line; // input
std::ostringstream oss; // output
while(std::getline(ifile, line)) // line ending agonstic
{
oss.write(line.c_str(), line.size());
oss.write("\r\n", 2); // line ending specific
}
In short - I don't think my approach is particuarly good. Is there a smarter way to do this?
Share asked Mar 3 at 22:23 user2138149user2138149 17.7k30 gold badges150 silver badges296 bronze badges 3 |1 Answer
Reset to default 0For such small input files, I would not care about input line ending and performance.
std::ifstream ifile("http_data.txt", std::ios::binary);
std::string data(std::istreambuf_iterator<char>{ifile}, {});
boost::replace_all(data, "\r\n", "\n");
boost::replace_all(data, "\n", "\r\n");
// data = std::regex_replace(data, std::regex("\r\n"), "\n"); // not tested
// data = std::regex_replace(data, std::regex("\n"), "\r\n"); // not tested
// Regex replace can be single: ([^\r])\n with \1\r\n, not tested
:set ff=dos
then save the file. That wil use\r\n
line endings. – Eljay Commented Mar 3 at 22:38dos2unix
andunix2dos
. – edrezen Commented Mar 3 at 22:41