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
Improvements in {get|set}_directive functions #347
Conversation
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Please see my in-line comments.
| @@ -1294,15 +1294,17 @@ def unescape_seq(seq, *args): | |||
|
|
|||
| def escape_seq(seq, *args): | |||
| """ | |||
| escape (prepend '\\') all occurences of sequence in input strings | |||
| escape (prepend '\\') all occurences of sequence in input strings unless it | |||
| is already escaped. | |||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think that the function called escape_seq should have no say in what is being escaped. Given that next commit modified get_directive to be inverse of set_directive, why is this change necessary at all?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Probably not, I was just thinking about future proofing the code. You are probably right that the function should be as dumb as possible.
| file to quote values. This character will be stripped and unescaped | ||
| from the raw value. | ||
|
|
||
| :returns: The (unquoted) value if the directive was found, None otherwise |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I know this is not originally your code but KeyError exception souds more appropriate to me (for non-existing directives)...
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I would rather not alter the function's contract in this way, who know how many callers are relying on this particular behavior. If you open a ticket for this I can do it in separate PR.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
No problem, I do not insist on this change.
| """ | ||
| fd = open(filename, "r") | ||
| for line in fd: | ||
| if line.lstrip().startswith(directive): | ||
| line = line.strip() | ||
| result = line.split(separator, 1)[1] | ||
| result = result.strip('"') | ||
| result = result.strip(quote_char) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think that this usage of strip will cause problems if the text in config file is like \"abc\". It will remove only the last " (which is incorrect anyway because " are part of the string and not quotation).
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
BTW this usage of strip does not remove any whitespace (unless quote_char is a whitespace ...) so the commit message needs correction as well.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Line 456: line = line.strip() so yes it does. The code masks this fact rather well.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Regarding stripping the quote_char, I realized that the correct thing to do is actually to first unescape all quote chars and then do the strip as this is the inverse operation of set_directive. Do you agree with such a change?.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Hmm, that depends. How is quote_char supposed to behave? Can it be used just once in each value like "this is my value" ? Or is it possible to use it as in C strings like "first" " part" "of " "string" producing string value first part of string?
Speaking of whitespace, the functions should be really inversible. Is there a reason to mock with the whitespace when reading values? (Just wondering out loud.)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thinking about it a bit more, I would argue that first use of strip() on line #347 (diff) is incorrect anyway. The code first does strip() and then split(separator, 1)[1].
What if result of split(separator, 1)[1] contains whitespace?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The way set_directive handle quote_char is that if it is present in the value-to-be added, it is escaped and then the whole value is stored:
my "quoted" value -> "my \"quoted\" value"
The get_directive should then do an inverse operation (regarding quotes, not the whitespace shenanigans).
The stripping around separator is buggy as you pointed out, the whitespace after separator is not handled correctly and breaks the following logic. I will fix that.
|
Please see my in-line comments. |
|
Please see my in-line replies to your in-line comments :). |
4b3344f
to
3de19d3
Compare
|
Can somebody take over the review of this PR please? |
| @@ -436,16 +436,31 @@ def format_directive(directive, value, separator, quotes, quote_char): | |||
| fd.close() | |||
| os.chown(filename, st.st_uid, st.st_gid) # reset perms | |||
|
|
|||
| def get_directive(filename, directive, separator=' '): | |||
|
|
|||
| def get_directive(filename, directive, separator=' ', quote_char='\"'): | |||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Is there a reason to escape the double quote in quote_char? It seems to be the same thing as '"'. It seems a bit confusing to me to use the escaped '\"'.
| @@ -134,14 +134,18 @@ def install_http_cert(self): | |||
| dirname = certs.NSS_DIR | |||
|
|
|||
| old_cert = installutils.get_directive(paths.HTTPD_NSS_CONF, | |||
| 'NSSNickname') | |||
| 'NSSNickname', quote_char="'") | |||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why is it safe to assume the NSSNickname will always be enclosed in single quotes?
mod_nss allows values to be enclosed in double quotes. If double quotes were indeed used, they'd be interpreted as a part of the value, which is not intended. It would be the exact same issue as ticket 6460, except for double quotes instead of single quotes.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
You are right. I think that I will delegate the quoting/unquoting transformations to separate functions. That will be more robust IMHO.
|
Please see my feedback in in-line comments. |
3de19d3
to
ed94035
Compare
| :returns: processed value | ||
| """ | ||
| unescaped_value = "".join(ipautil.unescape_seq(quote_char, value)) | ||
| return unescaped_value.strip(quote_char) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Using strip() causes issues when the actual value starts or ends with the same type of quote as is used to escape it, e.g. 'cn=\'ABC\'' gets unquoted to cn='ABC.
| :param directive: directive name | ||
| :param value: value of the directive | ||
| :param quotes: whether to quote `value` in `quote_char`. If true, then | ||
| the `quote_char` are first escaped to avoid unparseable directives. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Please remove reference to quote_char from comment.
| :param filename: input filename | ||
| :param directive: directive name | ||
| :param separator: separator between directive and value | ||
| :param quote_char: the characters that are used in this particular config |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Update doc here as well.
|
I still managed to find a an issue for certain edge cases. See inline comments for more info. |
ed94035
to
abc6186
Compare
|
Thanks, I have fixed the docstrings. I have also made directive unquoting less silly. |
|
I wasn't able to find any more issues with the quoting of certificate names. The directive quoting seems to work properly now. |
|
Thank's, let's hope that all this code will be replaced by some proper configuration parsing mechanism in the future. |
Add missing parameter descriptions and fix incorrect indentation https://fedorahosted.org/freeipa/ticket/6460
`get_directive` value parsing was improved in order to bring its logic more in-line to changes in `set_directive`: a specified quoting character is now unquoted and stripped from the retrieved value. The function will now also error out when malformed directive is encountered. https://fedorahosted.org/freeipa/ticket/6460
Separate functions were added to installutils module to quote/unquote a string in arbitrary characters. `installutils.get/set_directive` functions will use them to enclose the directive values in double quotes/strip the double quotes from retrieved values to maintain the original behavior. These functions can be used also for custom quoting/unquoting of retrieved values when desired. https://fedorahosted.org/freeipa/ticket/6460
Improve the single/double quote handling during parsing/unparsing of nss.conf's NSSNickname directive. Single quotes are now added/stripped explicitly when handling the certificate nickname. https://fedorahosted.org/freeipa/ticket/6460
abc6186
to
4028965
Compare
These should fix https://fedorahosted.org/freeipa/ticket/6460 and future-proof
the code a bit