swift 2.23.3__py3-none-any.whl → 2.35.0__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (206) hide show
  1. swift/__init__.py +29 -50
  2. swift/account/auditor.py +21 -118
  3. swift/account/backend.py +33 -28
  4. swift/account/reaper.py +37 -28
  5. swift/account/replicator.py +22 -0
  6. swift/account/server.py +60 -26
  7. swift/account/utils.py +28 -11
  8. swift-2.23.3.data/scripts/swift-account-audit → swift/cli/account_audit.py +23 -13
  9. swift-2.23.3.data/scripts/swift-config → swift/cli/config.py +2 -2
  10. swift/cli/container_deleter.py +5 -11
  11. swift-2.23.3.data/scripts/swift-dispersion-populate → swift/cli/dispersion_populate.py +8 -7
  12. swift/cli/dispersion_report.py +10 -9
  13. swift-2.23.3.data/scripts/swift-drive-audit → swift/cli/drive_audit.py +63 -21
  14. swift/cli/form_signature.py +3 -7
  15. swift-2.23.3.data/scripts/swift-get-nodes → swift/cli/get_nodes.py +8 -2
  16. swift/cli/info.py +154 -14
  17. swift/cli/manage_shard_ranges.py +705 -37
  18. swift-2.23.3.data/scripts/swift-oldies → swift/cli/oldies.py +25 -14
  19. swift-2.23.3.data/scripts/swift-orphans → swift/cli/orphans.py +7 -3
  20. swift/cli/recon.py +196 -67
  21. swift-2.23.3.data/scripts/swift-recon-cron → swift/cli/recon_cron.py +17 -20
  22. swift-2.23.3.data/scripts/swift-reconciler-enqueue → swift/cli/reconciler_enqueue.py +2 -3
  23. swift/cli/relinker.py +807 -126
  24. swift/cli/reload.py +135 -0
  25. swift/cli/ringbuilder.py +217 -20
  26. swift/cli/ringcomposer.py +0 -1
  27. swift/cli/shard-info.py +4 -3
  28. swift/common/base_storage_server.py +9 -20
  29. swift/common/bufferedhttp.py +48 -74
  30. swift/common/constraints.py +20 -15
  31. swift/common/container_sync_realms.py +9 -11
  32. swift/common/daemon.py +25 -8
  33. swift/common/db.py +195 -128
  34. swift/common/db_auditor.py +168 -0
  35. swift/common/db_replicator.py +95 -55
  36. swift/common/digest.py +141 -0
  37. swift/common/direct_client.py +144 -33
  38. swift/common/error_limiter.py +93 -0
  39. swift/common/exceptions.py +25 -1
  40. swift/common/header_key_dict.py +2 -9
  41. swift/common/http_protocol.py +373 -0
  42. swift/common/internal_client.py +129 -59
  43. swift/common/linkat.py +3 -4
  44. swift/common/manager.py +284 -67
  45. swift/common/memcached.py +390 -145
  46. swift/common/middleware/__init__.py +4 -0
  47. swift/common/middleware/account_quotas.py +211 -46
  48. swift/common/middleware/acl.py +3 -8
  49. swift/common/middleware/backend_ratelimit.py +230 -0
  50. swift/common/middleware/bulk.py +22 -34
  51. swift/common/middleware/catch_errors.py +1 -3
  52. swift/common/middleware/cname_lookup.py +6 -11
  53. swift/common/middleware/container_quotas.py +1 -1
  54. swift/common/middleware/container_sync.py +39 -17
  55. swift/common/middleware/copy.py +12 -0
  56. swift/common/middleware/crossdomain.py +22 -9
  57. swift/common/middleware/crypto/__init__.py +2 -1
  58. swift/common/middleware/crypto/crypto_utils.py +11 -15
  59. swift/common/middleware/crypto/decrypter.py +28 -11
  60. swift/common/middleware/crypto/encrypter.py +12 -17
  61. swift/common/middleware/crypto/keymaster.py +8 -15
  62. swift/common/middleware/crypto/kms_keymaster.py +2 -1
  63. swift/common/middleware/dlo.py +15 -11
  64. swift/common/middleware/domain_remap.py +5 -4
  65. swift/common/middleware/etag_quoter.py +128 -0
  66. swift/common/middleware/formpost.py +73 -70
  67. swift/common/middleware/gatekeeper.py +8 -1
  68. swift/common/middleware/keystoneauth.py +33 -3
  69. swift/common/middleware/list_endpoints.py +4 -4
  70. swift/common/middleware/listing_formats.py +85 -49
  71. swift/common/middleware/memcache.py +4 -95
  72. swift/common/middleware/name_check.py +3 -2
  73. swift/common/middleware/proxy_logging.py +160 -92
  74. swift/common/middleware/ratelimit.py +17 -10
  75. swift/common/middleware/read_only.py +6 -4
  76. swift/common/middleware/recon.py +59 -22
  77. swift/common/middleware/s3api/acl_handlers.py +25 -3
  78. swift/common/middleware/s3api/acl_utils.py +6 -1
  79. swift/common/middleware/s3api/controllers/__init__.py +6 -0
  80. swift/common/middleware/s3api/controllers/acl.py +3 -2
  81. swift/common/middleware/s3api/controllers/bucket.py +242 -137
  82. swift/common/middleware/s3api/controllers/logging.py +2 -2
  83. swift/common/middleware/s3api/controllers/multi_delete.py +43 -20
  84. swift/common/middleware/s3api/controllers/multi_upload.py +219 -133
  85. swift/common/middleware/s3api/controllers/obj.py +112 -8
  86. swift/common/middleware/s3api/controllers/object_lock.py +44 -0
  87. swift/common/middleware/s3api/controllers/s3_acl.py +2 -2
  88. swift/common/middleware/s3api/controllers/tagging.py +57 -0
  89. swift/common/middleware/s3api/controllers/versioning.py +36 -7
  90. swift/common/middleware/s3api/etree.py +22 -9
  91. swift/common/middleware/s3api/exception.py +0 -4
  92. swift/common/middleware/s3api/s3api.py +113 -41
  93. swift/common/middleware/s3api/s3request.py +384 -218
  94. swift/common/middleware/s3api/s3response.py +126 -23
  95. swift/common/middleware/s3api/s3token.py +16 -17
  96. swift/common/middleware/s3api/schema/delete.rng +1 -1
  97. swift/common/middleware/s3api/subresource.py +7 -10
  98. swift/common/middleware/s3api/utils.py +27 -10
  99. swift/common/middleware/slo.py +665 -358
  100. swift/common/middleware/staticweb.py +64 -37
  101. swift/common/middleware/symlink.py +51 -18
  102. swift/common/middleware/tempauth.py +76 -58
  103. swift/common/middleware/tempurl.py +191 -173
  104. swift/common/middleware/versioned_writes/__init__.py +51 -0
  105. swift/common/middleware/{versioned_writes.py → versioned_writes/legacy.py} +27 -26
  106. swift/common/middleware/versioned_writes/object_versioning.py +1482 -0
  107. swift/common/middleware/x_profile/exceptions.py +1 -4
  108. swift/common/middleware/x_profile/html_viewer.py +18 -19
  109. swift/common/middleware/x_profile/profile_model.py +1 -2
  110. swift/common/middleware/xprofile.py +10 -10
  111. swift-2.23.3.data/scripts/swift-container-server → swift/common/recon.py +13 -8
  112. swift/common/registry.py +147 -0
  113. swift/common/request_helpers.py +324 -57
  114. swift/common/ring/builder.py +67 -25
  115. swift/common/ring/composite_builder.py +1 -1
  116. swift/common/ring/ring.py +177 -51
  117. swift/common/ring/utils.py +1 -1
  118. swift/common/splice.py +10 -6
  119. swift/common/statsd_client.py +205 -0
  120. swift/common/storage_policy.py +49 -44
  121. swift/common/swob.py +86 -102
  122. swift/common/{utils.py → utils/__init__.py} +2163 -2772
  123. swift/common/utils/base.py +131 -0
  124. swift/common/utils/config.py +433 -0
  125. swift/common/utils/ipaddrs.py +256 -0
  126. swift/common/utils/libc.py +345 -0
  127. swift/common/utils/logs.py +859 -0
  128. swift/common/utils/timestamp.py +412 -0
  129. swift/common/wsgi.py +553 -535
  130. swift/container/auditor.py +14 -100
  131. swift/container/backend.py +490 -231
  132. swift/container/reconciler.py +126 -37
  133. swift/container/replicator.py +96 -22
  134. swift/container/server.py +358 -165
  135. swift/container/sharder.py +1540 -684
  136. swift/container/sync.py +94 -88
  137. swift/container/updater.py +53 -32
  138. swift/obj/auditor.py +153 -35
  139. swift/obj/diskfile.py +466 -217
  140. swift/obj/expirer.py +406 -124
  141. swift/obj/mem_diskfile.py +7 -4
  142. swift/obj/mem_server.py +1 -0
  143. swift/obj/reconstructor.py +523 -262
  144. swift/obj/replicator.py +249 -188
  145. swift/obj/server.py +207 -122
  146. swift/obj/ssync_receiver.py +145 -85
  147. swift/obj/ssync_sender.py +113 -54
  148. swift/obj/updater.py +652 -139
  149. swift/obj/watchers/__init__.py +0 -0
  150. swift/obj/watchers/dark_data.py +213 -0
  151. swift/proxy/controllers/account.py +11 -11
  152. swift/proxy/controllers/base.py +848 -604
  153. swift/proxy/controllers/container.py +433 -92
  154. swift/proxy/controllers/info.py +3 -2
  155. swift/proxy/controllers/obj.py +1000 -489
  156. swift/proxy/server.py +185 -112
  157. {swift-2.23.3.dist-info → swift-2.35.0.dist-info}/AUTHORS +58 -11
  158. {swift-2.23.3.dist-info → swift-2.35.0.dist-info}/METADATA +51 -56
  159. swift-2.35.0.dist-info/RECORD +201 -0
  160. {swift-2.23.3.dist-info → swift-2.35.0.dist-info}/WHEEL +1 -1
  161. {swift-2.23.3.dist-info → swift-2.35.0.dist-info}/entry_points.txt +43 -0
  162. swift-2.35.0.dist-info/pbr.json +1 -0
  163. swift/locale/de/LC_MESSAGES/swift.po +0 -1216
  164. swift/locale/en_GB/LC_MESSAGES/swift.po +0 -1207
  165. swift/locale/es/LC_MESSAGES/swift.po +0 -1085
  166. swift/locale/fr/LC_MESSAGES/swift.po +0 -909
  167. swift/locale/it/LC_MESSAGES/swift.po +0 -894
  168. swift/locale/ja/LC_MESSAGES/swift.po +0 -965
  169. swift/locale/ko_KR/LC_MESSAGES/swift.po +0 -964
  170. swift/locale/pt_BR/LC_MESSAGES/swift.po +0 -881
  171. swift/locale/ru/LC_MESSAGES/swift.po +0 -891
  172. swift/locale/tr_TR/LC_MESSAGES/swift.po +0 -832
  173. swift/locale/zh_CN/LC_MESSAGES/swift.po +0 -833
  174. swift/locale/zh_TW/LC_MESSAGES/swift.po +0 -838
  175. swift-2.23.3.data/scripts/swift-account-auditor +0 -23
  176. swift-2.23.3.data/scripts/swift-account-info +0 -51
  177. swift-2.23.3.data/scripts/swift-account-reaper +0 -23
  178. swift-2.23.3.data/scripts/swift-account-replicator +0 -34
  179. swift-2.23.3.data/scripts/swift-account-server +0 -23
  180. swift-2.23.3.data/scripts/swift-container-auditor +0 -23
  181. swift-2.23.3.data/scripts/swift-container-info +0 -55
  182. swift-2.23.3.data/scripts/swift-container-reconciler +0 -21
  183. swift-2.23.3.data/scripts/swift-container-replicator +0 -34
  184. swift-2.23.3.data/scripts/swift-container-sharder +0 -37
  185. swift-2.23.3.data/scripts/swift-container-sync +0 -23
  186. swift-2.23.3.data/scripts/swift-container-updater +0 -23
  187. swift-2.23.3.data/scripts/swift-dispersion-report +0 -24
  188. swift-2.23.3.data/scripts/swift-form-signature +0 -20
  189. swift-2.23.3.data/scripts/swift-init +0 -119
  190. swift-2.23.3.data/scripts/swift-object-auditor +0 -29
  191. swift-2.23.3.data/scripts/swift-object-expirer +0 -33
  192. swift-2.23.3.data/scripts/swift-object-info +0 -60
  193. swift-2.23.3.data/scripts/swift-object-reconstructor +0 -33
  194. swift-2.23.3.data/scripts/swift-object-relinker +0 -41
  195. swift-2.23.3.data/scripts/swift-object-replicator +0 -37
  196. swift-2.23.3.data/scripts/swift-object-server +0 -27
  197. swift-2.23.3.data/scripts/swift-object-updater +0 -23
  198. swift-2.23.3.data/scripts/swift-proxy-server +0 -23
  199. swift-2.23.3.data/scripts/swift-recon +0 -24
  200. swift-2.23.3.data/scripts/swift-ring-builder +0 -24
  201. swift-2.23.3.data/scripts/swift-ring-builder-analyzer +0 -22
  202. swift-2.23.3.data/scripts/swift-ring-composer +0 -22
  203. swift-2.23.3.dist-info/RECORD +0 -220
  204. swift-2.23.3.dist-info/pbr.json +0 -1
  205. {swift-2.23.3.dist-info → swift-2.35.0.dist-info}/LICENSE +0 -0
  206. {swift-2.23.3.dist-info → swift-2.35.0.dist-info}/top_level.txt +0 -0
