[tor-commits] [stem/master] Parsing the known-flags attribute

atagar at torproject.org atagar at torproject.org
Sat Oct 13 18:35:45 UTC 2012


commit 0e4f8bfbdcf1bc9e427748dd37b53ad6b4a32d93
Author: Damian Johnson <atagar at torproject.org>
Date:   Sun Sep 9 15:13:32 2012 -0700

    Parsing the known-flags attribute
    
    Only changes are...
    
    * Moving the Flag enum to stem.descriptor.Flag since it's something that users
      will commonly use. As a rule of thumb I'd like users to only need
      'stem.descriptor' unless they're doing something fancy. However, this is just
      a temporary move - I plan to move Flag to is own module, like Version.
    
    * Excluding empty strings from our known_flags attribute (our prior behavior
      was to parse things like "   " into ['', '', '', '']). The spec doesn't set
      any constraints on what a flag can be so I suppose technically one could be
      the empty string, though this'll never be the case. Still waffling back and
      forth about if this should cause a validation error or not...
---
 stem/descriptor/__init__.py                    |   17 +++++++++++++++
 stem/descriptor/networkstatus.py               |   27 +++++------------------
 test/integ/descriptor/networkstatus.py         |    3 +-
 test/unit/descriptor/networkstatus/document.py |   24 ++++++++++++++++++++-
 test/unit/descriptor/networkstatus/entry.py    |    3 +-
 5 files changed, 50 insertions(+), 24 deletions(-)

diff --git a/stem/descriptor/__init__.py b/stem/descriptor/__init__.py
index 688e1b6..b921058 100644
--- a/stem/descriptor/__init__.py
+++ b/stem/descriptor/__init__.py
@@ -27,12 +27,29 @@ import re
 import datetime
 import collections
 
+import stem.util.enum
+
 KEYWORD_CHAR    = "a-zA-Z0-9-"
 WHITESPACE      = " \t"
 KEYWORD_LINE    = re.compile("^([%s]+)(?:[%s]+(.*))?$" % (KEYWORD_CHAR, WHITESPACE))
 PGP_BLOCK_START = re.compile("^-----BEGIN ([%s%s]+)-----$" % (KEYWORD_CHAR, WHITESPACE))
 PGP_BLOCK_END   = "-----END %s-----"
 
