The little things give you away... A collection of various small helper stuff
25'ten fazla konu seçemezsiniz Konular bir harf veya rakamla başlamalı, kısa çizgiler ('-') içerebilir ve en fazla 35 karakter uzunluğunda olabilir.
 
 
 

115 satır
3.8 KiB

  1. #!/usr/bin/env python3
  2. import html
  3. import http.client
  4. import os
  5. import shlex
  6. import ssl
  7. import sys
  8. import urllib.parse
  9. # Arguments
  10. i = 1
  11. withListUrls = False
  12. listUrlsFD = None
  13. startMarker = None
  14. format = '{url}'
  15. args = []
  16. while i < len(sys.argv):
  17. arg = sys.argv[i]
  18. if arg == '--help':
  19. print('azure-storage-list [options] CONTAINERURL', file = sys.stderr)
  20. print('', file = sys.stderr)
  21. print('Options:', file = sys.stderr)
  22. print(f' --format FORMAT Modify the output format; FORMAT defaults to {format!r}; available fields: name, url, and all fields returned by Azure (e.g. Content-Length, Last-Modified)', file = sys.stderr)
  23. print( ' --marker MARKER Start with a marker instead of from the beginning', file = sys.stderr)
  24. print( ' --with-list-urls Enables printing the list URLs retrieved to FD 3', file = sys.stderr)
  25. sys.exit(1)
  26. elif arg == '--with-list-urls':
  27. withListUrls = True
  28. try:
  29. listUrlsFD = os.fdopen(3, 'w')
  30. except OSError:
  31. print('Error: FD 3 not open', file = sys.stderr)
  32. sys.exit(1)
  33. elif arg == '--marker':
  34. startMarker = sys.argv[i + 1]
  35. i += 1
  36. elif arg == '--format':
  37. format = sys.argv[i + 1]
  38. i += 1
  39. else:
  40. args.append(arg)
  41. i += 1
  42. assert len(args) == 1, 'Need one argument: container URL'
  43. baseUrl = args[0]
  44. assert baseUrl.startswith('http://') or baseUrl.startswith('https://'), 'Argument does not look like an HTTP URL'
  45. if '/' not in baseUrl.split('://', 1)[1] or not baseUrl.endswith('/'):
  46. baseUrl = f'{baseUrl}/'
  47. hostname = baseUrl.split('://', 1)[1].split('/', 1)[0]
  48. conn = http.client.HTTPSConnection(hostname, context = ssl._create_unverified_context())
  49. params = {'restype': 'container', 'comp': 'list'}
  50. if startMarker is not None:
  51. params['marker'] = startMarker
  52. while True:
  53. queryString = urllib.parse.urlencode(params)
  54. url = f'{baseUrl}?{queryString}'
  55. if withListUrls:
  56. print(f'{url}', file = listUrlsFD)
  57. conn.request('GET', url[url.index('/', 8):])
  58. resp = conn.getresponse()
  59. body = resp.read()
  60. if not body.startswith(b'\xef\xbb\xbf<?xml version="1.0" encoding="utf-8"?><EnumerationResults ContainerName="'):
  61. raise RuntimeError(f'Invalid body: {body[:200]}...')
  62. if b'<Marker>' not in body[:200] and 'marker' in params:
  63. raise RuntimeError('Marker loop (no marker in response despite providing one)')
  64. # No risk, no fun!
  65. blobs = body.split(b'<Blob>')
  66. assert all(blob.startswith(b'<Name>') for blob in blobs[1:])
  67. assert all(blob.endswith(b'</Blob>') for blob in blobs[1:-1])
  68. assert b'</Blobs>' in blobs[-1] and blobs[-1].endswith(b'</EnumerationResults>')
  69. blobs[-1], ending = blobs[-1].split(b'</Blobs>')
  70. assert b'<NextMarker' in ending
  71. for blob in blobs[1:]:
  72. name = html.unescape(blob[6 : blob.index(b'</Name>')].decode('utf-8')) # 6 = len(b'<Name>')
  73. url = f'{baseUrl}{urllib.parse.quote(name)}'
  74. tags = blob.split(b'>')
  75. assert tags[-1] == b''
  76. assert tags[-2] == b'</Blob'
  77. assert tags[-3] == b'</Properties'
  78. assert b'<Properties' in tags
  79. openTags = [] # Current open tag hierarchy
  80. fields = {}
  81. for tag in tags[:-3]:
  82. if tag == b'<Properties':
  83. continue
  84. if tag.endswith(b' /'): # Self-closing tag without a value
  85. continue
  86. if tag.startswith(b'<'):
  87. openTags.append(tag[1:])
  88. continue
  89. assert openTags
  90. if tag.endswith(b'</' + openTags[-1]):
  91. fields[b'>'.join(openTags).decode('utf-8')] = html.unescape(tag[:-(len(openTags[-1]) + 2)].decode('utf-8'))
  92. openTags.pop()
  93. continue
  94. assert False
  95. try:
  96. print(format.format(**fields, name = name, url = url))
  97. except BrokenPipeError:
  98. sys.exit(0)
  99. if b'<NextMarker />' in ending:
  100. break
  101. nextMarkerStart = ending.index(b'<NextMarker>')
  102. nextMarker = ending[nextMarkerStart + 12 : ending.index(b'</NextMarker', nextMarkerStart)]
  103. if 'marker' in params and params['marker'] == nextMarker:
  104. raise RuntimeError('Marker loop (same NextMarker as previous marker)')
  105. params['marker'] = nextMarker.decode('utf-8')