nodes: 0, module; 1, function_definition; 2, function_name:get_canonical_headers; 3, parameters; 4, block; 5, identifier:headers; 6, expression_statement; 7, if_statement; 8, if_statement; 9, expression_statement; 10, for_statement; 11, expression_statement; 12, expression_statement; 13, return_statement; 14, comment:"""Canonicalize headers for signing.
  
      See:
      https://cloud.google.com/storage/docs/access-control/signed-urls#about-canonical-extension-headers
  
      :type headers: Union[dict|List(Tuple(str,str))]
      :param headers:
          (Optional) Additional HTTP headers to be included as part of the
          signed URLs.  See:
          https://cloud.google.com/storage/docs/xml-api/reference-headers
          Requests using the signed URL *must* pass the specified header
          (name and value) with each request for the URL.
  
      :rtype: str
      :returns: List of headers, normalized / sortted per the URL refernced above.
      """; 15, comparison_operator:headers is None; 16, block; 17, elif_clause; 18, not_operator; 19, block; 20, assignment; 21, pattern_list; 22, identifier:headers; 23, block; 24, assignment; 25, assignment; 26, expression_list; 27, identifier:headers; 28, None; 29, expression_statement; 30, call; 31, block; 32, identifier:headers; 33, return_statement; 34, identifier:normalized; 35, call; 36, identifier:key; 37, identifier:val; 38, expression_statement; 39, expression_statement; 40, expression_statement; 41, identifier:ordered_headers; 42, call; 43, identifier:canonical_headers; 44, list_comprehension; 45, identifier:canonical_headers; 46, identifier:ordered_headers; 47, assignment; 48, identifier:isinstance; 49, argument_list; 50, expression_statement; 51, expression_list; 52, attribute; 53, argument_list; 54, assignment; 55, assignment; 56, call; 57, identifier:sorted; 58, generator_expression; 59, call; 60, for_in_clause; 61, identifier:headers; 62, list; 63, identifier:headers; 64, identifier:dict; 65, assignment; 66, list; 67, list; 68, identifier:collections; 69, identifier:defaultdict; 70, identifier:list; 71, identifier:key; 72, call; 73, identifier:val; 74, call; 75, attribute; 76, argument_list; 77, tuple; 78, for_in_clause; 79, attribute; 80, argument_list; 81, identifier:item; 82, identifier:ordered_headers; 83, identifier:headers; 84, call; 85, attribute; 86, argument_list; 87, attribute; 88, argument_list; 89, subscript; 90, identifier:append; 91, identifier:val; 92, identifier:key; 93, call; 94, pattern_list; 95, call; 96, string:"{}:{}"; 97, identifier:format; 98, list_splat; 99, identifier:list; 100, argument_list; 101, call; 102, identifier:strip; 103, identifier:MULTIPLE_SPACES; 104, identifier:sub; 105, string:" "; 106, call; 107, identifier:normalized; 108, identifier:key; 109, attribute; 110, argument_list; 111, identifier:key; 112, identifier:val; 113, attribute; 114, argument_list; 115, identifier:item; 116, call; 117, attribute; 118, argument_list; 119, attribute; 120, argument_list; 121, string:","; 122, identifier:join; 123, identifier:val; 124, identifier:normalized; 125, identifier:items; 126, attribute; 127, argument_list; 128, identifier:key; 129, identifier:lower; 130, identifier:val; 131, identifier:strip; 132, identifier:headers; 133, identifier:items
code: def get_canonical_headers(headers):
      """Canonicalize headers for signing.
  
      See:
      https://cloud.google.com/storage/docs/access-control/signed-urls#about-canonical-extension-headers
  
      :type headers: Union[dict|List(Tuple(str,str))]
      :param headers:
          (Optional) Additional HTTP headers to be included as part of the
          signed URLs.  See:
          https://cloud.google.com/storage/docs/xml-api/reference-headers
          Requests using the signed URL *must* pass the specified header
          (name and value) with each request for the URL.
  
      :rtype: str
      :returns: List of headers, normalized / sortted per the URL refernced above.
      """
      if headers is None:
          headers = []
      elif isinstance(headers, dict):
          headers = list(headers.items())
  
      if not headers:
          return [], []
  
      normalized = collections.defaultdict(list)
      for key, val in headers:
          key = key.lower().strip()
          val = MULTIPLE_SPACES.sub(" ", val.strip())
          normalized[key].append(val)
  
      ordered_headers = sorted((key, ",".join(val)) for key, val in normalized.items())
  
      canonical_headers = ["{}:{}".format(*item) for item in ordered_headers]
      return canonical_headers, ordered_headers