| 300 | | ### Copied from Amazon S3 example code and wrapped to support Twisted |
|---|
| 301 | | ### not my favorite interface but using SAX is probably faster than |
|---|
| 302 | | ### whatever I was going to do |
|---|
| 303 | | class S3Object: |
|---|
| 304 | | def __init__(self, data, metadata={}): |
|---|
| 305 | | self.data = data |
|---|
| 306 | | self.metadata = metadata |
|---|
| 307 | | class Owner: |
|---|
| 308 | | def __init__(self, id='', display_name=''): |
|---|
| 309 | | self.id = id |
|---|
| 310 | | self.display_name = display_name |
|---|
| 311 | | class ListEntry: |
|---|
| 312 | | def __init__(self, key='', last_modified=None, etag='', size=0, storage_class='', owner=None): |
|---|
| 313 | | self.key = key |
|---|
| 314 | | self.last_modified = last_modified |
|---|
| 315 | | self.etag = etag |
|---|
| 316 | | self.size = size |
|---|
| 317 | | self.storage_class = storage_class |
|---|
| 318 | | self.owner = owner |
|---|
| 319 | | class CommonPrefixEntry: |
|---|
| 320 | | def __init(self, prefix=''): |
|---|
| 321 | | self.prefix = prefix |
|---|
| 322 | | class Bucket: |
|---|
| 323 | | def __init__(self, name='', creation_date=''): |
|---|
| 324 | | self.name = name |
|---|
| 325 | | self.creation_date = creation_date |
|---|
| 326 | | class Response: |
|---|
| 327 | | def __init__(self, http_response): |
|---|
| 328 | | self.http_response = http_response |
|---|
| 329 | | # you have to do this read, even if you don't expect a body. |
|---|
| 330 | | # otherwise, the next request fails. |
|---|
| 331 | | self.body = http_response.read() |
|---|
| 332 | | class ListBucketResponse(Response): |
|---|
| 333 | | def __init__(self, http_response): |
|---|
| 334 | | Response.__init__(self, http_response) |
|---|
| 335 | | if http_response.status < 300: |
|---|
| 336 | | handler = ListBucketHandler() |
|---|
| 337 | | xml.sax.parseString(self.body, handler) |
|---|
| 338 | | self.entries = handler.entries |
|---|
| 339 | | self.common_prefixes = handler.common_prefixes |
|---|
| 340 | | self.name = handler.name |
|---|
| 341 | | self.marker = handler.marker |
|---|
| 342 | | self.prefix = handler.prefix |
|---|
| 343 | | self.is_truncated = handler.is_truncated |
|---|
| 344 | | self.delimiter = handler.delimiter |
|---|
| 345 | | self.max_keys = handler.max_keys |
|---|
| 346 | | self.next_marker = handler.next_marker |
|---|
| 347 | | else: |
|---|
| 348 | | self.entries = [] |
|---|
| 349 | | class ListAllMyBucketsResponse(Response): |
|---|
| 350 | | def __init__(self, http_response): |
|---|
| 351 | | Response.__init__(self, http_response) |
|---|
| 352 | | if http_response.status < 300: |
|---|
| 353 | | handler = ListAllMyBucketsHandler() |
|---|
| 354 | | xml.sax.parseString(self.body, handler) |
|---|
| 355 | | self.entries = handler.entries |
|---|
| 356 | | else: |
|---|
| 357 | | self.entries = [] |
|---|
| 358 | | class GetResponse(Response): |
|---|
| 359 | | def __init__(self, http_response): |
|---|
| 360 | | Response.__init__(self, http_response) |
|---|
| 361 | | response_headers = http_response.msg # older pythons don't have getheaders |
|---|
| 362 | | metadata = self.get_aws_metadata(response_headers) |
|---|
| 363 | | self.object = S3Object(self.body, metadata) |
|---|
| 364 | | |
|---|
| 365 | | def get_aws_metadata(self, headers): |
|---|
| 366 | | metadata = {} |
|---|
| 367 | | for hkey in headers.keys(): |
|---|
| 368 | | if hkey.lower().startswith(METADATA_PREFIX): |
|---|
| 369 | | metadata[hkey[len(METADATA_PREFIX):]] = headers[hkey] |
|---|
| 370 | | del headers[hkey] |
|---|
| 371 | | |
|---|
| 372 | | return metadata |
|---|
| 373 | | class ListBucketHandler(xml.sax.ContentHandler): |
|---|
| 374 | | def __init__(self): |
|---|
| 375 | | self.entries = [] |
|---|
| 376 | | self.curr_entry = None |
|---|
| 377 | | self.curr_text = '' |
|---|
| 378 | | self.common_prefixes = [] |
|---|
| 379 | | self.curr_common_prefix = None |
|---|
| 380 | | self.name = '' |
|---|
| 381 | | self.marker = '' |
|---|
| 382 | | self.prefix = '' |
|---|
| 383 | | self.is_truncated = False |
|---|
| 384 | | self.delimiter = '' |
|---|
| 385 | | self.max_keys = 0 |
|---|
| 386 | | self.next_marker = '' |
|---|
| 387 | | self.is_echoed_prefix_set = False |
|---|
| 388 | | |
|---|
| 389 | | def startElement(self, name, attrs): |
|---|
| 390 | | if name == 'Contents': |
|---|
| 391 | | self.curr_entry = ListEntry() |
|---|
| 392 | | elif name == 'Owner': |
|---|
| 393 | | self.curr_entry.owner = Owner() |
|---|
| 394 | | elif name == 'CommonPrefixes': |
|---|
| 395 | | self.curr_common_prefix = CommonPrefixEntry() |
|---|
| 396 | | |
|---|
| 397 | | |
|---|
| 398 | | def endElement(self, name): |
|---|
| 399 | | if name == 'Contents': |
|---|
| 400 | | self.entries.append(self.curr_entry) |
|---|
| 401 | | elif name == 'CommonPrefixes': |
|---|
| 402 | | self.common_prefixes.append(self.curr_common_prefix) |
|---|
| 403 | | elif name == 'Key': |
|---|
| 404 | | self.curr_entry.key = self.curr_text |
|---|
| 405 | | elif name == 'LastModified': |
|---|
| 406 | | self.curr_entry.last_modified = self.curr_text |
|---|
| 407 | | elif name == 'ETag': |
|---|
| 408 | | self.curr_entry.etag = self.curr_text |
|---|
| 409 | | elif name == 'Size': |
|---|
| 410 | | self.curr_entry.size = int(self.curr_text) |
|---|
| 411 | | elif name == 'ID': |
|---|
| 412 | | self.curr_entry.owner.id = self.curr_text |
|---|
| 413 | | elif name == 'DisplayName': |
|---|
| 414 | | self.curr_entry.owner.display_name = self.curr_text |
|---|
| 415 | | elif name == 'StorageClass': |
|---|
| 416 | | self.curr_entry.storage_class = self.curr_text |
|---|
| 417 | | elif name == 'Name': |
|---|
| 418 | | self.name = self.curr_text |
|---|
| 419 | | elif name == 'Prefix' and self.is_echoed_prefix_set: |
|---|
| 420 | | self.curr_common_prefix.prefix = self.curr_text |
|---|
| 421 | | elif name == 'Prefix': |
|---|
| 422 | | self.prefix = self.curr_text |
|---|
| 423 | | self.is_echoed_prefix_set = True |
|---|
| 424 | | elif name == 'Marker': |
|---|
| 425 | | self.marker = self.curr_text |
|---|
| 426 | | elif name == 'IsTruncated': |
|---|
| 427 | | self.is_truncated = self.curr_text == 'true' |
|---|
| 428 | | elif name == 'Delimiter': |
|---|
| 429 | | self.delimiter = self.curr_text |
|---|
| 430 | | elif name == 'MaxKeys': |
|---|
| 431 | | self.max_keys = int(self.curr_text) |
|---|
| 432 | | elif name == 'NextMarker': |
|---|
| 433 | | self.next_marker = self.curr_text |
|---|
| 434 | | |
|---|
| 435 | | self.curr_text = '' |
|---|
| 436 | | |
|---|
| 437 | | def characters(self, content): |
|---|
| 438 | | self.curr_text += content |
|---|
| 439 | | class ListAllMyBucketsHandler(xml.sax.ContentHandler): |
|---|
| 440 | | def __init__(self): |
|---|
| 441 | | self.entries = [] |
|---|
| 442 | | self.curr_entry = None |
|---|
| 443 | | self.curr_text = '' |
|---|
| 444 | | |
|---|
| 445 | | def startElement(self, name, attrs): |
|---|
| 446 | | if name == 'Bucket': |
|---|
| 447 | | self.curr_entry = Bucket() |
|---|
| 448 | | |
|---|
| 449 | | def endElement(self, name): |
|---|
| 450 | | if name == 'Name': |
|---|
| 451 | | self.curr_entry.name = self.curr_text |
|---|
| 452 | | elif name == 'CreationDate': |
|---|
| 453 | | self.curr_entry.creation_date = self.curr_text |
|---|
| 454 | | elif name == 'Bucket': |
|---|
| 455 | | self.entries.append(self.curr_entry) |
|---|
| 456 | | |
|---|
| 457 | | def characters(self, content): |
|---|
| 458 | | self.curr_text = content |
|---|
| 459 | | |
|---|
| 460 | | |
|---|
| 461 | | |
|---|
| 462 | | if __name__ == "__builtin__": |
|---|
| 463 | | from twisted.application import internet, service |
|---|
| 464 | | |
|---|
| 465 | | config = Options() |
|---|
| 466 | | #config.parseOptions() |
|---|
| 467 | | |
|---|
| 468 | | application = service.Application("s3") |
|---|
| 469 | | s = makeService(config) |
|---|
| 470 | | s.setServiceParent(application) |
|---|
| 471 | | |
|---|
| | 296 | |
|---|