-
Notifications
You must be signed in to change notification settings - Fork 2.4k
Whitespace trimming and libc++ compatibility workaround #280
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Conversation
@matvore, thanks for the contribution. I just took a look at the code a little bit. But I found that all the examples in example/ directory cannot be built anymore. This is due to the gtest #ifndef FRIEND_TEST
#define FRIEND_TEST(a, b)
#endif Personally, I don't want to have this kind of code in httplib.h, because that is not directly related to the httplib.h functionalities. I understand that you wanted to test the private methods, but I just wonder if we could do so without touching httplib.h itself. I am thinking to make a test HTTP client class which feeds the bad test data described in your test cases. Anyway, thank you for finding the bug and showing the excellent solution! |
HTTP Whitespace and regex whitespace are not the same, so we can't use \s in regexes when parsing HTTP headers. Instead, explicitly specify what is considered whitespace in the regex.
libc++ (the implementation of the C++ standard library usually used by Clang) throws an exception for the regex used by parse_headers before this patch for certain strings. Work around this by simplifying the regex and parsing the header lines "by hand" partially. I have repro'd this problem with Xcode 11.1 which I believe uses libc++ version 8. This may be a bug in libc++ as I can't see why the regex would result in asymptotic run-time complexity for any strings. However, it may take a while for libc++ to be fixed and for everyone to migrate to it, so it makes sense to work around it in this codebase for now.
5d6f2cf
to
bc9251e
Compare
I've pushed a new version. This is more black-box, as you suggested. I do agree this is a better approach. However, I did expose some socket-creation logic - once internal to the Client class - so that it could be used in tests to trigger requests. Note that I didn't create a test-Client class, but I did try to keep the redundant boilerplate to a reasonable amount. |
@matvore, great! After I merged it, I made some changes to make it a bit more readable. Thanks for your contribution! |
Thanks for the review :) |
The regex that parses header lines potentially causes an unlimited amount of backtracking, which can cause an exception in the libc++ regex engine. The exception that occurs looks like this and is identical to the message of the exception fixed in yhirose#280: libc++abi.dylib: terminating with uncaught exception of type std::__1::regex_error: The complexity of an attempted match against a regular expression exceeded a pre-set level. This commit eliminates the problematic backtracking.
The regex that parses header lines potentially causes an unlimited amount of backtracking, which can cause an exception in the libc++ regex engine. The exception that occurs looks like this and is identical to the message of the exception fixed in #280: libc++abi.dylib: terminating with uncaught exception of type std::__1::regex_error: The complexity of an attempted match against a regular expression exceeded a pre-set level. This commit eliminates the problematic backtracking.
The regex that parses header lines potentially causes an unlimited amount of backtracking, which can cause an exception in the libc++ regex engine. The exception that occurs looks like this and is identical to the message of the exception fixed in #280: libc++abi.dylib: terminating with uncaught exception of type std::__1::regex_error: The complexity of an attempted match against a regular expression exceeded a pre-set level. This commit eliminates the problematic backtracking.
The regex that parses header lines potentially causes an unlimited amount of backtracking, which can cause an exception in the libc++ regex engine. The exception that occurs looks like this and is identical to the message of the exception fixed in yhirose/cpp-httplib#280: libc++abi.dylib: terminating with uncaught exception of type std::__1::regex_error: The complexity of an attempted match against a regular expression exceeded a pre-set level. This commit eliminates the problematic backtracking.
The regex that parses header lines potentially causes an unlimited amount of backtracking, which can cause an exception in the libc++ regex engine. The exception that occurs looks like this and is identical to the message of the exception fixed in yhirose#280: libc++abi.dylib: terminating with uncaught exception of type std::__1::regex_error: The complexity of an attempted match against a regular expression exceeded a pre-set level. This commit eliminates the problematic backtracking.
I found a crashing bug when sending malformed input to the header-parsing code. It is particular to libc++ (i.e. it doesn't repro with other std C++ library implementations)
The exact error I saw was:
libc++abi.dylib: terminating with uncaught exception of type std::__1::regex_error: The complexity of an attempted match against a regular expression exceeded a pre-set level.
Abort trap: 6