@@ -36,7 +36,7 @@ from swift.common.utils import get_logger, config_true_value
36
36
  from swift.common.request_helpers import (
37
37
  remove_items, get_sys_meta_prefix, OBJECT_TRANSIENT_SYSMETA_PREFIX
38
38
  )
39
- from six.moves.urllib.parse import urlsplit
39
+ from urllib.parse import urlsplit
40
40
  import re
41
41
 
42
42
  #: A list of python regular expressions that will be used to
@@ -75,6 +75,8 @@ class GatekeeperMiddleware(object):
75
75
  self.outbound_condition = make_exclusion_test(outbound_exclusions)
76
76
  self.shunt_x_timestamp = config_true_value(
77
77
  conf.get('shunt_inbound_x_timestamp', 'true'))
78
+ self.allow_reserved_names_header = config_true_value(
79
+ conf.get('allow_reserved_names_header', 'false'))
78
80
 
79
81
  def __call__(self, env, start_response):
80
82
  req = Request(env)
@@ -89,6 +91,11 @@ class GatekeeperMiddleware(object):
89
91
  self.logger.debug('shunted request headers: %s' %
90
92
  [('X-Timestamp', ts)])
91
93
 
94
+ if 'X-Allow-Reserved-Names' in req.headers \
95
+ and self.allow_reserved_names_header:
96
+ req.headers['X-Backend-Allow-Reserved-Names'] = \
97
+ req.headers.pop('X-Allow-Reserved-Names')
98
+
92
99
  def gatekeeper_response(status, response_headers, exc_info=None):
