Skip to content
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

Closed
wants to merge 4 commits into from

Conversation

martbab
Copy link
Contributor

@martbab martbab commented Dec 16, 2016

These should fix https://fedorahosted.org/freeipa/ticket/6460 and future-proof
the code a bit

Copy link
Contributor

@pspacek pspacek left a 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.
Copy link
Contributor

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?

Copy link
Contributor Author

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
Copy link
Contributor

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)...

Copy link
Contributor Author

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.

Copy link
Contributor

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)
Copy link
Contributor

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).

Copy link
Contributor

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.

Copy link
Contributor Author

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.

Copy link
Contributor Author

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?.

Copy link
Contributor

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.)

Copy link
Contributor

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?

Copy link
Contributor Author

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.

@pspacek
Copy link
Contributor

pspacek commented Dec 19, 2016

Please see my in-line comments.

@martbab
Copy link
Contributor Author

martbab commented Dec 20, 2016

Please see my in-line replies to your in-line comments :).

@martbab
Copy link
Contributor Author

martbab commented Jan 3, 2017

Can somebody take over the review of this PR please?

@tkrizek tkrizek self-assigned this Jan 3, 2017
@@ -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='\"'):
Copy link
Contributor

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="'")
Copy link
Contributor

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.

Copy link
Contributor Author

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.

@tkrizek
Copy link
Contributor

tkrizek commented Jan 9, 2017

Please see my feedback in in-line comments.

:returns: processed value
"""
unescaped_value = "".join(ipautil.unescape_seq(quote_char, value))
return unescaped_value.strip(quote_char)
Copy link
Contributor

@tkrizek tkrizek Jan 17, 2017

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.
Copy link
Contributor

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
Copy link
Contributor

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.

@tkrizek
Copy link
Contributor

tkrizek commented Jan 17, 2017

I still managed to find a an issue for certain edge cases. See inline comments for more info.

@martbab
Copy link
Contributor Author

martbab commented Jan 17, 2017

Thanks, I have fixed the docstrings. I have also made directive unquoting less silly.

@tkrizek
Copy link
Contributor

tkrizek commented Jan 24, 2017

I wasn't able to find any more issues with the quoting of certificate names. The directive quoting seems to work properly now.

@tkrizek tkrizek added the ack Pull Request approved, can be merged label Jan 24, 2017
@martbab
Copy link
Contributor Author

martbab commented Jan 25, 2017

Thank's, let's hope that all this code will be replaced by some proper configuration parsing mechanism in the future.

Martin Babinsky added 4 commits January 25, 2017 13:49
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
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
ack Pull Request approved, can be merged pushed Pull Request has already been pushed
Projects
None yet
3 participants