aws-sdk-euca 1.8.5
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.
- data/.yardopts +5 -0
- data/LICENSE.txt +12 -0
- data/README.rdoc +189 -0
- data/ca-bundle.crt +3895 -0
- data/lib/aws-sdk-euca.rb +79 -0
- data/lib/aws-sdk.rb +79 -0
- data/lib/aws.rb +14 -0
- data/lib/aws/api_config/AutoScaling-2011-01-01.yml +825 -0
- data/lib/aws/api_config/CloudFormation-2010-05-15.yml +322 -0
- data/lib/aws/api_config/CloudFront-2012-05-05.yml +2102 -0
- data/lib/aws/api_config/CloudSearch-2011-02-01.yml +681 -0
- data/lib/aws/api_config/CloudWatch-2010-08-01.yml +433 -0
- data/lib/aws/api_config/DataPipeline-2012-10-29.yml +422 -0
- data/lib/aws/api_config/DynamoDB-2011-12-05.yml +1160 -0
- data/lib/aws/api_config/EC2-2013-02-01.yml +4368 -0
- data/lib/aws/api_config/ELB-2012-06-01.yml +597 -0
- data/lib/aws/api_config/EMR-2009-03-31.yml +370 -0
- data/lib/aws/api_config/ElastiCache-2012-03-09.yml +777 -0
- data/lib/aws/api_config/ElastiCache-2012-11-15.yml +979 -0
- data/lib/aws/api_config/ElasticBeanstalk-2010-12-01.yml +823 -0
- data/lib/aws/api_config/ElasticTranscoder-2012-09-25.yml +1036 -0
- data/lib/aws/api_config/Glacier-2012-06-01.yml +618 -0
- data/lib/aws/api_config/IAM-2010-05-08.yml +1222 -0
- data/lib/aws/api_config/ImportExport-2010-06-01.yml +109 -0
- data/lib/aws/api_config/OpsWorks-2013-02-18.yml +1463 -0
- data/lib/aws/api_config/RDS-2012-09-17.yml +1861 -0
- data/lib/aws/api_config/RDS-2013-02-12.yml +2377 -0
- data/lib/aws/api_config/Redshift-2012-12-01.yml +1149 -0
- data/lib/aws/api_config/Route53-2012-02-29.yml +380 -0
- data/lib/aws/api_config/Route53-2012-12-12.yml +547 -0
- data/lib/aws/api_config/SNS-2010-03-31.yml +249 -0
- data/lib/aws/api_config/SQS-2012-11-05.yml +317 -0
- data/lib/aws/api_config/STS-2011-06-15.yml +81 -0
- data/lib/aws/api_config/SimpleDB-2009-04-15.yml +306 -0
- data/lib/aws/api_config/SimpleEmailService-2010-12-01.yml +346 -0
- data/lib/aws/api_config/SimpleWorkflow-2012-01-25.yml +2358 -0
- data/lib/aws/api_config/StorageGateway-2012-06-30.yml +748 -0
- data/lib/aws/auto_scaling.rb +164 -0
- data/lib/aws/auto_scaling/activity.rb +102 -0
- data/lib/aws/auto_scaling/activity_collection.rb +82 -0
- data/lib/aws/auto_scaling/client.rb +521 -0
- data/lib/aws/auto_scaling/config.rb +18 -0
- data/lib/aws/auto_scaling/errors.rb +22 -0
- data/lib/aws/auto_scaling/group.rb +420 -0
- data/lib/aws/auto_scaling/group_collection.rb +96 -0
- data/lib/aws/auto_scaling/group_options.rb +146 -0
- data/lib/aws/auto_scaling/instance.rb +192 -0
- data/lib/aws/auto_scaling/instance_collection.rb +63 -0
- data/lib/aws/auto_scaling/launch_configuration.rb +158 -0
- data/lib/aws/auto_scaling/launch_configuration_collection.rb +154 -0
- data/lib/aws/auto_scaling/notification_configuration.rb +89 -0
- data/lib/aws/auto_scaling/notification_configuration_collection.rb +184 -0
- data/lib/aws/auto_scaling/request.rb +29 -0
- data/lib/aws/auto_scaling/scaling_policy.rb +142 -0
- data/lib/aws/auto_scaling/scaling_policy_collection.rb +72 -0
- data/lib/aws/auto_scaling/scaling_policy_options.rb +64 -0
- data/lib/aws/auto_scaling/scheduled_action.rb +145 -0
- data/lib/aws/auto_scaling/scheduled_action_collection.rb +195 -0
- data/lib/aws/auto_scaling/tag.rb +59 -0
- data/lib/aws/auto_scaling/tag_collection.rb +112 -0
- data/lib/aws/cloud_formation.rb +272 -0
- data/lib/aws/cloud_formation/client.rb +369 -0
- data/lib/aws/cloud_formation/config.rb +18 -0
- data/lib/aws/cloud_formation/errors.rb +22 -0
- data/lib/aws/cloud_formation/request.rb +29 -0
- data/lib/aws/cloud_formation/stack.rb +255 -0
- data/lib/aws/cloud_formation/stack_collection.rb +209 -0
- data/lib/aws/cloud_formation/stack_event.rb +75 -0
- data/lib/aws/cloud_formation/stack_event_collection.rb +47 -0
- data/lib/aws/cloud_formation/stack_options.rb +72 -0
- data/lib/aws/cloud_formation/stack_output.rb +53 -0
- data/lib/aws/cloud_formation/stack_resource.rb +117 -0
- data/lib/aws/cloud_formation/stack_resource_collection.rb +84 -0
- data/lib/aws/cloud_formation/stack_resource_summary_collection.rb +64 -0
- data/lib/aws/cloud_formation/stack_summary_collection.rb +123 -0
- data/lib/aws/cloud_front.rb +73 -0
- data/lib/aws/cloud_front/client.rb +1307 -0
- data/lib/aws/cloud_front/config.rb +18 -0
- data/lib/aws/cloud_front/errors.rb +22 -0
- data/lib/aws/cloud_front/request.rb +44 -0
- data/lib/aws/cloud_search.rb +74 -0
- data/lib/aws/cloud_search/client.rb +558 -0
- data/lib/aws/cloud_search/config.rb +18 -0
- data/lib/aws/cloud_search/errors.rb +22 -0
- data/lib/aws/cloud_search/request.rb +23 -0
- data/lib/aws/cloud_watch.rb +119 -0
- data/lib/aws/cloud_watch/alarm.rb +272 -0
- data/lib/aws/cloud_watch/alarm_collection.rb +153 -0
- data/lib/aws/cloud_watch/alarm_history_item.rb +50 -0
- data/lib/aws/cloud_watch/alarm_history_item_collection.rb +84 -0
- data/lib/aws/cloud_watch/client.rb +247 -0
- data/lib/aws/cloud_watch/config.rb +18 -0
- data/lib/aws/cloud_watch/errors.rb +22 -0
- data/lib/aws/cloud_watch/metric.rb +135 -0
- data/lib/aws/cloud_watch/metric_alarm_collection.rb +160 -0
- data/lib/aws/cloud_watch/metric_collection.rb +131 -0
- data/lib/aws/cloud_watch/metric_statistics.rb +69 -0
- data/lib/aws/cloud_watch/request.rb +23 -0
- data/lib/aws/core.rb +587 -0
- data/lib/aws/core/async_handle.rb +90 -0
- data/lib/aws/core/autoloader.rb +64 -0
- data/lib/aws/core/cacheable.rb +78 -0
- data/lib/aws/core/client.rb +691 -0
- data/lib/aws/core/collection.rb +267 -0
- data/lib/aws/core/collection/simple.rb +82 -0
- data/lib/aws/core/collection/with_limit_and_next_token.rb +71 -0
- data/lib/aws/core/collection/with_next_token.rb +97 -0
- data/lib/aws/core/configuration.rb +546 -0
- data/lib/aws/core/credential_providers.rb +461 -0
- data/lib/aws/core/data.rb +247 -0
- data/lib/aws/core/http/curb_handler.rb +155 -0
- data/lib/aws/core/http/handler.rb +89 -0
- data/lib/aws/core/http/net_http_handler.rb +128 -0
- data/lib/aws/core/http/request.rb +263 -0
- data/lib/aws/core/http/response.rb +81 -0
- data/lib/aws/core/indifferent_hash.rb +88 -0
- data/lib/aws/core/inflection.rb +56 -0
- data/lib/aws/core/json_client.rb +47 -0
- data/lib/aws/core/json_parser.rb +76 -0
- data/lib/aws/core/json_request_builder.rb +35 -0
- data/lib/aws/core/json_response_parser.rb +79 -0
- data/lib/aws/core/lazy_error_classes.rb +90 -0
- data/lib/aws/core/log_formatter.rb +462 -0
- data/lib/aws/core/managed_file.rb +32 -0
- data/lib/aws/core/meta_utils.rb +45 -0
- data/lib/aws/core/model.rb +57 -0
- data/lib/aws/core/naming.rb +30 -0
- data/lib/aws/core/option_grammar.rb +735 -0
- data/lib/aws/core/options/json_serializer.rb +82 -0
- data/lib/aws/core/options/validator.rb +155 -0
- data/lib/aws/core/options/xml_serializer.rb +118 -0
- data/lib/aws/core/page_result.rb +75 -0
- data/lib/aws/core/policy.rb +916 -0
- data/lib/aws/core/query_client.rb +41 -0
- data/lib/aws/core/query_error_parser.rb +24 -0
- data/lib/aws/core/query_request_builder.rb +47 -0
- data/lib/aws/core/query_response_parser.rb +35 -0
- data/lib/aws/core/resource.rb +413 -0
- data/lib/aws/core/resource_cache.rb +40 -0
- data/lib/aws/core/response.rb +208 -0
- data/lib/aws/core/response_cache.rb +50 -0
- data/lib/aws/core/rest_error_parser.rb +24 -0
- data/lib/aws/core/rest_json_client.rb +40 -0
- data/lib/aws/core/rest_request_builder.rb +146 -0
- data/lib/aws/core/rest_response_parser.rb +66 -0
- data/lib/aws/core/rest_xml_client.rb +47 -0
- data/lib/aws/core/service_interface.rb +61 -0
- data/lib/aws/core/signature/version_2.rb +56 -0
- data/lib/aws/core/signature/version_3.rb +77 -0
- data/lib/aws/core/signature/version_3_https.rb +54 -0
- data/lib/aws/core/signature/version_4.rb +135 -0
- data/lib/aws/core/signer.rb +46 -0
- data/lib/aws/core/uri_escape.rb +44 -0
- data/lib/aws/core/xml/frame.rb +244 -0
- data/lib/aws/core/xml/frame_stack.rb +85 -0
- data/lib/aws/core/xml/grammar.rb +307 -0
- data/lib/aws/core/xml/parser.rb +70 -0
- data/lib/aws/core/xml/root_frame.rb +65 -0
- data/lib/aws/core/xml/sax_handlers/libxml.rb +47 -0
- data/lib/aws/core/xml/sax_handlers/nokogiri.rb +55 -0
- data/lib/aws/core/xml/sax_handlers/ox.rb +41 -0
- data/lib/aws/core/xml/sax_handlers/rexml.rb +43 -0
- data/lib/aws/core/xml/stub.rb +123 -0
- data/lib/aws/data_pipeline.rb +73 -0
- data/lib/aws/data_pipeline/client.rb +339 -0
- data/lib/aws/data_pipeline/config.rb +18 -0
- data/lib/aws/data_pipeline/errors.rb +20 -0
- data/lib/aws/data_pipeline/request.rb +26 -0
- data/lib/aws/dynamo_db.rb +206 -0
- data/lib/aws/dynamo_db/attribute_collection.rb +461 -0
- data/lib/aws/dynamo_db/batch_get.rb +213 -0
- data/lib/aws/dynamo_db/batch_write.rb +252 -0
- data/lib/aws/dynamo_db/binary.rb +35 -0
- data/lib/aws/dynamo_db/client.rb +904 -0
- data/lib/aws/dynamo_db/config.rb +24 -0
- data/lib/aws/dynamo_db/errors.rb +20 -0
- data/lib/aws/dynamo_db/expectations.rb +40 -0
- data/lib/aws/dynamo_db/item.rb +133 -0
- data/lib/aws/dynamo_db/item_collection.rb +852 -0
- data/lib/aws/dynamo_db/item_data.rb +31 -0
- data/lib/aws/dynamo_db/keys.rb +41 -0
- data/lib/aws/dynamo_db/primary_key_element.rb +48 -0
- data/lib/aws/dynamo_db/request.rb +26 -0
- data/lib/aws/dynamo_db/resource.rb +33 -0
- data/lib/aws/dynamo_db/table.rb +491 -0
- data/lib/aws/dynamo_db/table_collection.rb +165 -0
- data/lib/aws/dynamo_db/types.rb +111 -0
- data/lib/aws/ec2.rb +440 -0
- data/lib/aws/ec2/attachment.rb +140 -0
- data/lib/aws/ec2/attachment_collection.rb +54 -0
- data/lib/aws/ec2/availability_zone.rb +86 -0
- data/lib/aws/ec2/availability_zone_collection.rb +43 -0
- data/lib/aws/ec2/block_device_mappings.rb +53 -0
- data/lib/aws/ec2/client.rb +3621 -0
- data/lib/aws/ec2/collection.rb +36 -0
- data/lib/aws/ec2/config.rb +18 -0
- data/lib/aws/ec2/config_transform.rb +63 -0
- data/lib/aws/ec2/customer_gateway.rb +90 -0
- data/lib/aws/ec2/customer_gateway_collection.rb +73 -0
- data/lib/aws/ec2/dhcp_options.rb +106 -0
- data/lib/aws/ec2/dhcp_options_collection.rb +87 -0
- data/lib/aws/ec2/elastic_ip.rb +208 -0
- data/lib/aws/ec2/elastic_ip_collection.rb +97 -0
- data/lib/aws/ec2/errors.rb +32 -0
- data/lib/aws/ec2/export_task.rb +120 -0
- data/lib/aws/ec2/export_task_collection.rb +67 -0
- data/lib/aws/ec2/filtered_collection.rb +89 -0
- data/lib/aws/ec2/has_permissions.rb +44 -0
- data/lib/aws/ec2/image.rb +264 -0
- data/lib/aws/ec2/image_collection.rb +228 -0
- data/lib/aws/ec2/instance.rb +796 -0
- data/lib/aws/ec2/instance_collection.rb +372 -0
- data/lib/aws/ec2/internet_gateway.rb +122 -0
- data/lib/aws/ec2/internet_gateway/attachment.rb +78 -0
- data/lib/aws/ec2/internet_gateway_collection.rb +54 -0
- data/lib/aws/ec2/key_pair.rb +82 -0
- data/lib/aws/ec2/key_pair_collection.rb +99 -0
- data/lib/aws/ec2/network_acl.rb +256 -0
- data/lib/aws/ec2/network_acl/association.rb +56 -0
- data/lib/aws/ec2/network_acl/entry.rb +147 -0
- data/lib/aws/ec2/network_acl_collection.rb +64 -0
- data/lib/aws/ec2/network_interface.rb +228 -0
- data/lib/aws/ec2/network_interface/attachment.rb +100 -0
- data/lib/aws/ec2/network_interface_collection.rb +103 -0
- data/lib/aws/ec2/permission_collection.rb +174 -0
- data/lib/aws/ec2/region.rb +106 -0
- data/lib/aws/ec2/region_collection.rb +51 -0
- data/lib/aws/ec2/request.rb +21 -0
- data/lib/aws/ec2/reserved_instances.rb +56 -0
- data/lib/aws/ec2/reserved_instances_collection.rb +40 -0
- data/lib/aws/ec2/reserved_instances_offering.rb +60 -0
- data/lib/aws/ec2/reserved_instances_offering_collection.rb +39 -0
- data/lib/aws/ec2/resource.rb +161 -0
- data/lib/aws/ec2/resource_tag_collection.rb +211 -0
- data/lib/aws/ec2/route_table.rb +205 -0
- data/lib/aws/ec2/route_table/association.rb +119 -0
- data/lib/aws/ec2/route_table/route.rb +119 -0
- data/lib/aws/ec2/route_table_collection.rb +72 -0
- data/lib/aws/ec2/security_group.rb +484 -0
- data/lib/aws/ec2/security_group/ip_permission.rb +135 -0
- data/lib/aws/ec2/security_group/ip_permission_collection.rb +82 -0
- data/lib/aws/ec2/security_group_collection.rb +135 -0
- data/lib/aws/ec2/snapshot.rb +143 -0
- data/lib/aws/ec2/snapshot_collection.rb +132 -0
- data/lib/aws/ec2/subnet.rb +161 -0
- data/lib/aws/ec2/subnet_collection.rb +115 -0
- data/lib/aws/ec2/tag.rb +81 -0
- data/lib/aws/ec2/tag_collection.rb +107 -0
- data/lib/aws/ec2/tagged_collection.rb +53 -0
- data/lib/aws/ec2/tagged_item.rb +85 -0
- data/lib/aws/ec2/volume.rb +174 -0
- data/lib/aws/ec2/volume_collection.rb +101 -0
- data/lib/aws/ec2/vpc.rb +166 -0
- data/lib/aws/ec2/vpc_collection.rb +70 -0
- data/lib/aws/ec2/vpn_connection.rb +99 -0
- data/lib/aws/ec2/vpn_connection/telemetry.rb +49 -0
- data/lib/aws/ec2/vpn_connection_collection.rb +96 -0
- data/lib/aws/ec2/vpn_gateway.rb +123 -0
- data/lib/aws/ec2/vpn_gateway/attachment.rb +45 -0
- data/lib/aws/ec2/vpn_gateway_collection.rb +77 -0
- data/lib/aws/elastic_beanstalk.rb +50 -0
- data/lib/aws/elastic_beanstalk/client.rb +867 -0
- data/lib/aws/elastic_beanstalk/config.rb +18 -0
- data/lib/aws/elastic_beanstalk/errors.rb +22 -0
- data/lib/aws/elastic_beanstalk/request.rb +29 -0
- data/lib/aws/elastic_transcoder.rb +30 -0
- data/lib/aws/elastic_transcoder/client.rb +672 -0
- data/lib/aws/elastic_transcoder/config.rb +18 -0
- data/lib/aws/elastic_transcoder/errors.rb +23 -0
- data/lib/aws/elastic_transcoder/request.rb +30 -0
- data/lib/aws/elasticache.rb +50 -0
- data/lib/aws/elasticache/client.rb +920 -0
- data/lib/aws/elasticache/config.rb +18 -0
- data/lib/aws/elasticache/errors.rb +22 -0
- data/lib/aws/elasticache/request.rb +23 -0
- data/lib/aws/elb.rb +67 -0
- data/lib/aws/elb/availability_zone_collection.rb +138 -0
- data/lib/aws/elb/backend_server_policy_collection.rb +139 -0
- data/lib/aws/elb/client.rb +500 -0
- data/lib/aws/elb/config.rb +18 -0
- data/lib/aws/elb/errors.rb +26 -0
- data/lib/aws/elb/instance_collection.rb +173 -0
- data/lib/aws/elb/listener.rb +190 -0
- data/lib/aws/elb/listener_collection.rb +113 -0
- data/lib/aws/elb/listener_opts.rb +45 -0
- data/lib/aws/elb/load_balancer.rb +281 -0
- data/lib/aws/elb/load_balancer_collection.rb +134 -0
- data/lib/aws/elb/load_balancer_policy.rb +93 -0
- data/lib/aws/elb/load_balancer_policy_collection.rb +208 -0
- data/lib/aws/elb/request.rb +29 -0
- data/lib/aws/emr.rb +86 -0
- data/lib/aws/emr/client.rb +330 -0
- data/lib/aws/emr/config.rb +18 -0
- data/lib/aws/emr/errors.rb +22 -0
- data/lib/aws/emr/instance_group.rb +138 -0
- data/lib/aws/emr/instance_group_collection.rb +82 -0
- data/lib/aws/emr/job_flow.rb +306 -0
- data/lib/aws/emr/job_flow_collection.rb +185 -0
- data/lib/aws/emr/request.rb +23 -0
- data/lib/aws/errors.rb +162 -0
- data/lib/aws/glacier.rb +80 -0
- data/lib/aws/glacier/archive.rb +56 -0
- data/lib/aws/glacier/archive_collection.rb +146 -0
- data/lib/aws/glacier/client.rb +286 -0
- data/lib/aws/glacier/config.rb +19 -0
- data/lib/aws/glacier/errors.rb +22 -0
- data/lib/aws/glacier/request.rb +34 -0
- data/lib/aws/glacier/resource.rb +30 -0
- data/lib/aws/glacier/vault.rb +145 -0
- data/lib/aws/glacier/vault_collection.rb +75 -0
- data/lib/aws/glacier/vault_notification_configuration.rb +29 -0
- data/lib/aws/iam.rb +420 -0
- data/lib/aws/iam/access_key.rb +180 -0
- data/lib/aws/iam/access_key_collection.rb +128 -0
- data/lib/aws/iam/account_alias_collection.rb +79 -0
- data/lib/aws/iam/client.rb +1092 -0
- data/lib/aws/iam/collection.rb +83 -0
- data/lib/aws/iam/config.rb +18 -0
- data/lib/aws/iam/errors.rb +22 -0
- data/lib/aws/iam/group.rb +111 -0
- data/lib/aws/iam/group_collection.rb +132 -0
- data/lib/aws/iam/group_policy_collection.rb +47 -0
- data/lib/aws/iam/group_user_collection.rb +84 -0
- data/lib/aws/iam/login_profile.rb +99 -0
- data/lib/aws/iam/mfa_device.rb +52 -0
- data/lib/aws/iam/mfa_device_collection.rb +127 -0
- data/lib/aws/iam/policy.rb +46 -0
- data/lib/aws/iam/policy_collection.rb +188 -0
- data/lib/aws/iam/request.rb +29 -0
- data/lib/aws/iam/resource.rb +62 -0
- data/lib/aws/iam/server_certificate.rb +141 -0
- data/lib/aws/iam/server_certificate_collection.rb +138 -0
- data/lib/aws/iam/signing_certificate.rb +169 -0
- data/lib/aws/iam/signing_certificate_collection.rb +131 -0
- data/lib/aws/iam/user.rb +205 -0
- data/lib/aws/iam/user_collection.rb +133 -0
- data/lib/aws/iam/user_group_collection.rb +98 -0
- data/lib/aws/iam/user_policy.rb +90 -0
- data/lib/aws/iam/user_policy_collection.rb +45 -0
- data/lib/aws/iam/virtual_mfa_device.rb +139 -0
- data/lib/aws/iam/virtual_mfa_device_collection.rb +73 -0
- data/lib/aws/import_export.rb +73 -0
- data/lib/aws/import_export/client.rb +109 -0
- data/lib/aws/import_export/config.rb +19 -0
- data/lib/aws/import_export/errors.rb +22 -0
- data/lib/aws/import_export/request.rb +23 -0
- data/lib/aws/ops_works.rb +30 -0
- data/lib/aws/ops_works/client.rb +713 -0
- data/lib/aws/ops_works/config.rb +18 -0
- data/lib/aws/ops_works/errors.rb +20 -0
- data/lib/aws/ops_works/request.rb +27 -0
- data/lib/aws/rails.rb +195 -0
- data/lib/aws/rds.rb +71 -0
- data/lib/aws/rds/client.rb +2228 -0
- data/lib/aws/rds/config.rb +18 -0
- data/lib/aws/rds/db_instance.rb +205 -0
- data/lib/aws/rds/db_instance_collection.rb +75 -0
- data/lib/aws/rds/db_snapshot.rb +163 -0
- data/lib/aws/rds/db_snapshot_collection.rb +89 -0
- data/lib/aws/rds/errors.rb +22 -0
- data/lib/aws/rds/request.rb +23 -0
- data/lib/aws/record.rb +116 -0
- data/lib/aws/record/abstract_base.rb +701 -0
- data/lib/aws/record/attributes.rb +384 -0
- data/lib/aws/record/conversion.rb +38 -0
- data/lib/aws/record/dirty_tracking.rb +285 -0
- data/lib/aws/record/errors.rb +143 -0
- data/lib/aws/record/exceptions.rb +48 -0
- data/lib/aws/record/hash_model.rb +161 -0
- data/lib/aws/record/hash_model/attributes.rb +197 -0
- data/lib/aws/record/hash_model/finder_methods.rb +172 -0
- data/lib/aws/record/hash_model/scope.rb +108 -0
- data/lib/aws/record/model.rb +427 -0
- data/lib/aws/record/model/attributes.rb +379 -0
- data/lib/aws/record/model/finder_methods.rb +232 -0
- data/lib/aws/record/model/scope.rb +213 -0
- data/lib/aws/record/naming.rb +31 -0
- data/lib/aws/record/scope.rb +199 -0
- data/lib/aws/record/validations.rb +712 -0
- data/lib/aws/record/validator.rb +246 -0
- data/lib/aws/record/validators/acceptance.rb +51 -0
- data/lib/aws/record/validators/block.rb +38 -0
- data/lib/aws/record/validators/confirmation.rb +43 -0
- data/lib/aws/record/validators/count.rb +108 -0
- data/lib/aws/record/validators/exclusion.rb +43 -0
- data/lib/aws/record/validators/format.rb +57 -0
- data/lib/aws/record/validators/inclusion.rb +56 -0
- data/lib/aws/record/validators/length.rb +107 -0
- data/lib/aws/record/validators/method.rb +33 -0
- data/lib/aws/record/validators/numericality.rb +138 -0
- data/lib/aws/record/validators/presence.rb +45 -0
- data/lib/aws/redshift.rb +52 -0
- data/lib/aws/redshift/client.rb +1291 -0
- data/lib/aws/redshift/config.rb +18 -0
- data/lib/aws/redshift/errors.rb +22 -0
- data/lib/aws/redshift/request.rb +29 -0
- data/lib/aws/route_53.rb +87 -0
- data/lib/aws/route_53/change_batch.rb +159 -0
- data/lib/aws/route_53/change_info.rb +72 -0
- data/lib/aws/route_53/client.rb +387 -0
- data/lib/aws/route_53/config.rb +18 -0
- data/lib/aws/route_53/errors.rb +22 -0
- data/lib/aws/route_53/hosted_zone.rb +111 -0
- data/lib/aws/route_53/hosted_zone_collection.rb +100 -0
- data/lib/aws/route_53/request.rb +23 -0
- data/lib/aws/route_53/resource_record_set.rb +237 -0
- data/lib/aws/route_53/resource_record_set_collection.rb +110 -0
- data/lib/aws/s3.rb +155 -0
- data/lib/aws/s3/access_control_list.rb +257 -0
- data/lib/aws/s3/acl_object.rb +264 -0
- data/lib/aws/s3/acl_options.rb +204 -0
- data/lib/aws/s3/bucket.rb +742 -0
- data/lib/aws/s3/bucket_collection.rb +160 -0
- data/lib/aws/s3/bucket_lifecycle_configuration.rb +458 -0
- data/lib/aws/s3/bucket_tag_collection.rb +109 -0
- data/lib/aws/s3/bucket_version_collection.rb +77 -0
- data/lib/aws/s3/cipher_io.rb +119 -0
- data/lib/aws/s3/client.rb +1700 -0
- data/lib/aws/s3/client/xml.rb +231 -0
- data/lib/aws/s3/config.rb +36 -0
- data/lib/aws/s3/cors_rule.rb +106 -0
- data/lib/aws/s3/cors_rule_collection.rb +192 -0
- data/lib/aws/s3/data_options.rb +185 -0
- data/lib/aws/s3/encryption_utils.rb +139 -0
- data/lib/aws/s3/errors.rb +94 -0
- data/lib/aws/s3/multipart_upload.rb +320 -0
- data/lib/aws/s3/multipart_upload_collection.rb +68 -0
- data/lib/aws/s3/object_collection.rb +355 -0
- data/lib/aws/s3/object_metadata.rb +96 -0
- data/lib/aws/s3/object_upload_collection.rb +77 -0
- data/lib/aws/s3/object_version.rb +148 -0
- data/lib/aws/s3/object_version_collection.rb +89 -0
- data/lib/aws/s3/paginated_collection.rb +75 -0
- data/lib/aws/s3/policy.rb +74 -0
- data/lib/aws/s3/prefix_and_delimiter_collection.rb +47 -0
- data/lib/aws/s3/prefixed_collection.rb +81 -0
- data/lib/aws/s3/presigned_post.rb +555 -0
- data/lib/aws/s3/request.rb +201 -0
- data/lib/aws/s3/s3_object.rb +1690 -0
- data/lib/aws/s3/tree.rb +118 -0
- data/lib/aws/s3/tree/branch_node.rb +68 -0
- data/lib/aws/s3/tree/child_collection.rb +104 -0
- data/lib/aws/s3/tree/leaf_node.rb +94 -0
- data/lib/aws/s3/tree/node.rb +22 -0
- data/lib/aws/s3/tree/parent.rb +87 -0
- data/lib/aws/s3/uploaded_part.rb +80 -0
- data/lib/aws/s3/uploaded_part_collection.rb +84 -0
- data/lib/aws/s3/website_configuration.rb +102 -0
- data/lib/aws/simple_db.rb +219 -0
- data/lib/aws/simple_db/attribute.rb +154 -0
- data/lib/aws/simple_db/attribute_collection.rb +231 -0
- data/lib/aws/simple_db/client.rb +287 -0
- data/lib/aws/simple_db/config.rb +20 -0
- data/lib/aws/simple_db/consistent_read_option.rb +42 -0
- data/lib/aws/simple_db/delete_attributes.rb +62 -0
- data/lib/aws/simple_db/domain.rb +121 -0
- data/lib/aws/simple_db/domain_collection.rb +86 -0
- data/lib/aws/simple_db/domain_metadata.rb +110 -0
- data/lib/aws/simple_db/errors.rb +55 -0
- data/lib/aws/simple_db/expect_condition_option.rb +45 -0
- data/lib/aws/simple_db/item.rb +93 -0
- data/lib/aws/simple_db/item_collection.rb +649 -0
- data/lib/aws/simple_db/item_data.rb +73 -0
- data/lib/aws/simple_db/put_attributes.rb +60 -0
- data/lib/aws/simple_db/request.rb +23 -0
- data/lib/aws/simple_email_service.rb +428 -0
- data/lib/aws/simple_email_service/client.rb +276 -0
- data/lib/aws/simple_email_service/config.rb +19 -0
- data/lib/aws/simple_email_service/email_address_collection.rb +69 -0
- data/lib/aws/simple_email_service/errors.rb +22 -0
- data/lib/aws/simple_email_service/identity.rb +209 -0
- data/lib/aws/simple_email_service/identity_collection.rb +81 -0
- data/lib/aws/simple_email_service/quotas.rb +64 -0
- data/lib/aws/simple_email_service/request.rb +27 -0
- data/lib/aws/simple_workflow.rb +228 -0
- data/lib/aws/simple_workflow/activity_task.rb +173 -0
- data/lib/aws/simple_workflow/activity_task_collection.rb +123 -0
- data/lib/aws/simple_workflow/activity_type.rb +131 -0
- data/lib/aws/simple_workflow/activity_type_collection.rb +93 -0
- data/lib/aws/simple_workflow/client.rb +1204 -0
- data/lib/aws/simple_workflow/config.rb +18 -0
- data/lib/aws/simple_workflow/count.rb +49 -0
- data/lib/aws/simple_workflow/decision_task.rb +603 -0
- data/lib/aws/simple_workflow/decision_task_collection.rb +225 -0
- data/lib/aws/simple_workflow/domain.rb +122 -0
- data/lib/aws/simple_workflow/domain_collection.rb +169 -0
- data/lib/aws/simple_workflow/errors.rb +20 -0
- data/lib/aws/simple_workflow/history_event.rb +276 -0
- data/lib/aws/simple_workflow/history_event_collection.rb +76 -0
- data/lib/aws/simple_workflow/option_formatters.rb +82 -0
- data/lib/aws/simple_workflow/request.rb +33 -0
- data/lib/aws/simple_workflow/resource.rb +94 -0
- data/lib/aws/simple_workflow/type.rb +89 -0
- data/lib/aws/simple_workflow/type_collection.rb +140 -0
- data/lib/aws/simple_workflow/workflow_execution.rb +386 -0
- data/lib/aws/simple_workflow/workflow_execution_collection.rb +617 -0
- data/lib/aws/simple_workflow/workflow_type.rb +177 -0
- data/lib/aws/simple_workflow/workflow_type_collection.rb +91 -0
- data/lib/aws/sns.rb +76 -0
- data/lib/aws/sns/client.rb +266 -0
- data/lib/aws/sns/config.rb +18 -0
- data/lib/aws/sns/errors.rb +22 -0
- data/lib/aws/sns/has_delivery_policy.rb +68 -0
- data/lib/aws/sns/policy.rb +47 -0
- data/lib/aws/sns/request.rb +23 -0
- data/lib/aws/sns/subscription.rb +144 -0
- data/lib/aws/sns/subscription_collection.rb +78 -0
- data/lib/aws/sns/topic.rb +403 -0
- data/lib/aws/sns/topic_collection.rb +62 -0
- data/lib/aws/sns/topic_subscription_collection.rb +54 -0
- data/lib/aws/sqs.rb +81 -0
- data/lib/aws/sqs/client.rb +258 -0
- data/lib/aws/sqs/config.rb +18 -0
- data/lib/aws/sqs/errors.rb +101 -0
- data/lib/aws/sqs/policy.rb +48 -0
- data/lib/aws/sqs/queue.rb +764 -0
- data/lib/aws/sqs/queue_collection.rb +174 -0
- data/lib/aws/sqs/received_message.rb +181 -0
- data/lib/aws/sqs/received_sns_message.rb +116 -0
- data/lib/aws/sqs/request.rb +67 -0
- data/lib/aws/storage_gateway.rb +73 -0
- data/lib/aws/storage_gateway/client.rb +472 -0
- data/lib/aws/storage_gateway/config.rb +18 -0
- data/lib/aws/storage_gateway/errors.rb +22 -0
- data/lib/aws/storage_gateway/request.rb +28 -0
- data/lib/aws/sts.rb +163 -0
- data/lib/aws/sts/client.rb +157 -0
- data/lib/aws/sts/config.rb +18 -0
- data/lib/aws/sts/errors.rb +22 -0
- data/lib/aws/sts/federated_session.rb +56 -0
- data/lib/aws/sts/policy.rb +30 -0
- data/lib/aws/sts/request.rb +29 -0
- data/lib/aws/sts/session.rb +48 -0
- data/lib/aws/version.rb +18 -0
- data/lib/net/http/connection_pool.rb +226 -0
- data/lib/net/http/connection_pool/connection.rb +189 -0
- data/lib/net/http/connection_pool/session.rb +126 -0
- data/rails/init.rb +15 -0
- metadata +632 -0
|
@@ -0,0 +1,109 @@
|
|
|
1
|
+
# Copyright 2011-2013 Amazon.com, Inc. or its affiliates. All Rights Reserved.
|
|
2
|
+
#
|
|
3
|
+
# Licensed under the Apache License, Version 2.0 (the "License"). You
|
|
4
|
+
# may not use this file except in compliance with the License. A copy of
|
|
5
|
+
# the License is located at
|
|
6
|
+
#
|
|
7
|
+
# http://aws.amazon.com/apache2.0/
|
|
8
|
+
#
|
|
9
|
+
# or in the "license" file accompanying this file. This file is
|
|
10
|
+
# distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF
|
|
11
|
+
# ANY KIND, either express or implied. See the License for the specific
|
|
12
|
+
# language governing permissions and limitations under the License.
|
|
13
|
+
|
|
14
|
+
module AWS
|
|
15
|
+
class S3
|
|
16
|
+
|
|
17
|
+
# Manages tags for a single S3 {Bucket}.
|
|
18
|
+
#
|
|
19
|
+
# @example Setting a tag.
|
|
20
|
+
#
|
|
21
|
+
# bucket.tags['key'] = 'value'
|
|
22
|
+
#
|
|
23
|
+
# @example Getting a tag.
|
|
24
|
+
#
|
|
25
|
+
# bucket.tags['key']
|
|
26
|
+
# #=> 'value'
|
|
27
|
+
#
|
|
28
|
+
# @example Getting all tags
|
|
29
|
+
#
|
|
30
|
+
# bucket.tags.to_h
|
|
31
|
+
# #=> { 'key' => 'value', ... }
|
|
32
|
+
#
|
|
33
|
+
# @example Removing all tags
|
|
34
|
+
#
|
|
35
|
+
# bucket.tags.clear
|
|
36
|
+
#
|
|
37
|
+
class BucketTagCollection
|
|
38
|
+
|
|
39
|
+
include Core::Model
|
|
40
|
+
|
|
41
|
+
# @param [Bucket] bucket
|
|
42
|
+
# @param [Hash] options
|
|
43
|
+
def initialize bucket, options = {}
|
|
44
|
+
@bucket = bucket
|
|
45
|
+
super
|
|
46
|
+
end
|
|
47
|
+
|
|
48
|
+
# @return [Bucket]
|
|
49
|
+
attr_reader :bucket
|
|
50
|
+
|
|
51
|
+
# @param [String] key
|
|
52
|
+
# @return [String,nil] Returns the tag for the given key. If there
|
|
53
|
+
# Returns +nil+ if the key does not exist.
|
|
54
|
+
def [] key
|
|
55
|
+
self.to_h[key]
|
|
56
|
+
end
|
|
57
|
+
|
|
58
|
+
# @param [String] key
|
|
59
|
+
# @param [String] value
|
|
60
|
+
def []= key, value
|
|
61
|
+
self.set(self.to_h.merge(key => value))
|
|
62
|
+
end
|
|
63
|
+
|
|
64
|
+
# @param [Hash<String,String>] tags A hash of tag keys and values.
|
|
65
|
+
# @return [nil]
|
|
66
|
+
def set tags
|
|
67
|
+
if tags.nil? or tags.empty?
|
|
68
|
+
self.clear
|
|
69
|
+
else
|
|
70
|
+
client.put_bucket_tagging(:bucket_name => bucket.name, :tags => tags)
|
|
71
|
+
end
|
|
72
|
+
nil
|
|
73
|
+
end
|
|
74
|
+
|
|
75
|
+
# Removes all tags from the bucket.
|
|
76
|
+
#
|
|
77
|
+
# bucket.tags.clear
|
|
78
|
+
# bucket.tags.to_h #=> {}
|
|
79
|
+
#
|
|
80
|
+
# @return [nil]
|
|
81
|
+
def clear
|
|
82
|
+
client.delete_bucket_tagging(:bucket_name => bucket.name)
|
|
83
|
+
nil
|
|
84
|
+
end
|
|
85
|
+
|
|
86
|
+
# @return [Hash]
|
|
87
|
+
def to_h
|
|
88
|
+
client.get_bucket_tagging(:bucket_name => bucket.name).data[:tags]
|
|
89
|
+
rescue AWS::S3::Errors::NoSuchTagSet
|
|
90
|
+
{}
|
|
91
|
+
end
|
|
92
|
+
alias_method :to_hash, :to_h
|
|
93
|
+
|
|
94
|
+
# @param [Hash] other
|
|
95
|
+
# @return [Boolean] Returns +true+ if the tags for this bucket match
|
|
96
|
+
# the passed hash.
|
|
97
|
+
def eql? other
|
|
98
|
+
self.to_h == other
|
|
99
|
+
end
|
|
100
|
+
alias_method :==, :eql?
|
|
101
|
+
|
|
102
|
+
# @private
|
|
103
|
+
def inspect
|
|
104
|
+
self.to_h.inspect
|
|
105
|
+
end
|
|
106
|
+
|
|
107
|
+
end
|
|
108
|
+
end
|
|
109
|
+
end
|
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
# Copyright 2011-2013 Amazon.com, Inc. or its affiliates. All Rights Reserved.
|
|
2
|
+
#
|
|
3
|
+
# Licensed under the Apache License, Version 2.0 (the "License"). You
|
|
4
|
+
# may not use this file except in compliance with the License. A copy of
|
|
5
|
+
# the License is located at
|
|
6
|
+
#
|
|
7
|
+
# http://aws.amazon.com/apache2.0/
|
|
8
|
+
#
|
|
9
|
+
# or in the "license" file accompanying this file. This file is
|
|
10
|
+
# distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF
|
|
11
|
+
# ANY KIND, either express or implied. See the License for the specific
|
|
12
|
+
# language governing permissions and limitations under the License.
|
|
13
|
+
|
|
14
|
+
module AWS
|
|
15
|
+
class S3
|
|
16
|
+
|
|
17
|
+
# A collection of versioned objects for the entire bucket.
|
|
18
|
+
#
|
|
19
|
+
# @see PrefixedCollection
|
|
20
|
+
class BucketVersionCollection
|
|
21
|
+
|
|
22
|
+
include PrefixAndDelimiterCollection
|
|
23
|
+
|
|
24
|
+
# @param [Bucket] bucket
|
|
25
|
+
def initialize bucket, options = {}
|
|
26
|
+
@bucket = bucket
|
|
27
|
+
super
|
|
28
|
+
end
|
|
29
|
+
|
|
30
|
+
# @return [Bucket] The bucket this collection belongs to.
|
|
31
|
+
attr_reader :bucket
|
|
32
|
+
|
|
33
|
+
# @return [ObjectVersion] Returns the most recently created object
|
|
34
|
+
# version in the entire bucket.
|
|
35
|
+
def latest
|
|
36
|
+
first
|
|
37
|
+
#self.find{|version| true }
|
|
38
|
+
end
|
|
39
|
+
|
|
40
|
+
# Yields once for each version in the bucket.
|
|
41
|
+
#
|
|
42
|
+
# @yield [object_version]
|
|
43
|
+
#
|
|
44
|
+
# @yieldparam [ObjectVersion] object_version
|
|
45
|
+
#
|
|
46
|
+
# @return nil
|
|
47
|
+
#
|
|
48
|
+
def each options = {}, █ super; end
|
|
49
|
+
|
|
50
|
+
# @private
|
|
51
|
+
protected
|
|
52
|
+
def each_member_in_page(page, &block)
|
|
53
|
+
super
|
|
54
|
+
page.versions.each do |version|
|
|
55
|
+
object_version = ObjectVersion.new(bucket.objects[version.key],
|
|
56
|
+
version.version_id, :delete_marker => version.delete_marker?)
|
|
57
|
+
yield(object_version)
|
|
58
|
+
end
|
|
59
|
+
end
|
|
60
|
+
|
|
61
|
+
# @private
|
|
62
|
+
protected
|
|
63
|
+
def list_request(options)
|
|
64
|
+
client.list_object_versions(options)
|
|
65
|
+
end
|
|
66
|
+
|
|
67
|
+
# @private
|
|
68
|
+
protected
|
|
69
|
+
def limit_param; :max_keys; end
|
|
70
|
+
|
|
71
|
+
# @private
|
|
72
|
+
protected
|
|
73
|
+
def pagination_markers; super + [:version_id_marker]; end
|
|
74
|
+
|
|
75
|
+
end
|
|
76
|
+
end
|
|
77
|
+
end
|
|
@@ -0,0 +1,119 @@
|
|
|
1
|
+
# Copyright 2011-2013 Amazon.com, Inc. or its affiliates. All Rights Reserved.
|
|
2
|
+
#
|
|
3
|
+
# Licensed under the Apache License, Version 2.0 (the "License"). You
|
|
4
|
+
# may not use this file except in compliance with the License. A copy of
|
|
5
|
+
# the License is located at
|
|
6
|
+
#
|
|
7
|
+
# http://aws.amazon.com/apache2.0/
|
|
8
|
+
#
|
|
9
|
+
# or in the "license" file accompanying this file. This file is
|
|
10
|
+
# distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF
|
|
11
|
+
# ANY KIND, either express or implied. See the License for the specific
|
|
12
|
+
# language governing permissions and limitations under the License.
|
|
13
|
+
|
|
14
|
+
module AWS
|
|
15
|
+
class S3
|
|
16
|
+
|
|
17
|
+
# @private
|
|
18
|
+
class CipherIO
|
|
19
|
+
|
|
20
|
+
def initialize cipher, stream, stream_size = nil
|
|
21
|
+
|
|
22
|
+
@stream = stream
|
|
23
|
+
@stream_size = stream_size
|
|
24
|
+
@orig_cipher = cipher.clone
|
|
25
|
+
|
|
26
|
+
reset_cipher
|
|
27
|
+
|
|
28
|
+
# add a #rewind method if the original stream can be rewound
|
|
29
|
+
if @stream.respond_to?(:rewind)
|
|
30
|
+
Core::MetaUtils.extend_method(self, :rewind) do
|
|
31
|
+
reset_cipher
|
|
32
|
+
@stream.rewind
|
|
33
|
+
end
|
|
34
|
+
end
|
|
35
|
+
|
|
36
|
+
# add a #size method if the stream size is known
|
|
37
|
+
if stream_size
|
|
38
|
+
Core::MetaUtils.extend_method(self, :size) do
|
|
39
|
+
EncryptionUtils.get_encrypted_size(@stream_size)
|
|
40
|
+
end
|
|
41
|
+
end
|
|
42
|
+
|
|
43
|
+
end
|
|
44
|
+
|
|
45
|
+
# @return [String] Returns the requested number of bytes. If no byte
|
|
46
|
+
# amount is given, it will return the entire body of encrypted data
|
|
47
|
+
def read bytes = nil
|
|
48
|
+
if bytes
|
|
49
|
+
(@eof) ? nil : read_chunk(bytes)
|
|
50
|
+
else
|
|
51
|
+
(@eof) ? "" : read_all()
|
|
52
|
+
end
|
|
53
|
+
end
|
|
54
|
+
|
|
55
|
+
# @return [Boolean] Returns +true+ when the entire stream has been read.
|
|
56
|
+
def eof?
|
|
57
|
+
@eof
|
|
58
|
+
end
|
|
59
|
+
|
|
60
|
+
private
|
|
61
|
+
|
|
62
|
+
attr_reader :cipher
|
|
63
|
+
|
|
64
|
+
# Sets the CipherIO in a reset state without having to know anything
|
|
65
|
+
# about the cipher
|
|
66
|
+
def reset_cipher
|
|
67
|
+
@cipher = @orig_cipher.clone
|
|
68
|
+
@eof = false
|
|
69
|
+
@final = nil
|
|
70
|
+
end
|
|
71
|
+
|
|
72
|
+
# @return [String] Returns an encrytped chunk
|
|
73
|
+
def read_chunk bytes
|
|
74
|
+
unless @final
|
|
75
|
+
# If given a number of bytes, read it out and work out encryption
|
|
76
|
+
# issues
|
|
77
|
+
chunk = @stream.read(bytes)
|
|
78
|
+
|
|
79
|
+
# If there is nothing, finish the encryption
|
|
80
|
+
if chunk and chunk.length > 0
|
|
81
|
+
handle_finish(bytes, cipher.update(chunk))
|
|
82
|
+
else
|
|
83
|
+
@eof = true
|
|
84
|
+
cipher.final
|
|
85
|
+
end
|
|
86
|
+
# Read as much as possible if not given a byte size
|
|
87
|
+
else
|
|
88
|
+
@eof = true
|
|
89
|
+
@final
|
|
90
|
+
end
|
|
91
|
+
end
|
|
92
|
+
|
|
93
|
+
# @return [String] Returns the entire encrypted data
|
|
94
|
+
def read_all
|
|
95
|
+
@eof = true
|
|
96
|
+
body = @stream.read()
|
|
97
|
+
data = (body and body.length > 0) ? cipher.update(body) : ""
|
|
98
|
+
data << cipher.final
|
|
99
|
+
end
|
|
100
|
+
|
|
101
|
+
# Figures out how much of the final block goes into the current chunk
|
|
102
|
+
# and adds it.
|
|
103
|
+
# @return [String] Returns the encrypted chunk with possible padding.
|
|
104
|
+
def handle_finish(bytes, chunk)
|
|
105
|
+
free_space = bytes - chunk.size
|
|
106
|
+
|
|
107
|
+
if free_space > 0
|
|
108
|
+
@final = cipher.final
|
|
109
|
+
chunk << @final[0..free_space-1]
|
|
110
|
+
@final = @final[free_space-1..@final.size-1]
|
|
111
|
+
@eof = true unless @final and @final.size > 0
|
|
112
|
+
end
|
|
113
|
+
|
|
114
|
+
chunk
|
|
115
|
+
end
|
|
116
|
+
|
|
117
|
+
end
|
|
118
|
+
end
|
|
119
|
+
end
|
|
@@ -0,0 +1,1700 @@
|
|
|
1
|
+
# Copyright 2011-2013 Amazon.com, Inc. or its affiliates. All Rights Reserved.
|
|
2
|
+
#
|
|
3
|
+
# Licensed under the Apache License, Version 2.0 (the "License"). You
|
|
4
|
+
# may not use this file except in compliance with the License. A copy of
|
|
5
|
+
# the License is located at
|
|
6
|
+
#
|
|
7
|
+
# http://aws.amazon.com/apache2.0/
|
|
8
|
+
#
|
|
9
|
+
# or in the "license" file accompanying this file. This file is
|
|
10
|
+
# distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF
|
|
11
|
+
# ANY KIND, either express or implied. See the License for the specific
|
|
12
|
+
# language governing permissions and limitations under the License.
|
|
13
|
+
|
|
14
|
+
require 'rexml/document'
|
|
15
|
+
require 'pathname'
|
|
16
|
+
require 'stringio'
|
|
17
|
+
require 'json'
|
|
18
|
+
require 'digest/md5'
|
|
19
|
+
require 'base64'
|
|
20
|
+
require 'nokogiri'
|
|
21
|
+
|
|
22
|
+
module AWS
|
|
23
|
+
class S3
|
|
24
|
+
|
|
25
|
+
# Client class for Amazon Simple Storage Service (S3).
|
|
26
|
+
class Client < Core::Client
|
|
27
|
+
|
|
28
|
+
API_VERSION = '2006-03-01'
|
|
29
|
+
|
|
30
|
+
XMLNS = "http://s3.amazonaws.com/doc/#{API_VERSION}/"
|
|
31
|
+
|
|
32
|
+
AWS.register_autoloads(self) do
|
|
33
|
+
autoload :XML, 'xml'
|
|
34
|
+
end
|
|
35
|
+
|
|
36
|
+
# @private
|
|
37
|
+
EMPTY_BODY_ERRORS = {
|
|
38
|
+
304 => Errors::NotModified,
|
|
39
|
+
403 => Errors::Forbidden,
|
|
40
|
+
400 => Errors::BadRequest,
|
|
41
|
+
404 => Errors::NoSuchKey,
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
# @private
|
|
45
|
+
CACHEABLE_REQUESTS = Set[]
|
|
46
|
+
|
|
47
|
+
include DataOptions
|
|
48
|
+
include Core::UriEscape
|
|
49
|
+
|
|
50
|
+
protected
|
|
51
|
+
|
|
52
|
+
def self.bucket_method(method_name, verb, *args, &block)
|
|
53
|
+
|
|
54
|
+
method_options = (args.pop if args.last.kind_of?(Hash)) || {}
|
|
55
|
+
xml_grammar = (args.pop if args.last.respond_to?(:rules))
|
|
56
|
+
verb = verb.to_s.upcase
|
|
57
|
+
subresource = args.first
|
|
58
|
+
|
|
59
|
+
add_client_request_method(method_name) do
|
|
60
|
+
|
|
61
|
+
configure_request do |req, options|
|
|
62
|
+
|
|
63
|
+
require_bucket_name!(options[:bucket_name])
|
|
64
|
+
|
|
65
|
+
req.http_method = verb
|
|
66
|
+
req.bucket = options[:bucket_name]
|
|
67
|
+
req.add_param(subresource) if subresource
|
|
68
|
+
|
|
69
|
+
if header_options = method_options[:header_options]
|
|
70
|
+
header_options.each do |(opt, header)|
|
|
71
|
+
if value = options[opt]
|
|
72
|
+
# for backwards compatability we translate canned acls
|
|
73
|
+
# header values from symbols to strings (e.g.
|
|
74
|
+
# :public_read translates to 'public-read')
|
|
75
|
+
value = (opt == :acl ? value.to_s.tr('_', '-') : value)
|
|
76
|
+
req.headers[header] = value
|
|
77
|
+
end
|
|
78
|
+
end
|
|
79
|
+
end
|
|
80
|
+
|
|
81
|
+
end
|
|
82
|
+
|
|
83
|
+
instance_eval(&block) if block
|
|
84
|
+
|
|
85
|
+
if xml_grammar
|
|
86
|
+
|
|
87
|
+
parser = Core::XML::Parser.new(xml_grammar.rules)
|
|
88
|
+
|
|
89
|
+
process_response do |resp|
|
|
90
|
+
resp.data = parser.parse(resp.http_response.body)
|
|
91
|
+
super(resp)
|
|
92
|
+
end
|
|
93
|
+
|
|
94
|
+
simulate_response do |resp|
|
|
95
|
+
resp.data = parser.simulate
|
|
96
|
+
super(resp)
|
|
97
|
+
end
|
|
98
|
+
|
|
99
|
+
end
|
|
100
|
+
|
|
101
|
+
end
|
|
102
|
+
end
|
|
103
|
+
|
|
104
|
+
def self.object_method(method_name, verb, *args, &block)
|
|
105
|
+
bucket_method(method_name, verb, *args) do
|
|
106
|
+
configure_request do |req, options|
|
|
107
|
+
validate_key!(options[:key])
|
|
108
|
+
super(req, options)
|
|
109
|
+
req.key = options[:key]
|
|
110
|
+
end
|
|
111
|
+
|
|
112
|
+
instance_eval(&block) if block
|
|
113
|
+
end
|
|
114
|
+
end
|
|
115
|
+
|
|
116
|
+
public
|
|
117
|
+
|
|
118
|
+
# Creates a bucket.
|
|
119
|
+
# @overload create_bucket(options = {})
|
|
120
|
+
# @param [Hash] options
|
|
121
|
+
# @option options [required,String] :bucket_name
|
|
122
|
+
# @option options [String] :acl A canned ACL (e.g. 'private',
|
|
123
|
+
# 'public-read', etc). See the S3 API documentation for
|
|
124
|
+
# a complete list of valid values.
|
|
125
|
+
# @option options [String] :grant_read
|
|
126
|
+
# @option options [String] :grant_write
|
|
127
|
+
# @option options [String] :grant_read_acp
|
|
128
|
+
# @option options [String] :grant_write_acp
|
|
129
|
+
# @option options [String] :grant_full_control
|
|
130
|
+
# @return [Core::Response]
|
|
131
|
+
bucket_method(:create_bucket, :put, :header_options => {
|
|
132
|
+
:acl => 'x-amz-acl',
|
|
133
|
+
:grant_read => 'x-amz-grant-read',
|
|
134
|
+
:grant_write => 'x-amz-grant-write',
|
|
135
|
+
:grant_read_acp => 'x-amz-grant-read-acp',
|
|
136
|
+
:grant_write_acp => 'x-amz-grant-write-acp',
|
|
137
|
+
:grant_full_control => 'x-amz-grant-full-control',
|
|
138
|
+
}) do
|
|
139
|
+
|
|
140
|
+
configure_request do |req, options|
|
|
141
|
+
validate_bucket_name!(options[:bucket_name])
|
|
142
|
+
if location = options[:location_constraint]
|
|
143
|
+
xmlns = "http://s3.amazonaws.com/doc/#{API_VERSION}/"
|
|
144
|
+
req.body = <<-XML
|
|
145
|
+
<CreateBucketConfiguration xmlns="#{xmlns}">
|
|
146
|
+
<LocationConstraint>#{location}</LocationConstraint>
|
|
147
|
+
</CreateBucketConfiguration>
|
|
148
|
+
XML
|
|
149
|
+
end
|
|
150
|
+
super(req, options)
|
|
151
|
+
end
|
|
152
|
+
|
|
153
|
+
end
|
|
154
|
+
alias_method :put_bucket, :create_bucket
|
|
155
|
+
|
|
156
|
+
# @!method put_bucket_website(options = {})
|
|
157
|
+
# @param [Hash] options
|
|
158
|
+
# @option (see WebsiteConfiguration#initialize)
|
|
159
|
+
# @option options [required,String] :bucket_name
|
|
160
|
+
# @return [Core::Response]
|
|
161
|
+
bucket_method(:put_bucket_website, :put, 'website') do
|
|
162
|
+
|
|
163
|
+
configure_request do |req, options|
|
|
164
|
+
validate_bucket_name!(options[:bucket_name])
|
|
165
|
+
req.body = Nokogiri::XML::Builder.new do |xml|
|
|
166
|
+
xml.WebsiteConfiguration(:xmlns => XMLNS) do
|
|
167
|
+
|
|
168
|
+
if redirect = options[:redirect_all_requests_to]
|
|
169
|
+
xml.RedirectAllRequestsTo do
|
|
170
|
+
xml.HostName(redirect[:host_name])
|
|
171
|
+
xml.Protocol(redirect[:protocol]) if redirect[:protocol]
|
|
172
|
+
end
|
|
173
|
+
end
|
|
174
|
+
|
|
175
|
+
if indx = options[:index_document]
|
|
176
|
+
xml.IndexDocument do
|
|
177
|
+
xml.Suffix(indx[:suffix])
|
|
178
|
+
end
|
|
179
|
+
end
|
|
180
|
+
|
|
181
|
+
if err = options[:error_document]
|
|
182
|
+
xml.ErrorDocument do
|
|
183
|
+
xml.Key(err[:key])
|
|
184
|
+
end
|
|
185
|
+
end
|
|
186
|
+
|
|
187
|
+
if rules = options[:routing_rules]
|
|
188
|
+
xml.RoutingRules do
|
|
189
|
+
rules.each do |rule|
|
|
190
|
+
xml.RoutingRule do
|
|
191
|
+
|
|
192
|
+
redirect = rule[:redirect]
|
|
193
|
+
xml.Redirect do
|
|
194
|
+
xml.Protocol(redirect[:protocol]) if redirect[:protocol]
|
|
195
|
+
xml.HostName(redirect[:host_name]) if redirect[:host_name]
|
|
196
|
+
xml.ReplaceKeyPrefixWith(redirect[:replace_key_prefix_with]) if redirect[:replace_key_prefix_with]
|
|
197
|
+
xml.ReplaceKeyWith(redirect[:replace_key_with]) if redirect[:replace_key_with]
|
|
198
|
+
xml.HttpRedirectCode(redirect[:http_redirect_code]) if redirect[:http_redirect_code]
|
|
199
|
+
end
|
|
200
|
+
|
|
201
|
+
if condition = rule[:condition]
|
|
202
|
+
xml.Condition do
|
|
203
|
+
xml.KeyPrefixEquals(condition[:key_prefix_equals]) if condition[:key_prefix_equals]
|
|
204
|
+
xml.HttpErrorCodeReturnedEquals(condition[:http_error_code_returned_equals]) if condition[:http_error_code_returned_equals]
|
|
205
|
+
end
|
|
206
|
+
end
|
|
207
|
+
|
|
208
|
+
end
|
|
209
|
+
end
|
|
210
|
+
end
|
|
211
|
+
end
|
|
212
|
+
|
|
213
|
+
end
|
|
214
|
+
end.doc.root.to_xml
|
|
215
|
+
super(req, options)
|
|
216
|
+
end
|
|
217
|
+
|
|
218
|
+
end
|
|
219
|
+
|
|
220
|
+
# @overload get_bucket_website(options = {})
|
|
221
|
+
# @param [Hash] options
|
|
222
|
+
# @option options [required,String] :bucket_name
|
|
223
|
+
# @return [Core::Response]
|
|
224
|
+
# * +:index_document+ - (Hash)
|
|
225
|
+
# * +:suffix+ - (String)
|
|
226
|
+
# * +:error_document+ - (Hash)
|
|
227
|
+
# * +:key+ - (String)
|
|
228
|
+
bucket_method(:get_bucket_website, :get, 'website', XML::GetBucketWebsite)
|
|
229
|
+
|
|
230
|
+
# @overload delete_bucket_website(options = {})
|
|
231
|
+
# @param [Hash] options
|
|
232
|
+
# @option options [required,String] :bucket_name
|
|
233
|
+
# @return [Core::Response]
|
|
234
|
+
bucket_method(:delete_bucket_website, :delete, 'website')
|
|
235
|
+
|
|
236
|
+
# Deletes an empty bucket.
|
|
237
|
+
# @overload delete_bucket(options = {})
|
|
238
|
+
# @param [Hash] options
|
|
239
|
+
# @option options [required,String] :bucket_name
|
|
240
|
+
# @return [Core::Response]
|
|
241
|
+
bucket_method(:delete_bucket, :delete)
|
|
242
|
+
|
|
243
|
+
# @overload set_bucket_lifecycle_configuration(options = {})
|
|
244
|
+
# @param [Hash] options
|
|
245
|
+
# @option options [required,String] :bucket_name
|
|
246
|
+
# @option options [required,String] :lifecycle_configuration
|
|
247
|
+
# @return [Core::Response]
|
|
248
|
+
bucket_method(:set_bucket_lifecycle_configuration, :put) do
|
|
249
|
+
|
|
250
|
+
configure_request do |req, options|
|
|
251
|
+
xml = options[:lifecycle_configuration]
|
|
252
|
+
req.add_param('lifecycle')
|
|
253
|
+
req.body = xml
|
|
254
|
+
req.headers['content-md5'] = md5(xml)
|
|
255
|
+
super(req, options)
|
|
256
|
+
end
|
|
257
|
+
|
|
258
|
+
end
|
|
259
|
+
|
|
260
|
+
# @overload get_bucket_lifecycle_configuration(options = {})
|
|
261
|
+
# @param [Hash] options
|
|
262
|
+
# @option options [required,String] :bucket_name
|
|
263
|
+
# @return [Core::Response]
|
|
264
|
+
bucket_method(:get_bucket_lifecycle_configuration, :get) do
|
|
265
|
+
|
|
266
|
+
configure_request do |req, options|
|
|
267
|
+
req.add_param('lifecycle')
|
|
268
|
+
super(req, options)
|
|
269
|
+
end
|
|
270
|
+
|
|
271
|
+
process_response do |resp|
|
|
272
|
+
xml = resp.http_response.body
|
|
273
|
+
resp.data = XML::GetBucketLifecycleConfiguration.parse(xml)
|
|
274
|
+
end
|
|
275
|
+
|
|
276
|
+
end
|
|
277
|
+
|
|
278
|
+
# @overload delete_bucket_lifecycle_configuration(options = {})
|
|
279
|
+
# @param [Hash] options
|
|
280
|
+
# @option options [required,String] :bucket_name
|
|
281
|
+
# @return [Core::Response]
|
|
282
|
+
bucket_method(:delete_bucket_lifecycle_configuration, :delete) do
|
|
283
|
+
|
|
284
|
+
configure_request do |req, options|
|
|
285
|
+
req.add_param('lifecycle')
|
|
286
|
+
super(req, options)
|
|
287
|
+
end
|
|
288
|
+
|
|
289
|
+
end
|
|
290
|
+
|
|
291
|
+
# @overload put_bucket_cors(options = {})
|
|
292
|
+
# @param [Hash] options
|
|
293
|
+
# @option options [required,String] :bucket_name
|
|
294
|
+
# @option options [required,Array<Hash>] :rules An array of rule hashes.
|
|
295
|
+
# * +:id+ - (String) A unique identifier for the rule. The ID
|
|
296
|
+
# value can be up to 255 characters long. The IDs help you find
|
|
297
|
+
# a rule in the configuration.
|
|
298
|
+
# * +:allowed_methods+ - (required,Array<String>) A list of HTTP
|
|
299
|
+
# methods that you want to allow the origin to execute.
|
|
300
|
+
# Each rule must identify at least one method.
|
|
301
|
+
# * +:allowed_origins+ - (required,Array<String>) A list of origins
|
|
302
|
+
# you want to allow cross-domain requests from. This can
|
|
303
|
+
# contain at most one * wild character.
|
|
304
|
+
# * +:allowed_headers+ - (Array<String>) A list of headers allowed
|
|
305
|
+
# in a pre-flight OPTIONS request via the
|
|
306
|
+
# Access-Control-Request-Headers header. Each header name
|
|
307
|
+
# specified in the Access-Control-Request-Headers header must
|
|
308
|
+
# have a corresponding entry in the rule.
|
|
309
|
+
# Amazon S3 will send only the allowed headers in a response
|
|
310
|
+
# that were requested. This can contain at most one * wild
|
|
311
|
+
# character.
|
|
312
|
+
# * +:max_age_seconds+ - (Integer) The time in seconds that your
|
|
313
|
+
# browser is to cache the preflight response for the specified
|
|
314
|
+
# resource.
|
|
315
|
+
# * +:expose_headers+ - (Array<String>) One or more headers in
|
|
316
|
+
# the response that you want customers to be able to access
|
|
317
|
+
# from their applications (for example, from a JavaScript
|
|
318
|
+
# XMLHttpRequest object).
|
|
319
|
+
# @return [Core::Response]
|
|
320
|
+
bucket_method(:put_bucket_cors, :put) do
|
|
321
|
+
configure_request do |req, options|
|
|
322
|
+
|
|
323
|
+
req.add_param('cors')
|
|
324
|
+
|
|
325
|
+
xml = Nokogiri::XML::Builder.new do |xml|
|
|
326
|
+
xml.CORSConfiguration do
|
|
327
|
+
options[:rules].each do |rule|
|
|
328
|
+
xml.CORSRule do
|
|
329
|
+
|
|
330
|
+
xml.ID(rule[:id]) if rule[:id]
|
|
331
|
+
|
|
332
|
+
(rule[:allowed_methods] || []).each do |method|
|
|
333
|
+
xml.AllowedMethod(method)
|
|
334
|
+
end
|
|
335
|
+
|
|
336
|
+
(rule[:allowed_origins] || []).each do |origin|
|
|
337
|
+
xml.AllowedOrigin(origin)
|
|
338
|
+
end
|
|
339
|
+
|
|
340
|
+
(rule[:allowed_headers] || []).each do |header|
|
|
341
|
+
xml.AllowedHeader(header)
|
|
342
|
+
end
|
|
343
|
+
|
|
344
|
+
xml.MaxAgeSeconds(rule[:max_age_seconds]) if
|
|
345
|
+
rule[:max_age_seconds]
|
|
346
|
+
|
|
347
|
+
(rule[:expose_headers] || []).each do |header|
|
|
348
|
+
xml.ExposeHeader(header)
|
|
349
|
+
end
|
|
350
|
+
|
|
351
|
+
end
|
|
352
|
+
end
|
|
353
|
+
end
|
|
354
|
+
end.doc.root.to_xml
|
|
355
|
+
|
|
356
|
+
req.body = xml
|
|
357
|
+
req.headers['content-md5'] = md5(xml)
|
|
358
|
+
|
|
359
|
+
super(req, options)
|
|
360
|
+
|
|
361
|
+
end
|
|
362
|
+
end
|
|
363
|
+
|
|
364
|
+
# @overload get_bucket_cors(options = {})
|
|
365
|
+
# @param [Hash] options
|
|
366
|
+
# @option options [required,String] :bucket_name
|
|
367
|
+
# @return [Core::Response]
|
|
368
|
+
bucket_method(:get_bucket_cors, :get) do
|
|
369
|
+
|
|
370
|
+
configure_request do |req, options|
|
|
371
|
+
req.add_param('cors')
|
|
372
|
+
super(req, options)
|
|
373
|
+
end
|
|
374
|
+
|
|
375
|
+
process_response do |resp|
|
|
376
|
+
resp.data = XML::GetBucketCors.parse(resp.http_response.body)
|
|
377
|
+
end
|
|
378
|
+
|
|
379
|
+
end
|
|
380
|
+
|
|
381
|
+
# @overload delete_bucket_cors(options = {})
|
|
382
|
+
# @param [Hash] options
|
|
383
|
+
# @option options [required,String] :bucket_name
|
|
384
|
+
# @return [Core::Response]
|
|
385
|
+
bucket_method(:delete_bucket_cors, :delete) do
|
|
386
|
+
configure_request do |req, options|
|
|
387
|
+
req.add_param('cors')
|
|
388
|
+
super(req, options)
|
|
389
|
+
end
|
|
390
|
+
end
|
|
391
|
+
|
|
392
|
+
# @overload put_bucket_tagging(options = {})
|
|
393
|
+
# @param [Hash] options
|
|
394
|
+
# @option options [required,String] :bucket_name
|
|
395
|
+
# @option options [Hash] :tags
|
|
396
|
+
# @return [Core::Response]
|
|
397
|
+
bucket_method(:put_bucket_tagging, :put) do
|
|
398
|
+
configure_request do |req, options|
|
|
399
|
+
|
|
400
|
+
req.add_param('tagging')
|
|
401
|
+
|
|
402
|
+
xml = Nokogiri::XML::Builder.new
|
|
403
|
+
xml.Tagging do |xml|
|
|
404
|
+
xml.TagSet do
|
|
405
|
+
options[:tags].each_pair do |key,value|
|
|
406
|
+
xml.Tag do
|
|
407
|
+
xml.Key(key)
|
|
408
|
+
xml.Value(value)
|
|
409
|
+
end
|
|
410
|
+
end
|
|
411
|
+
end
|
|
412
|
+
end
|
|
413
|
+
|
|
414
|
+
xml = xml.doc.root.to_xml
|
|
415
|
+
req.body = xml
|
|
416
|
+
req.headers['content-md5'] = md5(xml)
|
|
417
|
+
|
|
418
|
+
super(req, options)
|
|
419
|
+
|
|
420
|
+
end
|
|
421
|
+
end
|
|
422
|
+
|
|
423
|
+
# @overload get_bucket_tagging(options = {})
|
|
424
|
+
# @param [Hash] options
|
|
425
|
+
# @option options [required,String] :bucket_name
|
|
426
|
+
# @return [Core::Response]
|
|
427
|
+
bucket_method(:get_bucket_tagging, :get) do
|
|
428
|
+
|
|
429
|
+
configure_request do |req, options|
|
|
430
|
+
req.add_param('tagging')
|
|
431
|
+
super(req, options)
|
|
432
|
+
end
|
|
433
|
+
|
|
434
|
+
process_response do |resp|
|
|
435
|
+
resp.data = XML::GetBucketTagging.parse(resp.http_response.body)
|
|
436
|
+
end
|
|
437
|
+
|
|
438
|
+
end
|
|
439
|
+
|
|
440
|
+
# @overload delete_bucket_tagging(options = {})
|
|
441
|
+
# @param [Hash] options
|
|
442
|
+
# @option options [required,String] :bucket_name
|
|
443
|
+
# @return [Core::Response]
|
|
444
|
+
bucket_method(:delete_bucket_tagging, :delete) do
|
|
445
|
+
configure_request do |req, options|
|
|
446
|
+
req.add_param('tagging')
|
|
447
|
+
super(req, options)
|
|
448
|
+
end
|
|
449
|
+
end
|
|
450
|
+
|
|
451
|
+
# @overload list_buckets(options = {})
|
|
452
|
+
# @param [Hash] options
|
|
453
|
+
# @return [Core::Response]
|
|
454
|
+
add_client_request_method(:list_buckets) do
|
|
455
|
+
|
|
456
|
+
configure_request do |req, options|
|
|
457
|
+
req.http_method = "GET"
|
|
458
|
+
end
|
|
459
|
+
|
|
460
|
+
process_response do |resp|
|
|
461
|
+
resp.data = XML::ListBuckets.parse(resp.http_response.body)
|
|
462
|
+
end
|
|
463
|
+
|
|
464
|
+
simulate_response do |resp|
|
|
465
|
+
resp.data = Core::XML::Parser.new(XML::ListBuckets.rules).simulate
|
|
466
|
+
end
|
|
467
|
+
|
|
468
|
+
end
|
|
469
|
+
|
|
470
|
+
# Sets the access policy for a bucket.
|
|
471
|
+
# @overload set_bucket_policy(options = {})
|
|
472
|
+
# @param [Hash] options
|
|
473
|
+
# @option options [required,String] :bucket_name
|
|
474
|
+
# @option options [required,String] :policy This can be a String
|
|
475
|
+
# or any object that responds to +#to_json+.
|
|
476
|
+
# @return [Core::Response]
|
|
477
|
+
bucket_method(:set_bucket_policy, :put, 'policy') do
|
|
478
|
+
|
|
479
|
+
configure_request do |req, options|
|
|
480
|
+
require_policy!(options[:policy])
|
|
481
|
+
super(req, options)
|
|
482
|
+
policy = options[:policy]
|
|
483
|
+
policy = policy.to_json unless policy.respond_to?(:to_str)
|
|
484
|
+
req.body = policy
|
|
485
|
+
end
|
|
486
|
+
|
|
487
|
+
end
|
|
488
|
+
|
|
489
|
+
# Gets the access policy for a bucket.
|
|
490
|
+
# @overload get_bucket_policy(options = {})
|
|
491
|
+
# @param [Hash] options
|
|
492
|
+
# @option options [required,String] :bucket_name
|
|
493
|
+
# @return [Core::Response]
|
|
494
|
+
bucket_method(:get_bucket_policy, :get, 'policy') do
|
|
495
|
+
|
|
496
|
+
process_response do |resp|
|
|
497
|
+
resp.data[:policy] = resp.http_response.body
|
|
498
|
+
end
|
|
499
|
+
|
|
500
|
+
end
|
|
501
|
+
|
|
502
|
+
# Deletes the access policy for a bucket.
|
|
503
|
+
# @overload delete_bucket_policy(options = {})
|
|
504
|
+
# @param [Hash] options
|
|
505
|
+
# @option options [required,String] :bucket_name
|
|
506
|
+
# @return [Core::Response]
|
|
507
|
+
bucket_method(:delete_bucket_policy, :delete, 'policy')
|
|
508
|
+
|
|
509
|
+
# @overload set_bucket_versioning(options = {})
|
|
510
|
+
# @param [Hash] options
|
|
511
|
+
# @option options [required,String] :bucket_name
|
|
512
|
+
# @option options [required,String] :state
|
|
513
|
+
# @option options [String] :mfa_delete
|
|
514
|
+
# @option options [String] :mfa
|
|
515
|
+
# @return [Core::Response]
|
|
516
|
+
bucket_method(:set_bucket_versioning, :put, 'versioning', :header_options => { :mfa => "x-amz-mfa" }) do
|
|
517
|
+
|
|
518
|
+
configure_request do |req, options|
|
|
519
|
+
state = options[:state].to_s.downcase.capitalize
|
|
520
|
+
unless state =~ /^(Enabled|Suspended)$/
|
|
521
|
+
raise ArgumentError, "invalid versioning state `#{state}`"
|
|
522
|
+
end
|
|
523
|
+
|
|
524
|
+
# Leave validation of MFA options to S3
|
|
525
|
+
mfa_delete = options[:mfa_delete].to_s.downcase.capitalize if options[:mfa_delete]
|
|
526
|
+
|
|
527
|
+
# Generate XML request for versioning
|
|
528
|
+
req.body = Nokogiri::XML::Builder.new do |xml|
|
|
529
|
+
xml.VersioningConfiguration('xmlns' => XMLNS) do
|
|
530
|
+
xml.Status(state)
|
|
531
|
+
xml.MfaDelete(mfa_delete) if mfa_delete
|
|
532
|
+
end
|
|
533
|
+
end.doc.root.to_xml
|
|
534
|
+
|
|
535
|
+
super(req, options)
|
|
536
|
+
end
|
|
537
|
+
|
|
538
|
+
end
|
|
539
|
+
|
|
540
|
+
# Gets the bucket's location constraint.
|
|
541
|
+
# @overload get_bucket_location(options = {})
|
|
542
|
+
# @param [Hash] options
|
|
543
|
+
# @option options [required,String] :bucket_name
|
|
544
|
+
# @return [Core::Response]
|
|
545
|
+
bucket_method(:get_bucket_location, :get, 'location') do
|
|
546
|
+
|
|
547
|
+
process_response do |response|
|
|
548
|
+
regex = />(.*)<\/LocationConstraint>/
|
|
549
|
+
matches = response.http_response.body.to_s.match(regex)
|
|
550
|
+
response.data[:location_constraint] = matches ? matches[1] : nil
|
|
551
|
+
end
|
|
552
|
+
|
|
553
|
+
end
|
|
554
|
+
|
|
555
|
+
# @overload get_bucket_versioning(options = {})
|
|
556
|
+
# @param [Hash] options
|
|
557
|
+
# @option options [required,String] :bucket_name
|
|
558
|
+
# @return [Core::Response]
|
|
559
|
+
bucket_method(:get_bucket_versioning, :get, 'versioning',
|
|
560
|
+
XML::GetBucketVersioning)
|
|
561
|
+
|
|
562
|
+
# @overload list_object_versions(options = {})
|
|
563
|
+
# @param [Hash] options
|
|
564
|
+
# @option options [required,String] :bucket_name
|
|
565
|
+
# @option options [String] :prefix
|
|
566
|
+
# @option options [String] :delimiter
|
|
567
|
+
# @option options [String] :max_keys
|
|
568
|
+
# @option options [String] :key_marker
|
|
569
|
+
# @option options [String] :version_id_marker
|
|
570
|
+
# @return [Core::Response]
|
|
571
|
+
bucket_method(:list_object_versions, :get, 'versions',
|
|
572
|
+
XML::ListObjectVersions) do
|
|
573
|
+
|
|
574
|
+
configure_request do |req, options|
|
|
575
|
+
super(req, options)
|
|
576
|
+
params = %w(delimiter key_marker max_keys prefix version_id_marker)
|
|
577
|
+
params.each do |param|
|
|
578
|
+
if options[param.to_sym]
|
|
579
|
+
req.add_param(param.gsub(/_/, '-'), options[param.to_sym])
|
|
580
|
+
end
|
|
581
|
+
end
|
|
582
|
+
end
|
|
583
|
+
|
|
584
|
+
end
|
|
585
|
+
|
|
586
|
+
# Sets the access control list for a bucket. You must specify an ACL
|
|
587
|
+
# via one of the following methods:
|
|
588
|
+
#
|
|
589
|
+
# * as a canned ACL (via +:acl+)
|
|
590
|
+
# * as a list of grants (via the +:grant_*+ options)
|
|
591
|
+
# * as an access control policy document (via +:access_control_policy+)
|
|
592
|
+
#
|
|
593
|
+
# @example Using a canned acl
|
|
594
|
+
# s3_client.put_bucket_acl(
|
|
595
|
+
# :bucket_name => 'bucket-name',
|
|
596
|
+
# :acl => 'public-read')
|
|
597
|
+
#
|
|
598
|
+
# @example Using grants
|
|
599
|
+
# s3_client.put_bucket_acl(
|
|
600
|
+
# :bucket_name => 'bucket-name',
|
|
601
|
+
# :grant_read => 'uri="http://acs.amazonaws.com/groups/global/AllUsers"',
|
|
602
|
+
# :grant_full_control => 'emailAddress="xyz@amazon.com", id="8a9...fa7"')
|
|
603
|
+
#
|
|
604
|
+
# @example Using an access control policy document
|
|
605
|
+
# policy_xml = <<-XML
|
|
606
|
+
# <AccessControlPolicy xmlns="http://s3.amazonaws.com/doc/2006-03-01/">
|
|
607
|
+
# <Owner>
|
|
608
|
+
# <ID>852b113e7a2f25102679df27bb0ae12b3f85be6BucketOwnerCanonicalUserID</ID>
|
|
609
|
+
# <DisplayName>OwnerDisplayName</DisplayName>
|
|
610
|
+
# </Owner>
|
|
611
|
+
# <AccessControlList>
|
|
612
|
+
# <Grant>
|
|
613
|
+
# <Grantee xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:type="CanonicalUser">
|
|
614
|
+
# <ID>BucketOwnerCanonicalUserID</ID>
|
|
615
|
+
# <DisplayName>OwnerDisplayName</DisplayName>
|
|
616
|
+
# </Grantee>
|
|
617
|
+
# <Permission>FULL_CONTROL</Permission>
|
|
618
|
+
# </Grant>
|
|
619
|
+
# <Grant>
|
|
620
|
+
# <Grantee xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:type="Group">
|
|
621
|
+
# <URI xmlns="">http://acs.amazonaws.com/groups/global/AllUsers</URI>
|
|
622
|
+
# </Grantee>
|
|
623
|
+
# <Permission xmlns="">READ</Permission>
|
|
624
|
+
# </Grant>
|
|
625
|
+
# </AccessControlList>
|
|
626
|
+
# </AccessControlPolicy>
|
|
627
|
+
#
|
|
628
|
+
# XML
|
|
629
|
+
# s3_client.put_bucket_acl(
|
|
630
|
+
# :bucket_name => 'bucket-name',
|
|
631
|
+
# :access_control_policy => policy_xml)
|
|
632
|
+
#
|
|
633
|
+
# @overload put_bucket_acl(options = {})
|
|
634
|
+
# @param [Hash] options
|
|
635
|
+
# @option options [required,String] :bucket_name
|
|
636
|
+
# @option options [String] :access_control_policy An access control
|
|
637
|
+
# policy description as a string of XML. See the S3 API
|
|
638
|
+
# documentation for a description.
|
|
639
|
+
# @option options [String] :acl A canned ACL (e.g. 'private',
|
|
640
|
+
# 'public-read', etc). See the S3 API documentation for
|
|
641
|
+
# a complete list of valid values.
|
|
642
|
+
# @option options [String] :grant_read
|
|
643
|
+
# @option options [String] :grant_write
|
|
644
|
+
# @option options [String] :grant_read_acp
|
|
645
|
+
# @option options [String] :grant_write_acp
|
|
646
|
+
# @option options [String] :grant_full_control
|
|
647
|
+
# @return [Core::Response]
|
|
648
|
+
bucket_method(:put_bucket_acl, :put, 'acl', :header_options => {
|
|
649
|
+
:acl => 'x-amz-acl',
|
|
650
|
+
:grant_read => 'x-amz-grant-read',
|
|
651
|
+
:grant_write => 'x-amz-grant-write',
|
|
652
|
+
:grant_read_acp => 'x-amz-grant-read-acp',
|
|
653
|
+
:grant_write_acp => 'x-amz-grant-write-acp',
|
|
654
|
+
:grant_full_control => 'x-amz-grant-full-control',
|
|
655
|
+
}) do
|
|
656
|
+
|
|
657
|
+
configure_request do |req, options|
|
|
658
|
+
move_access_control_policy(options)
|
|
659
|
+
require_acl!(options)
|
|
660
|
+
super(req, options)
|
|
661
|
+
req.body = options[:access_control_policy] if
|
|
662
|
+
options[:access_control_policy]
|
|
663
|
+
end
|
|
664
|
+
|
|
665
|
+
end
|
|
666
|
+
alias_method :set_bucket_acl, :put_bucket_acl
|
|
667
|
+
|
|
668
|
+
# Gets the access control list for a bucket.
|
|
669
|
+
# @overload get_bucket_acl(options = {})
|
|
670
|
+
# @param [Hash] options
|
|
671
|
+
# @option options [required,String] :bucket_name
|
|
672
|
+
# @return [Core::Response]
|
|
673
|
+
bucket_method(:get_bucket_acl, :get, 'acl', XML::GetBucketAcl)
|
|
674
|
+
|
|
675
|
+
# Sets the access control list for an object. You must specify an ACL
|
|
676
|
+
# via one of the following methods:
|
|
677
|
+
#
|
|
678
|
+
# * as a canned ACL (via +:acl+)
|
|
679
|
+
# * as a list of grants (via the +:grant_*+ options)
|
|
680
|
+
# * as an access control policy document (via +:access_control_policy+)
|
|
681
|
+
#
|
|
682
|
+
# @example Using a canned acl
|
|
683
|
+
# s3_client.put_object_acl(
|
|
684
|
+
# :bucket_name => 'bucket-name',
|
|
685
|
+
# :key => 'object-key',
|
|
686
|
+
# :acl => 'public-read')
|
|
687
|
+
#
|
|
688
|
+
# @example Using grants
|
|
689
|
+
# s3_client.put_bucket_acl(
|
|
690
|
+
# :bucket_name => 'bucket-name',
|
|
691
|
+
# :key => 'object-key',
|
|
692
|
+
# :grant_read => 'uri="http://acs.amazonaws.com/groups/global/AllUsers"',
|
|
693
|
+
# :grant_full_control => 'emailAddress="xyz@amazon.com", id="8a9...fa7"')
|
|
694
|
+
#
|
|
695
|
+
# @example Using an access control policy document
|
|
696
|
+
# policy_xml = <<-XML
|
|
697
|
+
# <AccessControlPolicy xmlns="http://s3.amazonaws.com/doc/2006-03-01/">
|
|
698
|
+
# <Owner>
|
|
699
|
+
# <ID>852b113e7a2f25102679df27bb0ae12b3f85be6BucketOwnerCanonicalUserID</ID>
|
|
700
|
+
# <DisplayName>OwnerDisplayName</DisplayName>
|
|
701
|
+
# </Owner>
|
|
702
|
+
# <AccessControlList>
|
|
703
|
+
# <Grant>
|
|
704
|
+
# <Grantee xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:type="CanonicalUser">
|
|
705
|
+
# <ID>BucketOwnerCanonicalUserID</ID>
|
|
706
|
+
# <DisplayName>OwnerDisplayName</DisplayName>
|
|
707
|
+
# </Grantee>
|
|
708
|
+
# <Permission>FULL_CONTROL</Permission>
|
|
709
|
+
# </Grant>
|
|
710
|
+
# <Grant>
|
|
711
|
+
# <Grantee xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:type="Group">
|
|
712
|
+
# <URI xmlns="">http://acs.amazonaws.com/groups/global/AllUsers</URI>
|
|
713
|
+
# </Grantee>
|
|
714
|
+
# <Permission xmlns="">READ</Permission>
|
|
715
|
+
# </Grant>
|
|
716
|
+
# </AccessControlList>
|
|
717
|
+
# </AccessControlPolicy>
|
|
718
|
+
#
|
|
719
|
+
# XML
|
|
720
|
+
# s3_client.put_bucket_acl(
|
|
721
|
+
# :bucket_name => 'bucket-name',
|
|
722
|
+
# :key => 'object-key',
|
|
723
|
+
# :access_control_policy => policy_xml)
|
|
724
|
+
#
|
|
725
|
+
# @overload put_object_acl(options = {})
|
|
726
|
+
# @param [Hash] options
|
|
727
|
+
# @option options [required,String] :bucket_name
|
|
728
|
+
# @option options [required,String] :key
|
|
729
|
+
# @option options [String] :access_control_policy An access control
|
|
730
|
+
# policy description as a string of XML. See the S3 API
|
|
731
|
+
# documentation for a description.
|
|
732
|
+
# @option options [String] :acl A canned ACL (e.g. 'private',
|
|
733
|
+
# 'public-read', etc). See the S3 API documentation for
|
|
734
|
+
# a complete list of valid values.
|
|
735
|
+
# @option options [String] :grant_read
|
|
736
|
+
# @option options [String] :grant_write
|
|
737
|
+
# @option options [String] :grant_read_acp
|
|
738
|
+
# @option options [String] :grant_write_acp
|
|
739
|
+
# @option options [String] :grant_full_control
|
|
740
|
+
# @return [Core::Response]
|
|
741
|
+
object_method(:put_object_acl, :put, 'acl', :header_options => {
|
|
742
|
+
:acl => 'x-amz-acl',
|
|
743
|
+
:grant_read => 'x-amz-grant-read',
|
|
744
|
+
:grant_write => 'x-amz-grant-write',
|
|
745
|
+
:grant_read_acp => 'x-amz-grant-read-acp',
|
|
746
|
+
:grant_write_acp => 'x-amz-grant-write-acp',
|
|
747
|
+
:grant_full_control => 'x-amz-grant-full-control',
|
|
748
|
+
}) do
|
|
749
|
+
|
|
750
|
+
configure_request do |req, options|
|
|
751
|
+
move_access_control_policy(options)
|
|
752
|
+
require_acl!(options)
|
|
753
|
+
super(req, options)
|
|
754
|
+
req.body = options[:access_control_policy] if
|
|
755
|
+
options[:access_control_policy]
|
|
756
|
+
end
|
|
757
|
+
|
|
758
|
+
end
|
|
759
|
+
alias_method :set_object_acl, :put_object_acl
|
|
760
|
+
|
|
761
|
+
# Gets the access control list for an object.
|
|
762
|
+
# @overload get_object_acl(options = {})
|
|
763
|
+
# @param [Hash] options
|
|
764
|
+
# @option options [required,String] :bucket_name
|
|
765
|
+
# @option options [required,String] :key
|
|
766
|
+
# @return [Core::Response]
|
|
767
|
+
object_method(:get_object_acl, :get, 'acl', XML::GetBucketAcl)
|
|
768
|
+
|
|
769
|
+
# Puts data into an object, replacing the current contents.
|
|
770
|
+
#
|
|
771
|
+
# s3_client.put_object({
|
|
772
|
+
# :bucket_name => 'bucket-name',
|
|
773
|
+
# :key => 'readme.txt',
|
|
774
|
+
# :data => 'This is the readme for ...',
|
|
775
|
+
# })
|
|
776
|
+
#
|
|
777
|
+
# == Block Form
|
|
778
|
+
#
|
|
779
|
+
# In block form, this method yields a stream to the block that
|
|
780
|
+
# accepts data chunks. For example:
|
|
781
|
+
#
|
|
782
|
+
# s3_client.put_object(
|
|
783
|
+
# :bucket_name => 'mybucket',
|
|
784
|
+
# :key => 'some/key'
|
|
785
|
+
# :content_length => File.size('myfile')
|
|
786
|
+
# ) do |buffer|
|
|
787
|
+
#
|
|
788
|
+
# File.open('myfile') do |io|
|
|
789
|
+
# buffer.write(io.read(length)) until io.eof?
|
|
790
|
+
# end
|
|
791
|
+
#
|
|
792
|
+
# end
|
|
793
|
+
#
|
|
794
|
+
# This form is useful if you need finer control over how
|
|
795
|
+
# potentially large amounts of data are read from another
|
|
796
|
+
# source before being sent to S3; for example, if you are
|
|
797
|
+
# using a non-blocking IO model and reading from a large file
|
|
798
|
+
# on disk or from another network stream. Some HTTP handlers
|
|
799
|
+
# do not support streaming request bodies, so if you plan to
|
|
800
|
+
# upload large objects using this interface you should make
|
|
801
|
+
# sure the HTTP handler you configure for the client meets
|
|
802
|
+
# your needs.
|
|
803
|
+
#
|
|
804
|
+
# @overload put_object(options = {})
|
|
805
|
+
# @param [Hash] options
|
|
806
|
+
# @option options [required,String] :bucket_name
|
|
807
|
+
# @option options [required,String] :key
|
|
808
|
+
# @option options [required,String,Pathname,File,IO] :data
|
|
809
|
+
# The data to upload. This can be provided as a string,
|
|
810
|
+
# a Pathname object, or any object that responds to
|
|
811
|
+
# +#read+ and +#eof?+ (e.g. IO, File, Tempfile, StringIO, etc).
|
|
812
|
+
# @option options [Integer] :content_length
|
|
813
|
+
# Required if you are using block form to write data or if it is
|
|
814
|
+
# not possible to determine the size of +:data+. A best effort
|
|
815
|
+
# is made to determine the content length of strings, files,
|
|
816
|
+
# tempfiles, io objects, and any object that responds
|
|
817
|
+
# to +#length+ or +#size+.
|
|
818
|
+
# @option options [String] :website_redirect_location If the bucket is
|
|
819
|
+
# configured as a website, redirects requests for this object to
|
|
820
|
+
# another object in the same bucket or to an external URL.
|
|
821
|
+
# @option options [Hash] :metadata
|
|
822
|
+
# A hash of metadata to be included with the
|
|
823
|
+
# object. These will be sent to S3 as headers prefixed with
|
|
824
|
+
# +x-amz-meta+.
|
|
825
|
+
# @option options [Symbol] :acl (:private) A canned access
|
|
826
|
+
# control policy. Accepted values include:
|
|
827
|
+
# * +:private+
|
|
828
|
+
# * +:public_read+
|
|
829
|
+
# * ...
|
|
830
|
+
# @option options [String] :storage_class+ ('STANDARD')
|
|
831
|
+
# Controls whether Reduced Redundancy Storage is enabled for
|
|
832
|
+
# the object. Valid values are 'STANDARD' and
|
|
833
|
+
# 'REDUCED_REDUNDANCY'.
|
|
834
|
+
# @option options [Symbol,String] :server_side_encryption (nil) The
|
|
835
|
+
# algorithm used to encrypt the object on the server side
|
|
836
|
+
# (e.g. :aes256).
|
|
837
|
+
# object on the server side, e.g. +:aes256+)
|
|
838
|
+
# @option options [String] :cache_control
|
|
839
|
+
# Can be used to specify caching behavior.
|
|
840
|
+
# @option options [String] :content_disposition
|
|
841
|
+
# Specifies presentational information.
|
|
842
|
+
# @option options [String] :content_encoding
|
|
843
|
+
# Specifies the content encoding.
|
|
844
|
+
# @option options [String] :content_md5
|
|
845
|
+
# The base64 encoded content md5 of the +:data+.
|
|
846
|
+
# @option options [String] :content_type
|
|
847
|
+
# Specifies the content type.
|
|
848
|
+
# @option options [String] :expires The date and time at which the
|
|
849
|
+
# object is no longer cacheable.
|
|
850
|
+
# @option options [String] :acl A canned ACL (e.g. 'private',
|
|
851
|
+
# 'public-read', etc). See the S3 API documentation for
|
|
852
|
+
# a complete list of valid values.
|
|
853
|
+
# @option options [String] :grant_read
|
|
854
|
+
# @option options [String] :grant_write
|
|
855
|
+
# @option options [String] :grant_read_acp
|
|
856
|
+
# @option options [String] :grant_write_acp
|
|
857
|
+
# @option options [String] :grant_full_control
|
|
858
|
+
# @return [Core::Response]
|
|
859
|
+
#
|
|
860
|
+
object_method(:put_object, :put, :header_options => {
|
|
861
|
+
:website_redirect_location => 'x-amz-website-redirect-location',
|
|
862
|
+
:acl => 'x-amz-acl',
|
|
863
|
+
:grant_read => 'x-amz-grant-read',
|
|
864
|
+
:grant_write => 'x-amz-grant-write',
|
|
865
|
+
:grant_read_acp => 'x-amz-grant-read-acp',
|
|
866
|
+
:grant_write_acp => 'x-amz-grant-write-acp',
|
|
867
|
+
:grant_full_control => 'x-amz-grant-full-control',
|
|
868
|
+
:content_md5 => 'Content-MD5',
|
|
869
|
+
:cache_control => 'Cache-Control',
|
|
870
|
+
:content_disposition => 'Content-Disposition',
|
|
871
|
+
:content_encoding => 'Content-Encoding',
|
|
872
|
+
:content_type => 'Content-Type',
|
|
873
|
+
:expires => 'Expires',
|
|
874
|
+
}) do
|
|
875
|
+
|
|
876
|
+
configure_request do |request, options|
|
|
877
|
+
|
|
878
|
+
options = compute_write_options(options)
|
|
879
|
+
set_body_stream_and_content_length(request, options)
|
|
880
|
+
|
|
881
|
+
request.metadata = options[:metadata]
|
|
882
|
+
request.storage_class = options[:storage_class]
|
|
883
|
+
request.server_side_encryption = options[:server_side_encryption]
|
|
884
|
+
|
|
885
|
+
super(request, options)
|
|
886
|
+
|
|
887
|
+
end
|
|
888
|
+
|
|
889
|
+
process_response do |resp|
|
|
890
|
+
extract_object_headers(resp)
|
|
891
|
+
end
|
|
892
|
+
|
|
893
|
+
simulate_response do |response|
|
|
894
|
+
response.data[:etag] = 'abc123'
|
|
895
|
+
response.data[:version_id] = nil
|
|
896
|
+
end
|
|
897
|
+
|
|
898
|
+
end
|
|
899
|
+
|
|
900
|
+
# Gets the data for a key.
|
|
901
|
+
# @overload get_object(options = {})
|
|
902
|
+
# @param [Hash] options
|
|
903
|
+
# @option options [required,String] :bucket_name
|
|
904
|
+
# @option options [required,String] :key
|
|
905
|
+
# @option options [Time] :if_modified_since If specified, the
|
|
906
|
+
# response will contain an additional +:modified+ value that
|
|
907
|
+
# returns true if the object was modified after the given
|
|
908
|
+
# time. If +:modified+ is false, then the response
|
|
909
|
+
# +:data+ value will be +nil+.
|
|
910
|
+
# @option options [Time] :if_unmodified_since If specified, the
|
|
911
|
+
# response will contain an additional +:unmodified+ value
|
|
912
|
+
# that is true if the object was not modified after the
|
|
913
|
+
# given time. If +:unmodified+ returns false, the +:data+
|
|
914
|
+
# value will be +nil+.
|
|
915
|
+
# @option options [String] :if_match If specified, the response
|
|
916
|
+
# will contain an additional +:matches+ value that is true
|
|
917
|
+
# if the object ETag matches the value for this option. If
|
|
918
|
+
# +:matches+ is false, the +:data+ value of the
|
|
919
|
+
# response will be +nil+.
|
|
920
|
+
# @option options [String] :if_none_match If specified, the
|
|
921
|
+
# response will contain an additional +:matches+ value that
|
|
922
|
+
# is true if and only if the object ETag matches the value for
|
|
923
|
+
# this option. If +:matches+ is true, the +:data+ value
|
|
924
|
+
# of the response will be +nil+.
|
|
925
|
+
# @option options [Range<Integer>] :range A byte range of data to request.
|
|
926
|
+
# @return [Core::Response]
|
|
927
|
+
#
|
|
928
|
+
object_method(:get_object, :get,
|
|
929
|
+
:header_options => {
|
|
930
|
+
:if_modified_since => "If-Modified-Since",
|
|
931
|
+
:if_unmodified_since => "If-Unmodified-Since",
|
|
932
|
+
:if_match => "If-Match",
|
|
933
|
+
:if_none_match => "If-None-Match"
|
|
934
|
+
}) do
|
|
935
|
+
configure_request do |req, options|
|
|
936
|
+
|
|
937
|
+
super(req, options)
|
|
938
|
+
|
|
939
|
+
if options[:version_id]
|
|
940
|
+
req.add_param('versionId', options[:version_id])
|
|
941
|
+
end
|
|
942
|
+
|
|
943
|
+
["If-Modified-Since",
|
|
944
|
+
"If-Unmodified-Since"].each do |date_header|
|
|
945
|
+
case value = req.headers[date_header]
|
|
946
|
+
when DateTime
|
|
947
|
+
req.headers[date_header] = Time.parse(value.to_s).rfc2822
|
|
948
|
+
when Time
|
|
949
|
+
req.headers[date_header] = value.rfc2822
|
|
950
|
+
end
|
|
951
|
+
end
|
|
952
|
+
|
|
953
|
+
if options[:range]
|
|
954
|
+
range = options[:range]
|
|
955
|
+
range = "bytes=#{range.first}-#{range.last}" if range.is_a?(Range)
|
|
956
|
+
req.headers['Range'] = range
|
|
957
|
+
end
|
|
958
|
+
|
|
959
|
+
end
|
|
960
|
+
|
|
961
|
+
process_response do |resp|
|
|
962
|
+
extract_object_headers(resp)
|
|
963
|
+
resp.data[:data] = resp.http_response.body
|
|
964
|
+
end
|
|
965
|
+
|
|
966
|
+
end
|
|
967
|
+
|
|
968
|
+
# @overload head_object(options = {})
|
|
969
|
+
# @param [Hash] options
|
|
970
|
+
# @option options [required,String] :bucket_name
|
|
971
|
+
# @option options [required,String] :key
|
|
972
|
+
# @option options [String] :version_id
|
|
973
|
+
# @return [Core::Response]
|
|
974
|
+
object_method(:head_object, :head) do
|
|
975
|
+
|
|
976
|
+
configure_request do |req, options|
|
|
977
|
+
super(req, options)
|
|
978
|
+
if options[:version_id]
|
|
979
|
+
req.add_param('versionId', options[:version_id])
|
|
980
|
+
end
|
|
981
|
+
end
|
|
982
|
+
|
|
983
|
+
process_response do |resp|
|
|
984
|
+
extract_object_headers(resp)
|
|
985
|
+
end
|
|
986
|
+
|
|
987
|
+
end
|
|
988
|
+
|
|
989
|
+
# @overload delete_object(options = {})
|
|
990
|
+
# @param [Hash] options
|
|
991
|
+
# @option options [required,String] :bucket_name
|
|
992
|
+
# @option options [required,String] :key
|
|
993
|
+
# @option options [String] :version_id
|
|
994
|
+
# @option options [String] :mfa
|
|
995
|
+
# @return [Core::Response]
|
|
996
|
+
object_method(:delete_object, :delete, :header_options => { :mfa => "x-amz-mfa" }) do
|
|
997
|
+
|
|
998
|
+
configure_request do |req, options|
|
|
999
|
+
super(req, options)
|
|
1000
|
+
if options[:version_id]
|
|
1001
|
+
req.add_param('versionId', options[:version_id])
|
|
1002
|
+
end
|
|
1003
|
+
end
|
|
1004
|
+
|
|
1005
|
+
process_response do |resp|
|
|
1006
|
+
resp.data[:version_id] = resp.http_response.header('x-amz-version-id')
|
|
1007
|
+
end
|
|
1008
|
+
|
|
1009
|
+
end
|
|
1010
|
+
|
|
1011
|
+
# @overload restore_object(options = {})
|
|
1012
|
+
# Restores a temporary copy of an archived object.
|
|
1013
|
+
# @param [Hash] options
|
|
1014
|
+
# @option options [required,String] :bucket_name
|
|
1015
|
+
# @option options [required,String] :key
|
|
1016
|
+
# @option options [required,Integer] :days the number of days to keep
|
|
1017
|
+
# the restored object.
|
|
1018
|
+
# @return [Core::Response]
|
|
1019
|
+
# @since 1.7.2
|
|
1020
|
+
object_method(:restore_object, :post, 'restore',
|
|
1021
|
+
:header_options => { :content_md5 => 'Content-MD5' }) do
|
|
1022
|
+
configure_request do |req, options|
|
|
1023
|
+
super(req, options)
|
|
1024
|
+
|
|
1025
|
+
validate!(:days, options[:days]) do
|
|
1026
|
+
"must be greater or equal to 1" if options[:days].to_i <= 0
|
|
1027
|
+
end
|
|
1028
|
+
|
|
1029
|
+
xml = Nokogiri::XML::Builder.new do |xml|
|
|
1030
|
+
xml.RestoreRequest('xmlns' => XMLNS) do
|
|
1031
|
+
xml.Days(options[:days].to_i) if options[:days]
|
|
1032
|
+
end
|
|
1033
|
+
end.doc.root.to_xml
|
|
1034
|
+
|
|
1035
|
+
req.body = xml
|
|
1036
|
+
req.headers['content-type'] = 'application/xml'
|
|
1037
|
+
req.headers['content-md5'] = md5(xml)
|
|
1038
|
+
end
|
|
1039
|
+
end
|
|
1040
|
+
|
|
1041
|
+
|
|
1042
|
+
# @overload list_objects(options = {})
|
|
1043
|
+
# @param [Hash] options
|
|
1044
|
+
# @option options [required,String] :bucket_name
|
|
1045
|
+
# @option options [String] :delimiter
|
|
1046
|
+
# @option options [String] :marker
|
|
1047
|
+
# @option options [String] :max_keys
|
|
1048
|
+
# @option options [String] :prefix
|
|
1049
|
+
# @return [Core::Response]
|
|
1050
|
+
bucket_method(:list_objects, :get, XML::ListObjects) do
|
|
1051
|
+
configure_request do |req, options|
|
|
1052
|
+
super(req, options)
|
|
1053
|
+
params = %w(delimiter marker max_keys prefix)
|
|
1054
|
+
params.each do |param|
|
|
1055
|
+
if options[param.to_sym]
|
|
1056
|
+
req.add_param(param.gsub(/_/, '-'), options[param.to_sym])
|
|
1057
|
+
end
|
|
1058
|
+
end
|
|
1059
|
+
end
|
|
1060
|
+
end
|
|
1061
|
+
|
|
1062
|
+
alias_method :get_bucket, :list_objects
|
|
1063
|
+
|
|
1064
|
+
# @overload initiate_multipart_upload(options = {})
|
|
1065
|
+
# @param [Hash] options
|
|
1066
|
+
# @option options [required,String] :bucket_name
|
|
1067
|
+
# @option options [required,String] :key
|
|
1068
|
+
# @option options [String] :website_redirect_location If the bucket is
|
|
1069
|
+
# configured as a website, redirects requests for this object to
|
|
1070
|
+
# another object in the same bucket or to an external URL.
|
|
1071
|
+
# @option options [Hash] :metadata
|
|
1072
|
+
# @option options [Symbol] :acl
|
|
1073
|
+
# @option options [String] :cache_control
|
|
1074
|
+
# @option options [String] :content_disposition
|
|
1075
|
+
# @option options [String] :content_encoding
|
|
1076
|
+
# @option options [String] :content_type
|
|
1077
|
+
# @option options [String] :storage_class+ ('STANDARD')
|
|
1078
|
+
# Controls whether Reduced Redundancy Storage is enabled for
|
|
1079
|
+
# the object. Valid values are 'STANDARD' and
|
|
1080
|
+
# 'REDUCED_REDUNDANCY'.
|
|
1081
|
+
# @option options [Symbol,String] :server_side_encryption (nil) The
|
|
1082
|
+
# algorithm used to encrypt the object on the server side
|
|
1083
|
+
# (e.g. :aes256).
|
|
1084
|
+
# @option options [String] :expires The date and time at which the
|
|
1085
|
+
# object is no longer cacheable.
|
|
1086
|
+
# @option options [String] :acl A canned ACL (e.g. 'private',
|
|
1087
|
+
# 'public-read', etc). See the S3 API documentation for
|
|
1088
|
+
# a complete list of valid values.
|
|
1089
|
+
# @option options [String] :grant_read
|
|
1090
|
+
# @option options [String] :grant_write
|
|
1091
|
+
# @option options [String] :grant_read_acp
|
|
1092
|
+
# @option options [String] :grant_write_acp
|
|
1093
|
+
# @option options [String] :grant_full_control
|
|
1094
|
+
# @return [Core::Response]
|
|
1095
|
+
object_method(:initiate_multipart_upload, :post, 'uploads',
|
|
1096
|
+
XML::InitiateMultipartUpload,
|
|
1097
|
+
:header_options => {
|
|
1098
|
+
:website_redirect_location => 'x-amz-website-redirect-location',
|
|
1099
|
+
:acl => 'x-amz-acl',
|
|
1100
|
+
:grant_read => 'x-amz-grant-read',
|
|
1101
|
+
:grant_write => 'x-amz-grant-write',
|
|
1102
|
+
:grant_read_acp => 'x-amz-grant-read-acp',
|
|
1103
|
+
:grant_write_acp => 'x-amz-grant-write-acp',
|
|
1104
|
+
:grant_full_control => 'x-amz-grant-full-control',
|
|
1105
|
+
:cache_control => 'Cache-Control',
|
|
1106
|
+
:content_disposition => 'Content-Disposition',
|
|
1107
|
+
:content_encoding => 'Content-Encoding',
|
|
1108
|
+
:content_type => 'Content-Type',
|
|
1109
|
+
:expires => 'Expires',
|
|
1110
|
+
}) do
|
|
1111
|
+
|
|
1112
|
+
configure_request do |req, options|
|
|
1113
|
+
req.metadata = options[:metadata]
|
|
1114
|
+
req.storage_class = options[:storage_class]
|
|
1115
|
+
req.server_side_encryption = options[:server_side_encryption]
|
|
1116
|
+
super(req, options)
|
|
1117
|
+
end
|
|
1118
|
+
|
|
1119
|
+
process_response do |resp|
|
|
1120
|
+
extract_object_headers(resp)
|
|
1121
|
+
end
|
|
1122
|
+
|
|
1123
|
+
end
|
|
1124
|
+
|
|
1125
|
+
# @overload list_multipart_uploads(options = {})
|
|
1126
|
+
# @param [Hash] options
|
|
1127
|
+
# @option options [required,String] :bucket_name
|
|
1128
|
+
# @option options [String] :delimiter
|
|
1129
|
+
# @option options [String] :key_marker
|
|
1130
|
+
# @option options [String] :max_keys
|
|
1131
|
+
# @option options [String] :upload_id_marker
|
|
1132
|
+
# @option options [String] :max_uploads
|
|
1133
|
+
# @option options [String] :prefix
|
|
1134
|
+
# @return [Core::Response]
|
|
1135
|
+
bucket_method(:list_multipart_uploads,
|
|
1136
|
+
:get, 'uploads',
|
|
1137
|
+
XML::ListMultipartUploads) do
|
|
1138
|
+
configure_request do |req, options|
|
|
1139
|
+
super(req, options)
|
|
1140
|
+
params = %w(delimiter key_marker max_keys) +
|
|
1141
|
+
%w(upload_id_marker max_uploads prefix)
|
|
1142
|
+
params.each do |param|
|
|
1143
|
+
if options[param.to_sym]
|
|
1144
|
+
req.add_param(param.gsub(/_/, '-'), options[param.to_sym])
|
|
1145
|
+
end
|
|
1146
|
+
end
|
|
1147
|
+
end
|
|
1148
|
+
end
|
|
1149
|
+
|
|
1150
|
+
# @overload delete_objects(options = {})
|
|
1151
|
+
# @param [Hash] options
|
|
1152
|
+
# @option options [required,String] :bucket_name
|
|
1153
|
+
# @option options [required,Array<String>] :keys
|
|
1154
|
+
# @option options [Boolean] :quiet (true)
|
|
1155
|
+
# @option options [String] :mfa
|
|
1156
|
+
# @return [Core::Response]
|
|
1157
|
+
bucket_method(:delete_objects, :post, 'delete', XML::DeleteObjects, :header_options => { :mfa => "x-amz-mfa" }) do
|
|
1158
|
+
configure_request do |req, options|
|
|
1159
|
+
|
|
1160
|
+
super(req, options)
|
|
1161
|
+
|
|
1162
|
+
quiet = options.key?(:quiet) ? options[:quiet] : true
|
|
1163
|
+
|
|
1164
|
+
# previously named this option :objects, since renamed
|
|
1165
|
+
keys = options[:objects] || options[:keys]
|
|
1166
|
+
|
|
1167
|
+
objects = keys.inject('') do |xml,o|
|
|
1168
|
+
xml << "<Object><Key>#{REXML::Text.normalize(o[:key])}</Key>"
|
|
1169
|
+
xml << "<VersionId>#{o[:version_id]}</VersionId>" if o[:version_id]
|
|
1170
|
+
xml << "</Object>"
|
|
1171
|
+
end
|
|
1172
|
+
|
|
1173
|
+
xml = '<?xml version="1.0" encoding="UTF-8"?>'
|
|
1174
|
+
xml << "<Delete><Quiet>#{quiet}</Quiet>#{objects}</Delete>"
|
|
1175
|
+
|
|
1176
|
+
req.body = xml
|
|
1177
|
+
req.headers['content-md5'] = md5(xml)
|
|
1178
|
+
|
|
1179
|
+
end
|
|
1180
|
+
end
|
|
1181
|
+
|
|
1182
|
+
# @overload upload_part(options = {})
|
|
1183
|
+
# @param [Hash] options
|
|
1184
|
+
# @option options [required,String] :bucket_name
|
|
1185
|
+
# @option options [required,String] :key
|
|
1186
|
+
# @option options [required,String] :upload_id
|
|
1187
|
+
# @option options [required,Integer] :part_number
|
|
1188
|
+
# @option options [required,String,Pathname,File,IO] :data
|
|
1189
|
+
# The data to upload. This can be provided as a string,
|
|
1190
|
+
# a Pathname object, or any object that responds to
|
|
1191
|
+
# +#read+ and +#eof?+ (e.g. IO, File, Tempfile, StringIO, etc).
|
|
1192
|
+
# @return [Core::Response]
|
|
1193
|
+
object_method(:upload_part, :put,
|
|
1194
|
+
:header_options => {
|
|
1195
|
+
:content_md5 => 'Content-MD5'
|
|
1196
|
+
}) do
|
|
1197
|
+
configure_request do |request, options|
|
|
1198
|
+
|
|
1199
|
+
options = compute_write_options(options)
|
|
1200
|
+
set_body_stream_and_content_length(request, options)
|
|
1201
|
+
|
|
1202
|
+
require_upload_id!(options[:upload_id])
|
|
1203
|
+
request.add_param('uploadId', options[:upload_id])
|
|
1204
|
+
|
|
1205
|
+
require_part_number!(options[:part_number])
|
|
1206
|
+
request.add_param('partNumber', options[:part_number])
|
|
1207
|
+
|
|
1208
|
+
super(request, options)
|
|
1209
|
+
|
|
1210
|
+
end
|
|
1211
|
+
|
|
1212
|
+
process_response do |resp|
|
|
1213
|
+
extract_object_headers(resp)
|
|
1214
|
+
end
|
|
1215
|
+
|
|
1216
|
+
simulate_response do |response|
|
|
1217
|
+
response.data[:etag] = 'abc123'
|
|
1218
|
+
end
|
|
1219
|
+
end
|
|
1220
|
+
|
|
1221
|
+
# @overload complete_multipart_upload(options = {})
|
|
1222
|
+
# @param [Hash] options
|
|
1223
|
+
# @option options [required,String] :bucket_name
|
|
1224
|
+
# @option options [required,String] :key
|
|
1225
|
+
# @option options [required,String] :upload_id
|
|
1226
|
+
# @option options [required,Array<String>] :parts
|
|
1227
|
+
# @return [Core::Response]
|
|
1228
|
+
object_method(:complete_multipart_upload, :post,
|
|
1229
|
+
XML::CompleteMultipartUpload) do
|
|
1230
|
+
configure_request do |req, options|
|
|
1231
|
+
require_upload_id!(options[:upload_id])
|
|
1232
|
+
validate_parts!(options[:parts])
|
|
1233
|
+
super(req, options)
|
|
1234
|
+
req.add_param('uploadId', options[:upload_id])
|
|
1235
|
+
parts_xml = options[:parts].map do |part|
|
|
1236
|
+
"<Part>"+
|
|
1237
|
+
"<PartNumber>#{part[:part_number].to_i}</PartNumber>"+
|
|
1238
|
+
"<ETag>#{REXML::Text.normalize(part[:etag].to_s)}</ETag>"+
|
|
1239
|
+
"</Part>"
|
|
1240
|
+
end.join
|
|
1241
|
+
req.body =
|
|
1242
|
+
"<CompleteMultipartUpload>#{parts_xml}</CompleteMultipartUpload>"
|
|
1243
|
+
end
|
|
1244
|
+
|
|
1245
|
+
process_response do |resp|
|
|
1246
|
+
extract_object_headers(resp)
|
|
1247
|
+
end
|
|
1248
|
+
|
|
1249
|
+
simulate_response do |response|
|
|
1250
|
+
response.data = {}
|
|
1251
|
+
end
|
|
1252
|
+
|
|
1253
|
+
end
|
|
1254
|
+
|
|
1255
|
+
# @overload abort_multipart_upload(options = {})
|
|
1256
|
+
# @param [Hash] options
|
|
1257
|
+
# @option options [required,String] :bucket_name
|
|
1258
|
+
# @option options [required,String] :key
|
|
1259
|
+
# @option options [required,String] :upload_id
|
|
1260
|
+
# @return [Core::Response]
|
|
1261
|
+
object_method(:abort_multipart_upload, :delete) do
|
|
1262
|
+
configure_request do |req, options|
|
|
1263
|
+
require_upload_id!(options[:upload_id])
|
|
1264
|
+
super(req, options)
|
|
1265
|
+
req.add_param('uploadId', options[:upload_id])
|
|
1266
|
+
end
|
|
1267
|
+
end
|
|
1268
|
+
|
|
1269
|
+
# @overload list_parts(options = {})
|
|
1270
|
+
# @param [Hash] options
|
|
1271
|
+
# @option options [required,String] :bucket_name
|
|
1272
|
+
# @option options [required,String] :key
|
|
1273
|
+
# @option options [required,String] :upload_id
|
|
1274
|
+
# @option options [Integer] :max_parts
|
|
1275
|
+
# @option options [Integer] :part_number_marker
|
|
1276
|
+
# @return [Core::Response]
|
|
1277
|
+
object_method(:list_parts, :get, XML::ListParts) do
|
|
1278
|
+
|
|
1279
|
+
configure_request do |req, options|
|
|
1280
|
+
require_upload_id!(options[:upload_id])
|
|
1281
|
+
super(req, options)
|
|
1282
|
+
req.add_param('uploadId', options[:upload_id])
|
|
1283
|
+
req.add_param('max-parts', options[:max_parts])
|
|
1284
|
+
req.add_param('part-number-marker', options[:part_number_marker])
|
|
1285
|
+
end
|
|
1286
|
+
|
|
1287
|
+
end
|
|
1288
|
+
|
|
1289
|
+
# Copies an object from one key to another.
|
|
1290
|
+
# @overload copy_object(options = {})
|
|
1291
|
+
# @param [Hash] options
|
|
1292
|
+
# @option options [required, String] :bucket_name Name of the bucket
|
|
1293
|
+
# to copy a object into.
|
|
1294
|
+
# @option options [required, String] :key Where (object key) in the
|
|
1295
|
+
# bucket the object should be copied to.
|
|
1296
|
+
# @option options [String] :website_redirect_location If the bucket is
|
|
1297
|
+
# configured as a website, redirects requests for this object to
|
|
1298
|
+
# another object in the same bucket or to an external URL.
|
|
1299
|
+
# @option options [required, String] :copy_source The source
|
|
1300
|
+
# bucket name and key, joined by a forward slash ('/').
|
|
1301
|
+
# This string must be URL-encoded. Additionally, you must
|
|
1302
|
+
# have read access to the source object.
|
|
1303
|
+
# @option options [String] :acl A canned ACL (e.g. 'private',
|
|
1304
|
+
# 'public-read', etc). See the S3 API documentation for
|
|
1305
|
+
# a complete list of valid values.
|
|
1306
|
+
# @option options [Symbol,String] :server_side_encryption (nil) The
|
|
1307
|
+
# algorithm used to encrypt the object on the server side
|
|
1308
|
+
# (e.g. :aes256).
|
|
1309
|
+
# @option options [String] :storage_class+ ('STANDARD')
|
|
1310
|
+
# Controls whether Reduced Redundancy Storage is enabled for
|
|
1311
|
+
# the object. Valid values are 'STANDARD' and
|
|
1312
|
+
# 'REDUCED_REDUNDANCY'.
|
|
1313
|
+
# @option options [String] :expires The date and time at which the
|
|
1314
|
+
# object is no longer cacheable.
|
|
1315
|
+
# @option options [String] :grant_read
|
|
1316
|
+
# @option options [String] :grant_write
|
|
1317
|
+
# @option options [String] :grant_read_acp
|
|
1318
|
+
# @option options [String] :grant_write_acp
|
|
1319
|
+
# @option options [String] :grant_full_control
|
|
1320
|
+
# @return [Core::Response]
|
|
1321
|
+
object_method(:copy_object, :put, :header_options => {
|
|
1322
|
+
:website_redirect_location => 'x-amz-website-redirect-location',
|
|
1323
|
+
:acl => 'x-amz-acl',
|
|
1324
|
+
:grant_read => 'x-amz-grant-read',
|
|
1325
|
+
:grant_write => 'x-amz-grant-write',
|
|
1326
|
+
:grant_read_acp => 'x-amz-grant-read-acp',
|
|
1327
|
+
:grant_write_acp => 'x-amz-grant-write-acp',
|
|
1328
|
+
:grant_full_control => 'x-amz-grant-full-control',
|
|
1329
|
+
:copy_source => 'x-amz-copy-source',
|
|
1330
|
+
:cache_control => 'Cache-Control',
|
|
1331
|
+
:metadata_directive => 'x-amz-metadata-directive',
|
|
1332
|
+
:content_type => 'Content-Type',
|
|
1333
|
+
:content_disposition => 'Content-Disposition',
|
|
1334
|
+
:expires => 'Expires',
|
|
1335
|
+
}) do
|
|
1336
|
+
|
|
1337
|
+
configure_request do |req, options|
|
|
1338
|
+
|
|
1339
|
+
validate!(:copy_source, options[:copy_source]) do
|
|
1340
|
+
"may not be blank" if options[:copy_source].to_s.empty?
|
|
1341
|
+
end
|
|
1342
|
+
|
|
1343
|
+
options = options.merge(:copy_source => escape_path(options[:copy_source]))
|
|
1344
|
+
super(req, options)
|
|
1345
|
+
req.metadata = options[:metadata]
|
|
1346
|
+
req.storage_class = options[:storage_class]
|
|
1347
|
+
req.server_side_encryption = options[:server_side_encryption]
|
|
1348
|
+
|
|
1349
|
+
if options[:version_id]
|
|
1350
|
+
req.headers['x-amz-copy-source'] += "?versionId=#{options[:version_id]}"
|
|
1351
|
+
end
|
|
1352
|
+
end
|
|
1353
|
+
|
|
1354
|
+
process_response do |resp|
|
|
1355
|
+
extract_object_headers(resp)
|
|
1356
|
+
end
|
|
1357
|
+
|
|
1358
|
+
end
|
|
1359
|
+
|
|
1360
|
+
protected
|
|
1361
|
+
|
|
1362
|
+
def extract_error_details response
|
|
1363
|
+
if
|
|
1364
|
+
(response.http_response.status >= 300 ||
|
|
1365
|
+
response.request_type == :complete_multipart_upload) and
|
|
1366
|
+
body = response.http_response.body and
|
|
1367
|
+
error = Core::XML::Parser.parse(body) and
|
|
1368
|
+
error[:code]
|
|
1369
|
+
then
|
|
1370
|
+
[error[:code], error[:message]]
|
|
1371
|
+
end
|
|
1372
|
+
end
|
|
1373
|
+
|
|
1374
|
+
# There are a few of s3 requests that can generate empty bodies and
|
|
1375
|
+
# yet still be errors. These return empty bodies to comply with the
|
|
1376
|
+
# HTTP spec. We have to detect these errors specially.
|
|
1377
|
+
def populate_error resp
|
|
1378
|
+
code = resp.http_response.status
|
|
1379
|
+
if EMPTY_BODY_ERRORS.include?(code) and resp.http_response.body.nil?
|
|
1380
|
+
error_class = EMPTY_BODY_ERRORS[code]
|
|
1381
|
+
resp.error = error_class.new(resp.http_request, resp.http_response)
|
|
1382
|
+
else
|
|
1383
|
+
super
|
|
1384
|
+
end
|
|
1385
|
+
end
|
|
1386
|
+
|
|
1387
|
+
def retryable_error? response
|
|
1388
|
+
super or
|
|
1389
|
+
(response.request_type == :complete_multipart_upload &&
|
|
1390
|
+
extract_error_details(response))
|
|
1391
|
+
# complete multipart upload can return an error inside a
|
|
1392
|
+
# 200 level response -- this forces us to parse the
|
|
1393
|
+
# response for errors every time
|
|
1394
|
+
end
|
|
1395
|
+
|
|
1396
|
+
def new_request
|
|
1397
|
+
req = S3::Request.new
|
|
1398
|
+
req.force_path_style = config.s3_force_path_style?
|
|
1399
|
+
req.service_path = config.s3_service_path
|
|
1400
|
+
req
|
|
1401
|
+
end
|
|
1402
|
+
|
|
1403
|
+
# Previously the access control policy could be specified via :acl
|
|
1404
|
+
# as a string or an object that responds to #to_xml. The prefered
|
|
1405
|
+
# method now is to pass :access_control_policy an xml document.
|
|
1406
|
+
def move_access_control_policy options
|
|
1407
|
+
if acl = options[:acl]
|
|
1408
|
+
if acl.is_a?(String) and is_xml?(acl)
|
|
1409
|
+
options[:access_control_policy] = options.delete(:acl)
|
|
1410
|
+
elsif acl.respond_to?(:to_xml)
|
|
1411
|
+
options[:access_control_policy] = options.delete(:acl).to_xml
|
|
1412
|
+
end
|
|
1413
|
+
end
|
|
1414
|
+
end
|
|
1415
|
+
|
|
1416
|
+
# @param [String] possible_xml
|
|
1417
|
+
# @return [Boolean] Returns +true+ if the given string is a valid xml
|
|
1418
|
+
# document.
|
|
1419
|
+
def is_xml? possible_xml
|
|
1420
|
+
begin
|
|
1421
|
+
REXML::Document.new(possible_xml).has_elements?
|
|
1422
|
+
rescue
|
|
1423
|
+
false
|
|
1424
|
+
end
|
|
1425
|
+
end
|
|
1426
|
+
|
|
1427
|
+
def md5 str
|
|
1428
|
+
Base64.encode64(Digest::MD5.digest(str)).strip
|
|
1429
|
+
end
|
|
1430
|
+
|
|
1431
|
+
def extract_object_headers resp
|
|
1432
|
+
meta = {}
|
|
1433
|
+
resp.http_response.headers.each_pair do |name,value|
|
|
1434
|
+
if name =~ /^x-amz-meta-(.+)$/i
|
|
1435
|
+
meta[$1] = [value].flatten.join
|
|
1436
|
+
end
|
|
1437
|
+
end
|
|
1438
|
+
resp.data[:meta] = meta
|
|
1439
|
+
|
|
1440
|
+
if expiry = resp.http_response.headers['x-amz-expiration']
|
|
1441
|
+
expiry.first =~ /^expiry-date="(.+)", rule-id="(.+)"$/
|
|
1442
|
+
exp_date = DateTime.parse($1)
|
|
1443
|
+
exp_rule_id = $2
|
|
1444
|
+
else
|
|
1445
|
+
exp_date = nil
|
|
1446
|
+
exp_rule_id = nil
|
|
1447
|
+
end
|
|
1448
|
+
resp.data[:expiration_date] = exp_date if exp_date
|
|
1449
|
+
resp.data[:expiration_rule_id] = exp_rule_id if exp_rule_id
|
|
1450
|
+
|
|
1451
|
+
restoring = false
|
|
1452
|
+
restore_date = nil
|
|
1453
|
+
|
|
1454
|
+
if restore = resp.http_response.headers['x-amz-restore']
|
|
1455
|
+
if restore.first =~ /ongoing-request="(.+?)", expiry-date="(.+?)"/
|
|
1456
|
+
restoring = $1 == "true"
|
|
1457
|
+
restore_date = $2 && DateTime.parse($2)
|
|
1458
|
+
elsif restore.first =~ /ongoing-request="(.+?)"/
|
|
1459
|
+
restoring = $1 == "true"
|
|
1460
|
+
end
|
|
1461
|
+
end
|
|
1462
|
+
resp.data[:restore_in_progress] = restoring
|
|
1463
|
+
resp.data[:restore_expiration_date] = restore_date if restore_date
|
|
1464
|
+
|
|
1465
|
+
{
|
|
1466
|
+
'x-amz-version-id' => :version_id,
|
|
1467
|
+
'content-type' => :content_type,
|
|
1468
|
+
'content-encoding' => :content_encoding,
|
|
1469
|
+
'cache-control' => :cache_control,
|
|
1470
|
+
'etag' => :etag,
|
|
1471
|
+
'x-amz-website-redirect-location' => :website_redirect_location,
|
|
1472
|
+
'accept-ranges' => :accept_ranges,
|
|
1473
|
+
}.each_pair do |header,method|
|
|
1474
|
+
if value = resp.http_response.header(header)
|
|
1475
|
+
resp.data[method] = value
|
|
1476
|
+
end
|
|
1477
|
+
end
|
|
1478
|
+
|
|
1479
|
+
if time = resp.http_response.header('Last-Modified')
|
|
1480
|
+
resp.data[:last_modified] = Time.parse(time)
|
|
1481
|
+
end
|
|
1482
|
+
|
|
1483
|
+
if length = resp.http_response.header('content-length')
|
|
1484
|
+
resp.data[:content_length] = length.to_i
|
|
1485
|
+
end
|
|
1486
|
+
|
|
1487
|
+
if sse = resp.http_response.header('x-amz-server-side-encryption')
|
|
1488
|
+
resp.data[:server_side_encryption] = sse.downcase.to_sym
|
|
1489
|
+
end
|
|
1490
|
+
|
|
1491
|
+
end
|
|
1492
|
+
|
|
1493
|
+
module Validators
|
|
1494
|
+
|
|
1495
|
+
# @return [Boolean] Returns true if the given bucket name is valid.
|
|
1496
|
+
def valid_bucket_name?(bucket_name)
|
|
1497
|
+
validate_bucket_name!(bucket_name) rescue false
|
|
1498
|
+
end
|
|
1499
|
+
|
|
1500
|
+
# Returns true if the given +bucket_name+ is DNS compatible.
|
|
1501
|
+
#
|
|
1502
|
+
# DNS compatible bucket names may be accessed like:
|
|
1503
|
+
#
|
|
1504
|
+
# http://dns.compat.bucket.name.s3.amazonaws.com/
|
|
1505
|
+
#
|
|
1506
|
+
# Whereas non-dns compatible bucket names must place the bucket
|
|
1507
|
+
# name in the url path, like:
|
|
1508
|
+
#
|
|
1509
|
+
# http://s3.amazonaws.com/dns_incompat_bucket_name/
|
|
1510
|
+
#
|
|
1511
|
+
# @return [Boolean] Returns true if the given bucket name may be
|
|
1512
|
+
# is dns compatible.
|
|
1513
|
+
# this bucket n
|
|
1514
|
+
#
|
|
1515
|
+
def dns_compatible_bucket_name?(bucket_name)
|
|
1516
|
+
return false if
|
|
1517
|
+
!valid_bucket_name?(bucket_name) or
|
|
1518
|
+
|
|
1519
|
+
# Bucket names should not contain underscores (_)
|
|
1520
|
+
bucket_name["_"] or
|
|
1521
|
+
|
|
1522
|
+
# Bucket names should be between 3 and 63 characters long
|
|
1523
|
+
bucket_name.size > 63 or
|
|
1524
|
+
|
|
1525
|
+
# Bucket names should not end with a dash
|
|
1526
|
+
bucket_name[-1,1] == '-' or
|
|
1527
|
+
|
|
1528
|
+
# Bucket names cannot contain two, adjacent periods
|
|
1529
|
+
bucket_name['..'] or
|
|
1530
|
+
|
|
1531
|
+
# Bucket names cannot contain dashes next to periods
|
|
1532
|
+
# (e.g., "my-.bucket.com" and "my.-bucket" are invalid)
|
|
1533
|
+
(bucket_name['-.'] || bucket_name['.-'])
|
|
1534
|
+
|
|
1535
|
+
true
|
|
1536
|
+
end
|
|
1537
|
+
|
|
1538
|
+
# Returns true if the bucket name must be used in the request
|
|
1539
|
+
# path instead of as a sub-domain when making requests against
|
|
1540
|
+
# S3.
|
|
1541
|
+
#
|
|
1542
|
+
# This can be an issue if the bucket name is DNS compatible but
|
|
1543
|
+
# contains '.' (periods). These cause the SSL certificate to
|
|
1544
|
+
# become invalid when making authenticated requets over SSL to the
|
|
1545
|
+
# bucket name. The solution is to send this as a path argument
|
|
1546
|
+
# instead.
|
|
1547
|
+
#
|
|
1548
|
+
# @return [Boolean] Returns true if the bucket name should be used
|
|
1549
|
+
# as a path segement instead of dns prefix when making requests
|
|
1550
|
+
# against s3.
|
|
1551
|
+
#
|
|
1552
|
+
def path_style_bucket_name? bucket_name
|
|
1553
|
+
if dns_compatible_bucket_name?(bucket_name)
|
|
1554
|
+
bucket_name =~ /\./ ? true : false
|
|
1555
|
+
else
|
|
1556
|
+
true
|
|
1557
|
+
end
|
|
1558
|
+
end
|
|
1559
|
+
|
|
1560
|
+
def validate! name, value, &block
|
|
1561
|
+
if error_msg = yield
|
|
1562
|
+
raise ArgumentError, "#{name} #{error_msg}"
|
|
1563
|
+
end
|
|
1564
|
+
value
|
|
1565
|
+
end
|
|
1566
|
+
|
|
1567
|
+
def validate_key!(key)
|
|
1568
|
+
validate!('key', key) do
|
|
1569
|
+
case
|
|
1570
|
+
when key.nil? || key == ''
|
|
1571
|
+
'may not be blank'
|
|
1572
|
+
end
|
|
1573
|
+
end
|
|
1574
|
+
end
|
|
1575
|
+
|
|
1576
|
+
def require_bucket_name! bucket_name
|
|
1577
|
+
if [nil, ''].include?(bucket_name)
|
|
1578
|
+
raise ArgumentError, "bucket_name may not be blank"
|
|
1579
|
+
end
|
|
1580
|
+
end
|
|
1581
|
+
|
|
1582
|
+
# Returns true if the given bucket name is valid. If the name
|
|
1583
|
+
# is invalid, an ArgumentError is raised.
|
|
1584
|
+
def validate_bucket_name!(bucket_name)
|
|
1585
|
+
validate!('bucket_name', bucket_name) do
|
|
1586
|
+
case
|
|
1587
|
+
when bucket_name.nil? || bucket_name == ''
|
|
1588
|
+
'may not be blank'
|
|
1589
|
+
when bucket_name !~ /^[a-z0-9._\-]+$/
|
|
1590
|
+
'may only contain lowercase letters, numbers, periods (.), ' +
|
|
1591
|
+
'underscores (_), and dashes (-)'
|
|
1592
|
+
when bucket_name !~ /^[a-z0-9]/
|
|
1593
|
+
'must start with a letter or a number'
|
|
1594
|
+
when !(3..255).include?(bucket_name.size)
|
|
1595
|
+
'must be between 3 and 255 characters long'
|
|
1596
|
+
when bucket_name =~ /(\d+\.){3}\d+/
|
|
1597
|
+
'must not be formatted like an IP address (e.g., 192.168.5.4)'
|
|
1598
|
+
when bucket_name =~ /\n/
|
|
1599
|
+
'must not contain a newline character'
|
|
1600
|
+
end
|
|
1601
|
+
end
|
|
1602
|
+
end
|
|
1603
|
+
|
|
1604
|
+
def require_policy!(policy)
|
|
1605
|
+
validate!('policy', policy) do
|
|
1606
|
+
case
|
|
1607
|
+
when policy.nil? || policy == ''
|
|
1608
|
+
'may not be blank'
|
|
1609
|
+
else
|
|
1610
|
+
json_validation_message(policy)
|
|
1611
|
+
end
|
|
1612
|
+
end
|
|
1613
|
+
end
|
|
1614
|
+
|
|
1615
|
+
def require_acl! options
|
|
1616
|
+
acl_options = [
|
|
1617
|
+
:acl,
|
|
1618
|
+
:grant_read,
|
|
1619
|
+
:grant_write,
|
|
1620
|
+
:grant_read_acp,
|
|
1621
|
+
:grant_write_acp,
|
|
1622
|
+
:grant_full_control,
|
|
1623
|
+
:access_control_policy,
|
|
1624
|
+
]
|
|
1625
|
+
unless options.keys.any?{|opt| acl_options.include?(opt) }
|
|
1626
|
+
msg = "missing a required ACL option, must provide an ACL " +
|
|
1627
|
+
"via :acl, :grant_* or :access_control_policy"
|
|
1628
|
+
raise ArgumentError, msg
|
|
1629
|
+
end
|
|
1630
|
+
end
|
|
1631
|
+
|
|
1632
|
+
def set_body_stream_and_content_length request, options
|
|
1633
|
+
|
|
1634
|
+
unless options[:content_length]
|
|
1635
|
+
msg = "S3 requires a content-length header, unable to determine "
|
|
1636
|
+
msg << "the content length of the data provided, please set "
|
|
1637
|
+
msg << ":content_length"
|
|
1638
|
+
raise ArgumentError, msg
|
|
1639
|
+
end
|
|
1640
|
+
|
|
1641
|
+
request.headers['content-length'] = options[:content_length]
|
|
1642
|
+
request.body_stream = options[:data]
|
|
1643
|
+
|
|
1644
|
+
end
|
|
1645
|
+
|
|
1646
|
+
def require_upload_id!(upload_id)
|
|
1647
|
+
validate!("upload_id", upload_id) do
|
|
1648
|
+
"must not be blank" if upload_id.to_s.empty?
|
|
1649
|
+
end
|
|
1650
|
+
end
|
|
1651
|
+
|
|
1652
|
+
def require_part_number! part_number
|
|
1653
|
+
validate!("part_number", part_number) do
|
|
1654
|
+
"must not be blank" if part_number.to_s.empty?
|
|
1655
|
+
end
|
|
1656
|
+
end
|
|
1657
|
+
|
|
1658
|
+
def validate_parts!(parts)
|
|
1659
|
+
validate!("parts", parts) do
|
|
1660
|
+
if !parts.kind_of?(Array)
|
|
1661
|
+
"must not be blank"
|
|
1662
|
+
elsif parts.empty?
|
|
1663
|
+
"must contain at least one entry"
|
|
1664
|
+
elsif !parts.all? { |p| p.kind_of?(Hash) }
|
|
1665
|
+
"must be an array of hashes"
|
|
1666
|
+
elsif !parts.all? { |p| p[:part_number] }
|
|
1667
|
+
"must contain part_number for each part"
|
|
1668
|
+
elsif !parts.all? { |p| p[:etag] }
|
|
1669
|
+
"must contain etag for each part"
|
|
1670
|
+
elsif parts.any? { |p| p[:part_number].to_i < 1 }
|
|
1671
|
+
"must not have part numbers less than 1"
|
|
1672
|
+
end
|
|
1673
|
+
end
|
|
1674
|
+
end
|
|
1675
|
+
|
|
1676
|
+
def json_validation_message(obj)
|
|
1677
|
+
if obj.respond_to?(:to_str)
|
|
1678
|
+
obj = obj.to_str
|
|
1679
|
+
elsif obj.respond_to?(:to_json)
|
|
1680
|
+
obj = obj.to_json
|
|
1681
|
+
end
|
|
1682
|
+
|
|
1683
|
+
error = nil
|
|
1684
|
+
begin
|
|
1685
|
+
JSON.parse(obj)
|
|
1686
|
+
rescue => e
|
|
1687
|
+
error = e
|
|
1688
|
+
end
|
|
1689
|
+
"contains invalid JSON: #{error}" if error
|
|
1690
|
+
end
|
|
1691
|
+
|
|
1692
|
+
end
|
|
1693
|
+
|
|
1694
|
+
include Validators
|
|
1695
|
+
extend Validators
|
|
1696
|
+
|
|
1697
|
+
end
|
|
1698
|
+
|
|
1699
|
+
end
|
|
1700
|
+
end
|