93
100
  def fixed_response_headers():
94
101
  def relative_path(value):
@@ -178,9 +178,13 @@ class KeystoneAuth(object):
178
178
  config_read_reseller_options(conf,
179
179
  dict(operator_roles=['admin',
180
180
  'swiftoperator'],
181
- service_roles=[]))
181
+ service_roles=[],
182
+ project_reader_roles=[]))
182
183
  self.reseller_admin_role = conf.get('reseller_admin_role',
183
184
  'ResellerAdmin').lower()
185
+ self.system_reader_roles = {role.lower() for role in list_from_csv(
186
+ conf.get('system_reader_roles', ''))}
187
+
184
188
  config_is_admin = conf.get('is_admin', "false").lower()
185
189
  if swift_utils.config_true_value(config_is_admin):
186
190
  self.logger.warning("The 'is_admin' option for keystoneauth is no "
@@ -415,14 +419,26 @@ class KeystoneAuth(object):
415
419
  user_service_roles = [r.lower() for r in env_identity.get(
416
420
  'service_roles', [])]
417
421
 
418
- # Give unconditional access to a user with the reseller_admin
419
- # role.
422
+ # Give unconditional access to a user with the reseller_admin role.
420
423
  if self.reseller_admin_role in user_roles:
421
424
  msg = 'User %s has reseller admin authorizing'
422
425
  self.logger.debug(msg, tenant_id)
423
426
  req.environ['swift_owner'] = True
424
427
  return
425
428
 
429
+ # Being in system_reader_roles is almost as good as reseller_admin.
430
+ if self.system_reader_roles.intersection(user_roles):
431
+ # Note that if a system reader is trying to write, we're letting
432
+ # the request fall on other access checks below. This way,
433
+ # a compliance auditor can write a log file as a normal member.
434
+ if req.method in ('GET', 'HEAD'):
435
+ msg = 'User %s has system reader authorizing'
436
+ self.logger.debug(msg, tenant_id)
437
+ # We aren't setting 'swift_owner' nor 'reseller_request'
438
+ # because they are only ever used for something that modifies
439
+ # the contents of the cluster (setting ACL, deleting accounts).
440
+ return
441
+
426
442
  # If we are not reseller admin and user is trying to delete its own
427
443
  # account then deny it.
428
444
  if not container and not obj and req.method == 'DELETE':
@@ -485,6 +501,20 @@ class KeystoneAuth(object):
485
501
  req.environ['swift_owner'] = True
486
502
  return
487
503
 
504
+ # The project_reader_roles is almost as good as operator_roles. But
505
+ # it does not work with service tokens and does not get 'swift_owner'.
506
+ # And, it only serves GET requests, obviously.
507
+ project_reader_roles = self.account_rules[account_prefix][
508
+ 'project_reader_roles']
509
+ have_reader_role = set(project_reader_roles).intersection(
510
+ set(user_roles))
511
+ if have_reader_role:
512
+ if req.method in ('GET', 'HEAD'):
513
+ msg = 'User %s with role(s) %s has project reader authorizing'
514
+ self.logger.debug(msg, tenant_id,
515
+ ','.join(project_reader_roles))
516
+ return
517
+
488
518
  if acl_authorized is not None:
489
519
  return self.denied_response(req)
490
520
 
@@ -52,9 +52,9 @@ of endpoints having the same form as described above, and a key 'headers' that
52
52
  maps to a dictionary of headers that should be sent with a request made to
53
53
  the endpoints, e.g.::
54
54
 
55
- { "endpoints": {"http://10.1.1.1:6010/sda1/2/a/c3/o1",
56
- "http://10.1.1.1:6030/sda3/2/a/c3/o1",
57
- "http://10.1.1.1:6040/sda4/2/a/c3/o1"},
55
+ { "endpoints": {"http://10.1.1.1:6210/sda1/2/a/c3/o1",
56
+ "http://10.1.1.1:6230/sda3/2/a/c3/o1",
57
+ "http://10.1.1.1:6240/sda4/2/a/c3/o1"},
58
58
  "headers": {"X-Backend-Storage-Policy-Index": "1"}}
59
59
 
60
60
  In this example, the 'headers' dictionary indicates that requests to the
@@ -80,7 +80,7 @@ environment (everyone can query the locality data using this middleware).
80
80
 
81
81
  import json
82
82
 
83
- from six.moves.urllib.parse import quote, unquote
83
+ from urllib.parse import quote, unquote
84
84
 
85
85
  from swift.common.ring import Ring
86
86
  from swift.common.utils import get_logger, split_path
@@ -14,14 +14,15 @@
14
14
  # limitations under the License.
15
15
 
16
16
  import json
17
- import six
18
17
  from xml.etree.cElementTree import Element, SubElement, tostring
19
18
 
20
19
  from swift.common.constraints import valid_api_version
20
+ from swift.common.header_key_dict import HeaderKeyDict
21
21
  from swift.common.http import HTTP_NO_CONTENT
22
22
  from swift.common.request_helpers import get_param
23
23
  from swift.common.swob import HTTPException, HTTPNotAcceptable, Request, \
24
- RESPONSE_REASONS, HTTPBadRequest
24
+ RESPONSE_REASONS, HTTPBadRequest, wsgi_quote, wsgi_to_bytes
25
+ from swift.common.utils import RESERVED, get_logger, list_from_csv
25
26
 
26
27
 
27
28
  #: Mapping of query string ``format=`` values to their corresponding
@@ -73,8 +74,6 @@ def to_xml(document_element):
73
74
 
74
75
 
75
76
  def account_to_xml(listing, account_name):
76
- if isinstance(account_name, bytes):
77
- account_name = account_name.decode('utf-8')
78
77
  doc = Element('account', name=account_name)
79
78
  doc.text = '\n'
80
79
  for record in listing:
@@ -84,15 +83,15 @@ def account_to_xml(listing, account_name):
84
83
  else:
85
84
  sub = SubElement(doc, 'container')
86
85
  for field in ('name', 'count', 'bytes', 'last_modified'):
87
- SubElement(sub, field).text = six.text_type(
88
- record.pop(field))
86
+ SubElement(sub, field).text = str(record.pop(field))
87
+ for field in ('storage_policy',):
88
+ if field in record:
89
+ SubElement(sub, field).text = str(record.pop(field))
89
90
  sub.tail = '\n'
90
91
  return to_xml(doc)
91
92
 
92
93
 
93
94
  def container_to_xml(listing, base_name):
94
- if isinstance(base_name, bytes):
95
- base_name = base_name.decode('utf-8')
96
95
  doc = Element('container', name=base_name)
97
96
  for record in listing:
98
97
  if 'subdir' in record:
@@ -103,8 +102,7 @@ def container_to_xml(listing, base_name):
103
102
  sub = SubElement(doc, 'object')
104
103
  for field in ('name', 'hash', 'bytes', 'content_type',
105
104
  'last_modified'):
106
- SubElement(sub, field).text = six.text_type(
107
- record.pop(field))
105
+ SubElement(sub, field).text = str(record.pop(field))
108
106
  return to_xml(doc)
109
107
 
110
108
 
@@ -119,8 +117,31 @@ def listing_to_text(listing):
119
117
 
120
118
 
121
119
  class ListingFilter(object):
122
- def __init__(self, app):
120
+ def __init__(self, app, conf, logger=None):
123
121
  self.app = app
122
+ self.logger = logger or get_logger(conf, log_route='listing-filter')
123
+
124
+ def filter_reserved(self, listing, account, container):
125
+ new_listing = []
126
+ for entry in list(listing):
127
+ for key in ('name', 'subdir'):
128
+ value = entry.get(key, '')
129
+ if RESERVED in value:
130
+ if container:
131
+ self.logger.warning(
132
+ 'Container listing for %s/%s had '
133
+ 'reserved byte in %s: %r',
134
+ wsgi_quote(account), wsgi_quote(container),
135
+ key, value)
136
+ else:
137
+ self.logger.warning(
138
+ 'Account listing for %s had '
139
+ 'reserved byte in %s: %r',
140
+ wsgi_quote(account), key, value)
141
+ break # out of the *key* loop; check next entry
142
+ else:
143
+ new_listing.append(entry)
144
+ return new_listing
124
145
 
125
146
  def __call__(self, env, start_response):
126
147
  req = Request(env)
@@ -128,10 +149,10 @@ class ListingFilter(object):
128
149
  # account and container only
129
150
  version, acct, cont = req.split_path(2, 3)
130
151
  except ValueError:
131
- is_container_req = False
152
+ is_account_or_container_req = False
132
153
  else:
133
- is_container_req = True
134
- if not is_container_req:
154
+ is_account_or_container_req = True
155
+ if not is_account_or_container_req:
135
156
  return self.app(env, start_response)
136
157
 
137
158
  if not valid_api_version(version) or req.method not in ('GET', 'HEAD'):
@@ -145,46 +166,50 @@ class ListingFilter(object):
145
166
  return err(env, start_response)
146
167
 
147
168
  params = req.params
169
+ can_vary = 'format' not in params
148
170
  params['format'] = 'json'
149
171
  req.params = params
150
172
 
173
+ # Give other middlewares a chance to be in charge
174
+ env.setdefault('swift.format_listing', True)
151
175
  status, headers, resp_iter = req.call_application(self.app)
152
-
153
- header_to_index = {}
154
- resp_content_type = resp_length = None
155
- for i, (header, value) in enumerate(headers):
156
- header = header.lower()
157
- if header == 'content-type':
158
- header_to_index[header] = i
159
- resp_content_type = value.partition(';')[0]
160
- elif header == 'content-length':
161
- header_to_index[header] = i
162
- resp_length = int(value)
163
-
164
- if not status.startswith('200 '):
176
+ if not env.get('swift.format_listing'):
165
177
  start_response(status, headers)
166
178
  return resp_iter
167
179
 
168
- if resp_content_type != 'application/json':
180
+ if not status.startswith(('200 ', '204 ')):
169
181
  start_response(status, headers)
170
182
  return resp_iter
171
183
 
172
- if resp_length is None or \
173
- resp_length > MAX_CONTAINER_LISTING_CONTENT_LENGTH:
174
- start_response(status, headers)
175
- return resp_iter
184
+ headers_dict = HeaderKeyDict(headers)
185
+ resp_content_type = headers_dict.get(
186
+ 'content-type', '').partition(';')[0]
187
+ resp_length = headers_dict.get('content-length')
176
188
 
177
- def set_header(header, value):
178
- if value is None:
179
- del headers[header_to_index[header]]
189
+ if can_vary:
190
+ if 'vary' in headers_dict:
191
+ value = headers_dict['vary']
192
+ if 'accept' not in list_from_csv(value.lower()):
193
+ headers_dict['vary'] = value + ', Accept'
180
194
  else:
181
- headers[header_to_index[header]] = (
182
- headers[header_to_index[header]][0], str(value))
195
+ headers_dict['vary'] = 'Accept'
196
+
197
+ if resp_content_type != 'application/json':
198
+ start_response(status, list(headers_dict.items()))
199
+ return resp_iter
183
200
 
184
201
  if req.method == 'HEAD':
185
- set_header('content-type', out_content_type + '; charset=utf-8')
186
- set_header('content-length', None) # don't know, can't determine
187
- start_response(status, headers)
202
+ headers_dict['content-type'] = out_content_type + '; charset=utf-8'
203
+ # proxy logging (and maybe other mw?) seem to be good about
204
+ # sticking this on HEAD/204 but we do it here to be responsible
205
+ # and explicit
206
+ headers_dict['content-length'] = 0
207
+ start_response(status, list(headers_dict.items()))
208
+ return resp_iter
209
+
210
+ if resp_length is None or \
211
+ int(resp_length) > MAX_CONTAINER_LISTING_CONTENT_LENGTH:
212
+ start_response(status, list(headers_dict.items()))
188
213
  return resp_iter
189
214
 
190
215
  body = b''.join(resp_iter)
@@ -198,32 +223,43 @@ class ListingFilter(object):
198
223
  except ValueError:
199
224
  # Static web listing that's returning invalid JSON?
200
225
  # Just pass it straight through; that's about all we *can* do.
201
- start_response(status, headers)
226
+ start_response(status, list(headers_dict.items()))
202
227
  return [body]
203
228
 
229
+ if not req.allow_reserved_names:
230
+ listing = self.filter_reserved(listing, acct, cont)
231
+
204
232
  try:
205
233
  if out_content_type.endswith('/xml'):
206
234
  if cont:
207
- body = container_to_xml(listing, cont)
235
+ body = container_to_xml(
236
+ listing, wsgi_to_bytes(cont).decode('utf-8'))
208
237
  else:
209
- body = account_to_xml(listing, acct)
238
+ body = account_to_xml(
239
+ listing, wsgi_to_bytes(acct).decode('utf-8'))
210
240
  elif out_content_type == 'text/plain':
211
241
  body = listing_to_text(listing)
212
- # else, json -- we continue down here to be sure we set charset
242
+ else:
243
+ body = json.dumps(listing).encode('ascii')
213
244
  except KeyError:
214
245
  # listing was in a bad format -- funky static web listing??
215
- start_response(status, headers)
246
+ start_response(status, list(headers_dict.items()))
216
247
  return [body]
217
248
 
218
249
  if not body:
219
250
  status = '%s %s' % (HTTP_NO_CONTENT,
220
251
  RESPONSE_REASONS[HTTP_NO_CONTENT][0])
221
252
 
222
- set_header('content-type', out_content_type + '; charset=utf-8')
223
- set_header('content-length', len(body))
224
- start_response(status, headers)
253
+ headers_dict['content-type'] = out_content_type + '; charset=utf-8'
254
+ headers_dict['content-length'] = len(body)
255
+ start_response(status, list(headers_dict.items()))
225
256
  return [body]
226
257
 
227
258
 
228
259
  def filter_factory(global_conf, **local_conf):
229
- return ListingFilter
260
+ conf = global_conf.copy()
261
+ conf.update(local_conf)
262
+
263
+ def listing_filter(app):
264
+ return ListingFilter(app, conf)
265
+ return listing_filter
@@ -13,14 +13,8 @@
13
13
  # See the License for the specific language governing permissions and
14
14
  # limitations under the License.
15
15
 
16
- import os
17
-
18
- from eventlet.green import ssl
19
- from six.moves.configparser import ConfigParser, NoSectionError, NoOptionError
20
-
21
- from swift.common.memcached import (MemcacheRing, CONN_TIMEOUT, POOL_TIMEOUT,
22
- IO_TIMEOUT, TRY_COUNT)
23
- from swift.common.utils import config_true_value
16
+ from swift.common.memcached import load_memcache
17
+ from swift.common.utils import get_logger
24
18
 
25
19
 
26
20
  class MemcacheMiddleware(object):
@@ -30,93 +24,8 @@ class MemcacheMiddleware(object):
30
24
 
31
25
  def __init__(self, app, conf):
32
26
  self.app = app
33
- self.memcache_servers = conf.get('memcache_servers')
34
- serialization_format = conf.get('memcache_serialization_support')
35
- try:
36
- # Originally, while we documented using memcache_max_connections
37
- # we only accepted max_connections
38
- max_conns = int(conf.get('memcache_max_connections',
39
- conf.get('max_connections', 0)))
40
- except ValueError:
41
- max_conns = 0
42
-
43
- memcache_options = {}
44
- if (not self.memcache_servers
45
- or serialization_format is None
46
- or max_conns <= 0):
47
- path = os.path.join(conf.get('swift_dir', '/etc/swift'),
48
- 'memcache.conf')
49
- memcache_conf = ConfigParser()
50
- if memcache_conf.read(path):
51
- # if memcache.conf exists we'll start with those base options
52
- try:
53
- memcache_options = dict(memcache_conf.items('memcache'))
54
- except NoSectionError:
55
- pass
56
-
57
- if not self.memcache_servers:
58
- try:
59
- self.memcache_servers = \
60
- memcache_conf.get('memcache', 'memcache_servers')
61
- except (NoSectionError, NoOptionError):
62
- pass
63
- if serialization_format is None:
64
- try:
65
- serialization_format = \
66
- memcache_conf.get('memcache',
67
- 'memcache_serialization_support')
68
- except (NoSectionError, NoOptionError):
69
- pass
70
- if max_conns <= 0:
71
- try:
72
- new_max_conns = \
73
- memcache_conf.get('memcache',
74
- 'memcache_max_connections')
75
- max_conns = int(new_max_conns)
76
- except (NoSectionError, NoOptionError, ValueError):
77
- pass
78
-
79
- # while memcache.conf options are the base for the memcache
80
- # middleware, if you set the same option also in the filter
81
- # section of the proxy config it is more specific.
82
- memcache_options.update(conf)
83
- connect_timeout = float(memcache_options.get(
84
- 'connect_timeout', CONN_TIMEOUT))
85
- pool_timeout = float(memcache_options.get(
86
- 'pool_timeout', POOL_TIMEOUT))
87
- tries = int(memcache_options.get('tries', TRY_COUNT))
88
- io_timeout = float(memcache_options.get('io_timeout', IO_TIMEOUT))
89
- if config_true_value(memcache_options.get('tls_enabled', 'false')):
90
- tls_cafile = memcache_options.get('tls_cafile')
91
- tls_certfile = memcache_options.get('tls_certfile')
92
- tls_keyfile = memcache_options.get('tls_keyfile')
93
- self.tls_context = ssl.create_default_context(
94
- cafile=tls_cafile)
95
- if tls_certfile:
96
- self.tls_context.load_cert_chain(tls_certfile,
97
- tls_keyfile)
98
- else:
99
- self.tls_context = None
100
-
101
- if not self.memcache_servers:
102
- self.memcache_servers = '127.0.0.1:11211'
103
- if max_conns <= 0:
104
- max_conns = 2
105
- if serialization_format is None:
106
- serialization_format = 2
107
- else:
108
- serialization_format = int(serialization_format)
109
-
110
- self.memcache = MemcacheRing(
111
- [s.strip() for s in self.memcache_servers.split(',') if s.strip()],
112
- connect_timeout=connect_timeout,
113
- pool_timeout=pool_timeout,
114
- tries=tries,
115
- io_timeout=io_timeout,
116
- allow_pickle=(serialization_format == 0),
117
- allow_unpickle=(serialization_format <= 1),
118
- max_conns=max_conns,
119
- tls_context=self.tls_context)
27
+ self.logger = get_logger(conf, log_route='memcache')
28
+ self.memcache = load_memcache(conf, self.logger)
120
29
 
121
30
  def __call__(self, env, start_response):
122
31
  env['swift.cache'] = self.memcache
@@ -41,14 +41,15 @@ The filter returns HTTPBadRequest if path is invalid.
41
41
  '''
42
42
 
43
43
  import re
44
- from swift.common.utils import get_logger, register_swift_info
44
+ from swift.common.utils import get_logger
45
+ from swift.common.registry import register_swift_info
45
46
 
46
47
  from swift.common.swob import Request, HTTPBadRequest
47
48
 
48
49
 
49
50
  FORBIDDEN_CHARS = "\'\"`<>"
50
51
  MAX_LENGTH = 255
51
- FORBIDDEN_REGEXP = "/\./|/\.\./|/\.$|/\.\.$"
52
+ FORBIDDEN_REGEXP = r"/\./|/\.\./|/\.$|/\.\.$"
52
53
 
53
54
 
54
55
  class NameCheckMiddleware(object):