+Flag = stem.util.enum.Enum(
+  ("AUTHORITY", "Authority"),
+  ("BADEXIT", "BadExit"),
+  ("EXIT", "Exit"),
+  ("FAST", "Fast"),
+  ("GUARD", "Guard"),
+  ("HSDIR", "HSDir"),
+  ("NAMED", "Named"),
+  ("RUNNING", "Running"),
+  ("STABLE", "Stable"),
+  ("UNNAMED", "Unnamed"),
+  ("V2DIR", "V2Dir"),
+  ("VALID", "Valid"),
+)
+
 def parse_file(path, descriptor_file):
   """
   Provides an iterator for the descriptors within a given file.
diff --git a/stem/descriptor/networkstatus.py b/stem/descriptor/networkstatus.py
index eca3b71..beafe89 100644
--- a/stem/descriptor/networkstatus.py
+++ b/stem/descriptor/networkstatus.py
@@ -52,7 +52,6 @@ except:
 import stem.descriptor
 import stem.version
 import stem.exit_policy
-import stem.util.enum
 import stem.util.tor_tools
 
 from stem.descriptor import _read_until_keywords, _peek_keyword, _strptime
@@ -61,21 +60,6 @@ from stem.descriptor import _read_keyword_line, _read_keyword_line_str, _get_pse
 _bandwidth_weights_regex = re.compile(" ".join(["W%s=\d+" % weight for weight in ["bd",
   "be", "bg", "bm", "db", "eb", "ed", "ee", "eg", "em", "gb", "gd", "gg", "gm", "mb", "md", "me", "mg", "mm"]]))
 
-Flag = stem.util.enum.Enum(
-  ("AUTHORITY", "Authority"),
-  ("BADEXIT", "BadExit"),
-  ("EXIT", "Exit"),
-  ("FAST", "Fast"),
-  ("GUARD", "Guard"),
-  ("HSDIR", "HSDir"),
-  ("NAMED", "Named"),
-  ("RUNNING", "Running"),
-  ("STABLE", "Stable"),
-  ("UNNAMED", "Unnamed"),
-  ("V2DIR", "V2Dir"),
-  ("VALID", "Valid"),
-)
-
 # Network status document are either a 'vote' or 'consensus', with different
 # mandatory fields for each. Both though require that their fields appear in a
 # specific order. This is an ordered listing of the following...
@@ -383,6 +367,11 @@ class NetworkStatusDocument(stem.descriptor.Descriptor):
           except ValueError:
             if validate:
               raise ValueError("Network status document's '%s' line had '%s', which isn't a parseable tor version: %s" % (keyword, entry, line))
+      elif keyword == "known-flags":
+        # "known-flags" FlagList
+        
+        # simply fetches the entries, excluding empty strings
+        self.known_flags = [entry for entry in value.split(" ") if entry]
     
     # doing this validation afterward so we know our 'is_consensus' and
     # 'is_vote' attributes
@@ -408,14 +397,10 @@ class NetworkStatusDocument(stem.descriptor.Descriptor):
     _read_keyword_line("voting-delay", content, False, True)
     _read_keyword_line("client-versions", content, False, True)
     _read_keyword_line("server-versions", content, False, True)
+    _read_keyword_line("known-flags", content, False, True)
     
     vote = self.is_vote
     
-    flags_content = _read_keyword_line("known-flags", content, validate)
-    
-    if flags_content:
-      self.known_flags = flags_content.split(" ")
-    
     read_keyword_line("params", True)
     if self.params:
       self.params = dict([(param.split("=")[0], int(param.split("=")[1])) for param in self.params.split(" ")])
diff --git a/test/integ/descriptor/networkstatus.py b/test/integ/descriptor/networkstatus.py
index 9087b22..d77a36f 100644
--- a/test/integ/descriptor/networkstatus.py
+++ b/test/integ/descriptor/networkstatus.py
@@ -11,6 +11,7 @@ import unittest
 
 import stem.exit_policy
 import stem.version
+import stem.descriptor
 import stem.descriptor.networkstatus
 import test.integ.descriptor
 
@@ -47,7 +48,7 @@ class TestNetworkStatus(unittest.TestCase):
         
         # check if there's any unknown flags
         for flag in desc.flags:
-          if not flag in stem.descriptor.networkstatus.Flag:
+          if not flag in stem.descriptor.Flag:
             # TODO: this should be a special 'new capability' check later
             # rather than failing the tests
             raise ValueError("Unrecognized flag type: %s, found on relay %s (%s)" % (flag, desc.fingerprint, desc.nickname))
diff --git a/test/unit/descriptor/networkstatus/document.py b/test/unit/descriptor/networkstatus/document.py
index 032c095..5e3ec4b 100644
--- a/test/unit/descriptor/networkstatus/document.py
+++ b/test/unit/descriptor/networkstatus/document.py
@@ -6,7 +6,8 @@ import datetime
 import unittest
 
 import stem.version
-from stem.descriptor.networkstatus import HEADER_STATUS_DOCUMENT_FIELDS, FOOTER_STATUS_DOCUMENT_FIELDS, Flag, NetworkStatusDocument, DirectorySignature
+from stem.descriptor import Flag
+from stem.descriptor.networkstatus import HEADER_STATUS_DOCUMENT_FIELDS, FOOTER_STATUS_DOCUMENT_FIELDS, NetworkStatusDocument, DirectorySignature
 
 NETWORK_STATUS_DOCUMENT_ATTR = {
   "network-status-version": "3",
@@ -354,4 +355,25 @@ class TestNetworkStatusDocument(unittest.TestCase):
         
         document = NetworkStatusDocument(content, False)
         self.assertEquals(expected_value, getattr(document, attr))
+  
+  def test_known_flags(self):
+    """
+    Parses some known-flag entries. Just exercising the field, there's not much
+    to test here.
+    """
+    
+    test_values = (
+      ("", []),
+      ("   ", []),
+      ("BadExit", [Flag.BADEXIT]),
+      ("BadExit ", [Flag.BADEXIT]),
+      ("BadExit   ", [Flag.BADEXIT]),
+      ("BadExit Fast", [Flag.BADEXIT, Flag.FAST]),
+      ("BadExit Unrecognized Fast", [Flag.BADEXIT, "Unrecognized", Flag.FAST]),
+    )
+    
+    for test_value, expected_value in test_values:
+      content = get_network_status_document({"known-flags": test_value})
+      document = NetworkStatusDocument(content)
+      self.assertEquals(expected_value, document.known_flags)
 
diff --git a/test/unit/descriptor/networkstatus/entry.py b/test/unit/descriptor/networkstatus/entry.py
index 195600c..7c9e051 100644
--- a/test/unit/descriptor/networkstatus/entry.py
+++ b/test/unit/descriptor/networkstatus/entry.py
@@ -5,7 +5,8 @@ Unit tests for the RouterStatusEntry of stem.descriptor.networkstatus.
 import datetime
 import unittest
 
-from stem.descriptor.networkstatus import Flag, RouterStatusEntry, _decode_fingerprint
+from stem.descriptor import Flag
+from stem.descriptor.networkstatus import RouterStatusEntry, _decode_fingerprint
 from stem.version import Version
 from stem.exit_policy import MicrodescriptorExitPolicy
 





More information about the tor-commits mailing list