aws_sdk 3.1.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/lib/aws-sdk.rb +14 -0
- data/lib/aws.rb +49 -0
- data/lib/aws/api_config/AutoScaling-2011-01-01.yml +791 -0
- data/lib/aws/api_config/CloudFormation-2010-05-15.yml +303 -0
- data/lib/aws/api_config/DynamoDB-2011-12-05.yml +540 -0
- data/lib/aws/api_config/EC2-2011-12-15.yml +3638 -0
- data/lib/aws/api_config/EC2-2012-04-01.yml +3739 -0
- data/lib/aws/api_config/ELB-2011-08-15.yml +512 -0
- data/lib/aws/api_config/IAM-2010-05-08.yml +1221 -0
- data/lib/aws/api_config/SNS-2010-03-31.yml +248 -0
- data/lib/aws/api_config/SQS-2011-10-01.yml +314 -0
- data/lib/aws/api_config/STS-2011-06-15.yml +54 -0
- data/lib/aws/api_config/SimpleDB-2009-04-15.yml +305 -0
- data/lib/aws/api_config/SimpleEmailService-2010-12-01.yml +231 -0
- data/lib/aws/api_config/SimpleWorkflow-2012-01-25.yml +721 -0
- data/lib/aws/auto_scaling.rb +162 -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 +765 -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 +150 -0
- data/lib/aws/auto_scaling/launch_configuration_collection.rb +144 -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 +23 -0
- data/lib/aws/auto_scaling/scaling_policy.rb +125 -0
- data/lib/aws/auto_scaling/scaling_policy_collection.rb +72 -0
- data/lib/aws/auto_scaling/scaling_policy_options.rb +61 -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 +270 -0
- data/lib/aws/cloud_formation/client.rb +339 -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 +256 -0
- data/lib/aws/cloud_formation/stack_collection.rb +206 -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 +72 -0
- data/lib/aws/cloud_formation/stack_summary.rb +71 -0
- data/lib/aws/cloud_formation/stack_summary_collection.rb +127 -0
- data/lib/aws/core.rb +474 -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 +541 -0
- data/lib/aws/core/client/query_json.rb +110 -0
- data/lib/aws/core/client/query_xml.rb +122 -0
- data/lib/aws/core/collection.rb +234 -0
- data/lib/aws/core/collection/limitable.rb +99 -0
- data/lib/aws/core/collection/simple.rb +90 -0
- data/lib/aws/core/configuration.rb +445 -0
- data/lib/aws/core/data.rb +242 -0
- data/lib/aws/core/default_signer.rb +67 -0
- data/lib/aws/core/http/curb_handler.rb +136 -0
- data/lib/aws/core/http/handler.rb +77 -0
- data/lib/aws/core/http/httparty_handler.rb +114 -0
- data/lib/aws/core/http/net_http_handler.rb +85 -0
- data/lib/aws/core/http/request.rb +250 -0
- data/lib/aws/core/http/response.rb +74 -0
- data/lib/aws/core/indifferent_hash.rb +88 -0
- data/lib/aws/core/inflection.rb +47 -0
- data/lib/aws/core/lazy_error_classes.rb +90 -0
- data/lib/aws/core/log_formatter.rb +454 -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 +700 -0
- data/lib/aws/core/page_result.rb +73 -0
- data/lib/aws/core/policy.rb +916 -0
- data/lib/aws/core/resource.rb +408 -0
- data/lib/aws/core/resource_cache.rb +40 -0
- data/lib/aws/core/response.rb +202 -0
- data/lib/aws/core/response_cache.rb +50 -0
- data/lib/aws/core/service_interface.rb +61 -0
- data/lib/aws/core/session_signer.rb +90 -0
- data/lib/aws/core/signature/version_2.rb +42 -0
- data/lib/aws/core/signature/version_3.rb +73 -0
- data/lib/aws/core/signature/version_3_http.rb +72 -0
- data/lib/aws/core/signature/version_4.rb +138 -0
- data/lib/aws/core/uri_escape.rb +42 -0
- data/lib/aws/core/xml/frame.rb +242 -0
- data/lib/aws/core/xml/frame_stack.rb +85 -0
- data/lib/aws/core/xml/grammar.rb +299 -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/dynamo_db.rb +213 -0
- data/lib/aws/dynamo_db/attribute_collection.rb +460 -0
- data/lib/aws/dynamo_db/batch_get.rb +206 -0
- data/lib/aws/dynamo_db/batch_write.rb +251 -0
- data/lib/aws/dynamo_db/client.rb +888 -0
- data/lib/aws/dynamo_db/config.rb +20 -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 +130 -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 +47 -0
- data/lib/aws/dynamo_db/request.rb +28 -0
- data/lib/aws/dynamo_db/resource.rb +33 -0
- data/lib/aws/dynamo_db/table.rb +489 -0
- data/lib/aws/dynamo_db/table_collection.rb +165 -0
- data/lib/aws/dynamo_db/types.rb +86 -0
- data/lib/aws/ec2.rb +431 -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 +87 -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 +4121 -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 +157 -0
- data/lib/aws/ec2/elastic_ip_collection.rb +97 -0
- data/lib/aws/ec2/errors.rb +32 -0
- data/lib/aws/ec2/filtered_collection.rb +90 -0
- data/lib/aws/ec2/has_permissions.rb +44 -0
- data/lib/aws/ec2/image.rb +254 -0
- data/lib/aws/ec2/image_collection.rb +228 -0
- data/lib/aws/ec2/instance.rb +669 -0
- data/lib/aws/ec2/instance_collection.rb +346 -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 +97 -0
- data/lib/aws/ec2/region_collection.rb +51 -0
- data/lib/aws/ec2/request.rb +22 -0
- data/lib/aws/ec2/reserved_instances.rb +53 -0
- data/lib/aws/ec2/reserved_instances_collection.rb +40 -0
- data/lib/aws/ec2/reserved_instances_offering.rb +58 -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 +113 -0
- data/lib/aws/ec2/route_table_collection.rb +72 -0
- data/lib/aws/ec2/security_group.rb +458 -0
- data/lib/aws/ec2/security_group/egress_ip_permission_collection.rb +63 -0
- data/lib/aws/ec2/security_group/ingress_ip_permission_collection.rb +61 -0
- data/lib/aws/ec2/security_group/ip_permission.rb +128 -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 +131 -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 +170 -0
- data/lib/aws/ec2/volume_collection.rb +97 -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/elb.rb +65 -0
- data/lib/aws/elb/availability_zone_collection.rb +138 -0
- data/lib/aws/elb/backend_server_policy_collection.rb +140 -0
- data/lib/aws/elb/client.rb +539 -0
- data/lib/aws/elb/config.rb +18 -0
- data/lib/aws/elb/errors.rb +26 -0
- data/lib/aws/elb/instance_collection.rb +174 -0
- data/lib/aws/elb/listener.rb +189 -0
- data/lib/aws/elb/listener_collection.rb +119 -0
- data/lib/aws/elb/listener_opts.rb +45 -0
- data/lib/aws/elb/load_balancer.rb +253 -0
- data/lib/aws/elb/load_balancer_collection.rb +113 -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 +23 -0
- data/lib/aws/errors.rb +122 -0
- data/lib/aws/iam.rb +418 -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 +1609 -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 +71 -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/rails.rb +195 -0
- data/lib/aws/record.rb +116 -0
- data/lib/aws/record/abstract_base.rb +645 -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 +182 -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 +694 -0
- data/lib/aws/record/validator.rb +237 -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/s3.rb +135 -0
- data/lib/aws/s3/access_control_list.rb +250 -0
- data/lib/aws/s3/acl_object.rb +264 -0
- data/lib/aws/s3/bucket.rb +393 -0
- data/lib/aws/s3/bucket_collection.rb +143 -0
- data/lib/aws/s3/bucket_lifecycle_configuration.rb +360 -0
- data/lib/aws/s3/bucket_version_collection.rb +77 -0
- data/lib/aws/s3/client.rb +1184 -0
- data/lib/aws/s3/client/xml.rb +177 -0
- data/lib/aws/s3/config.rb +26 -0
- data/lib/aws/s3/data_options.rb +100 -0
- data/lib/aws/s3/errors.rb +81 -0
- data/lib/aws/s3/multipart_upload.rb +317 -0
- data/lib/aws/s3/multipart_upload_collection.rb +68 -0
- data/lib/aws/s3/object_collection.rb +337 -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 +143 -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 +553 -0
- data/lib/aws/s3/request.rb +201 -0
- data/lib/aws/s3/s3_object.rb +1037 -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/simple_db.rb +217 -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 +349 -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 +113 -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 +426 -0
- data/lib/aws/simple_email_service/client.rb +286 -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 +91 -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 +29 -0
- data/lib/aws/simple_workflow.rb +226 -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 +1434 -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 +601 -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 +36 -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 +74 -0
- data/lib/aws/sns/client.rb +371 -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 +80 -0
- data/lib/aws/sns/topic.rb +403 -0
- data/lib/aws/sns/topic_collection.rb +67 -0
- data/lib/aws/sns/topic_subscription_collection.rb +55 -0
- data/lib/aws/sqs.rb +79 -0
- data/lib/aws/sqs/client.rb +360 -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 +725 -0
- data/lib/aws/sqs/queue_collection.rb +170 -0
- data/lib/aws/sqs/received_message.rb +181 -0
- data/lib/aws/sqs/received_sns_message.rb +112 -0
- data/lib/aws/sqs/request.rb +43 -0
- data/lib/aws/sts.rb +152 -0
- data/lib/aws/sts/client.rb +105 -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/net/http/connection_pool.rb +210 -0
- data/lib/net/http/connection_pool/connection.rb +132 -0
- data/lib/net/http/connection_pool/session.rb +93 -0
- data/lib/user.rb +49 -0
- metadata +433 -0
|
@@ -0,0 +1,360 @@
|
|
|
1
|
+
# Copyright 2011-2012 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 'builder'
|
|
15
|
+
require 'uuidtools'
|
|
16
|
+
|
|
17
|
+
module AWS
|
|
18
|
+
class S3
|
|
19
|
+
|
|
20
|
+
# A lifecycle configuration is collections of rules for a single
|
|
21
|
+
# bucket that instructs that instruct
|
|
22
|
+
# Amazon S3 to delete certain objects after a period of days.
|
|
23
|
+
#
|
|
24
|
+
# == Rules
|
|
25
|
+
#
|
|
26
|
+
# Each lifecycle configuration has a list of rules. Each rule has the
|
|
27
|
+
# following attributes:
|
|
28
|
+
#
|
|
29
|
+
# * +#prefix+
|
|
30
|
+
# * +#expiration_days+
|
|
31
|
+
# * +#status+
|
|
32
|
+
# * +#id+
|
|
33
|
+
#
|
|
34
|
+
# Objects with keys matching a rule prefix will be deleted after
|
|
35
|
+
# #expiration_days have passed.
|
|
36
|
+
#
|
|
37
|
+
# A rule is comprised primarily of a prefix and number of expiration days.
|
|
38
|
+
# Objects with keys that start with the given prefix will be automatically
|
|
39
|
+
# deleted after "expiration days" have passed. Rules also have an
|
|
40
|
+
# ID and a status (they can be disabled).
|
|
41
|
+
#
|
|
42
|
+
# See {Rule} for more information on all of the attributes and methods
|
|
43
|
+
# available for rules.
|
|
44
|
+
#
|
|
45
|
+
# == Adding Rules
|
|
46
|
+
#
|
|
47
|
+
# You can add a rule to a bucket lifecycle configuration using {#add_rule}.
|
|
48
|
+
#
|
|
49
|
+
# # add a rule that deletes backups after they are 1 year old
|
|
50
|
+
# bucket.lifecycle_configuration.update do
|
|
51
|
+
# add_rule('backups/', 365)
|
|
52
|
+
# end
|
|
53
|
+
#
|
|
54
|
+
# If you perfer to specify a rule's ID or status (defaults to 'Enabled')
|
|
55
|
+
# you can do this with {#add_rule}.
|
|
56
|
+
#
|
|
57
|
+
# # add a rule that deletes backups after they are 1 year old
|
|
58
|
+
# bucket.lifecycle_configuration.update do
|
|
59
|
+
# add_rule('backups/', 365, :id => 'backup-rule', :disabled => true
|
|
60
|
+
# end
|
|
61
|
+
#
|
|
62
|
+
# == Replacing Rules
|
|
63
|
+
#
|
|
64
|
+
# If you prefer to completely replace a lifecycle configuration, call
|
|
65
|
+
# {#add_rule} inside a #replace block instead of an #update block:
|
|
66
|
+
#
|
|
67
|
+
# # replace all existing rules with the following
|
|
68
|
+
# bucket.lifecycle_configuration.replace do
|
|
69
|
+
# add_rule('backups/', 30)
|
|
70
|
+
# add_rule('temp/', 10)
|
|
71
|
+
# end
|
|
72
|
+
#
|
|
73
|
+
# == Removing Rules
|
|
74
|
+
#
|
|
75
|
+
# You can delete specific rules with #remove_rule.
|
|
76
|
+
#
|
|
77
|
+
# # delete all disabled rules
|
|
78
|
+
# bucket.lifecycle_configuration.update do
|
|
79
|
+
# rules.each do |rule|
|
|
80
|
+
# remove_rule(rule) if rule.disabled?
|
|
81
|
+
# end
|
|
82
|
+
# end
|
|
83
|
+
#
|
|
84
|
+
# You can also remove all rules in a single call:
|
|
85
|
+
#
|
|
86
|
+
# # remove all rules from this lifecycle configuration
|
|
87
|
+
# bucket.lifecycle_configuration.clear
|
|
88
|
+
#
|
|
89
|
+
# == Editing Existing Rules
|
|
90
|
+
#
|
|
91
|
+
# You can also make changes to existing rules.
|
|
92
|
+
#
|
|
93
|
+
# # change the expiration days to 10 for EVERY rule
|
|
94
|
+
# bucket.lifecycle_configuration.update do
|
|
95
|
+
# rules.each do |rule|
|
|
96
|
+
# rule.expiration_days = 10
|
|
97
|
+
# end
|
|
98
|
+
# end
|
|
99
|
+
#
|
|
100
|
+
# Please be aware, if you add, remove or edit rules outside of an
|
|
101
|
+
# #update or #replace block, then you must call {#update} yourself
|
|
102
|
+
# or the changes will not be persisted.
|
|
103
|
+
#
|
|
104
|
+
class BucketLifecycleConfiguration
|
|
105
|
+
|
|
106
|
+
# @private
|
|
107
|
+
def initialize bucket, options = {}
|
|
108
|
+
@bucket = bucket
|
|
109
|
+
@rules = parse_xml(options[:xml]) if options[:xml]
|
|
110
|
+
@rules = [] if options[:empty] == true
|
|
111
|
+
end
|
|
112
|
+
|
|
113
|
+
# @return [Bucket] Returns the bucket this lifecycle configuration
|
|
114
|
+
# belongs to.
|
|
115
|
+
attr_reader :bucket
|
|
116
|
+
|
|
117
|
+
# @return [Array<Hash>] Returns an array of rules.
|
|
118
|
+
def rules
|
|
119
|
+
@rules ||= begin
|
|
120
|
+
begin
|
|
121
|
+
opts = { :bucket_name => bucket.name }
|
|
122
|
+
response = bucket.client.get_bucket_lifecycle_configuration(opts)
|
|
123
|
+
parse_xml(response.http_response.body)
|
|
124
|
+
rescue Errors::NoSuchLifecycleConfiguration
|
|
125
|
+
[]
|
|
126
|
+
end
|
|
127
|
+
end
|
|
128
|
+
end
|
|
129
|
+
|
|
130
|
+
# @param [String] prefix
|
|
131
|
+
#
|
|
132
|
+
# @param [Integer] expiration_days Indicates the lifetime for objects
|
|
133
|
+
# matching the given prefix.
|
|
134
|
+
#
|
|
135
|
+
# @param [Hash] options
|
|
136
|
+
#
|
|
137
|
+
# @option options [String] :id A unique ID for this rule. If an ID
|
|
138
|
+
# is not provided, one will be generated.
|
|
139
|
+
#
|
|
140
|
+
# @option options [Boolean] :disabled (false) By default, all rules
|
|
141
|
+
# will have the status of enabled. You can override this default
|
|
142
|
+
# by passing +:disabled+ => true.
|
|
143
|
+
#
|
|
144
|
+
# @return [Rule] Returns the rule that was added, as a {Rule} object.
|
|
145
|
+
#
|
|
146
|
+
def add_rule prefix, expiration_days, options = {}
|
|
147
|
+
id = options[:id] || UUIDTools::UUID.random_create.to_s
|
|
148
|
+
status = options[:disabled] == true ? 'Disabled' : 'Enabled'
|
|
149
|
+
rule = Rule.new(self, id, prefix, expiration_days, status)
|
|
150
|
+
self.rules << rule
|
|
151
|
+
rule
|
|
152
|
+
end
|
|
153
|
+
|
|
154
|
+
# Removes a single rule. You can pass a rule id or a {Rule}
|
|
155
|
+
# object.
|
|
156
|
+
#
|
|
157
|
+
# # remove a single rule by its ID
|
|
158
|
+
# bucket.lifecycle_configuration.update do
|
|
159
|
+
# remove_rule('rule-id')
|
|
160
|
+
# end
|
|
161
|
+
#
|
|
162
|
+
# # remove all disabled rules
|
|
163
|
+
# bucket.lifecycle_configuration.update do
|
|
164
|
+
# rules.each do |rule|
|
|
165
|
+
# remove_rule(rule) if rule.disabled?
|
|
166
|
+
# end
|
|
167
|
+
# end
|
|
168
|
+
#
|
|
169
|
+
# If you call #remove_rule outside an update block
|
|
170
|
+
# you need to call #update to save the changes.
|
|
171
|
+
#
|
|
172
|
+
# @param [Rule,String] rule_or_rule_id
|
|
173
|
+
#
|
|
174
|
+
# @return [nil]
|
|
175
|
+
#
|
|
176
|
+
def remove_rule rule_or_rule_id
|
|
177
|
+
rule_id = rule_or_rule_id
|
|
178
|
+
if rule_id.nil?
|
|
179
|
+
raise ArgumentError, "expected a rule or rule id, got nil"
|
|
180
|
+
end
|
|
181
|
+
rule_id = rule_id.id unless rule_id.is_a?(String)
|
|
182
|
+
@rules = rules.select{|r| r.id != rule_id }
|
|
183
|
+
nil
|
|
184
|
+
end
|
|
185
|
+
|
|
186
|
+
# Saves changes made to this lifecycle configuration.
|
|
187
|
+
#
|
|
188
|
+
# # set the number of days before expiration for all rules to 10
|
|
189
|
+
# config = bucket.lifecycle_configuration
|
|
190
|
+
# config.rules.each do |rule|
|
|
191
|
+
# rule.expiration_days = 10
|
|
192
|
+
# end
|
|
193
|
+
# config.update
|
|
194
|
+
#
|
|
195
|
+
# You can call #update with a block. Changes are persisted at the
|
|
196
|
+
# end of the block.
|
|
197
|
+
#
|
|
198
|
+
# # shorter version of the example above
|
|
199
|
+
# bucket.lifecycle_configuration.update do
|
|
200
|
+
# rules.each {|rule| rule.expiration_days = 10 }
|
|
201
|
+
# end
|
|
202
|
+
#
|
|
203
|
+
# A block method for updating a BucketLifecycleConfiguration.
|
|
204
|
+
# All modifications made inside the block are persisted at the end of
|
|
205
|
+
# the block.
|
|
206
|
+
#
|
|
207
|
+
# # 1 request
|
|
208
|
+
# bucket.lifecycle_configuration.update do
|
|
209
|
+
# add_rule 'prefix/a', 10
|
|
210
|
+
# add_rule 'prefix/b', 5
|
|
211
|
+
# end
|
|
212
|
+
#
|
|
213
|
+
# # 2 requests
|
|
214
|
+
# bucket.lifecycle_configuration.add_rule 'prefix/a', 10
|
|
215
|
+
# bucket.lifecycle_configuration.add_rule 'prefix/b', 5
|
|
216
|
+
#
|
|
217
|
+
# @return [nil]
|
|
218
|
+
#
|
|
219
|
+
def update &block
|
|
220
|
+
begin
|
|
221
|
+
@batching = true
|
|
222
|
+
instance_eval(&block) if block_given?
|
|
223
|
+
persist(true)
|
|
224
|
+
ensure
|
|
225
|
+
@batching = false
|
|
226
|
+
end
|
|
227
|
+
nil
|
|
228
|
+
end
|
|
229
|
+
|
|
230
|
+
# Yields to the given block. Before yielding, the current
|
|
231
|
+
# rules will be blanked out. This allows you to provide all
|
|
232
|
+
# new rules.
|
|
233
|
+
#
|
|
234
|
+
# When the block is complete, a single call will be made to save
|
|
235
|
+
# the new rules.
|
|
236
|
+
#
|
|
237
|
+
# bucket.lifecycle_configuration.rules.size #=> 3
|
|
238
|
+
#
|
|
239
|
+
# # replace the existing 3 rules with a single rule
|
|
240
|
+
# bucket.lifecycle_configuration.replace
|
|
241
|
+
# add_rule 'temp/', 10
|
|
242
|
+
# end
|
|
243
|
+
#
|
|
244
|
+
# bucket.lifecycle_configuration.rules.size #=> 1
|
|
245
|
+
#
|
|
246
|
+
def replace &block
|
|
247
|
+
@rules = []
|
|
248
|
+
update(&block)
|
|
249
|
+
end
|
|
250
|
+
|
|
251
|
+
def clear
|
|
252
|
+
@rules = []
|
|
253
|
+
bucket.lifecycle_configuration = nil
|
|
254
|
+
end
|
|
255
|
+
alias_method :remove, :clear
|
|
256
|
+
|
|
257
|
+
# @return [String] Returns an xml string representation of this
|
|
258
|
+
# bucket lifecycle configuration.
|
|
259
|
+
def to_xml
|
|
260
|
+
xml = Builder::XmlMarkup.new(:indent => 2)
|
|
261
|
+
xml.LifecycleConfiguration do
|
|
262
|
+
rules.each do |rule|
|
|
263
|
+
xml.Rule do
|
|
264
|
+
xml.ID rule.id
|
|
265
|
+
xml.Prefix rule.prefix
|
|
266
|
+
xml.Status rule.status
|
|
267
|
+
xml.Expiration do
|
|
268
|
+
xml.Days rule.expiration_days
|
|
269
|
+
end
|
|
270
|
+
end
|
|
271
|
+
end
|
|
272
|
+
end.strip
|
|
273
|
+
end
|
|
274
|
+
|
|
275
|
+
protected
|
|
276
|
+
def persist force = false
|
|
277
|
+
unless @batching and force == false
|
|
278
|
+
if rules.empty?
|
|
279
|
+
bucket.lifecycle_configuration = nil
|
|
280
|
+
else
|
|
281
|
+
bucket.lifecycle_configuration = self
|
|
282
|
+
end
|
|
283
|
+
end
|
|
284
|
+
end
|
|
285
|
+
|
|
286
|
+
protected
|
|
287
|
+
def parse_xml xml
|
|
288
|
+
Client::XML::GetBucketLifecycleConfiguration.parse(xml).rules.map do |r|
|
|
289
|
+
Rule.new(self, r.id, r.prefix, r.expiration.days, r.status)
|
|
290
|
+
end
|
|
291
|
+
end
|
|
292
|
+
|
|
293
|
+
# Represents a single rule from an Amazon S3 bucket lifecycle
|
|
294
|
+
# configuration.
|
|
295
|
+
#
|
|
296
|
+
# # delete all objects with the prefix 'temporary/' after 10 days
|
|
297
|
+
# bucket.lifecycle_configuration.add_rule 'temporary/', 10
|
|
298
|
+
#
|
|
299
|
+
# # remove the rule created above
|
|
300
|
+
# bucket.lifecycle_configuration.remove_rule 'temporary/'
|
|
301
|
+
#
|
|
302
|
+
#
|
|
303
|
+
class Rule
|
|
304
|
+
|
|
305
|
+
def initialize configuration, id, prefix, expiration_days, status
|
|
306
|
+
@configuration = configuration
|
|
307
|
+
@id = id
|
|
308
|
+
@prefix = prefix
|
|
309
|
+
@expiration_days = expiration_days
|
|
310
|
+
@status = status
|
|
311
|
+
end
|
|
312
|
+
|
|
313
|
+
# @return [BucketLifecycleConfiguration]
|
|
314
|
+
attr_reader :configuration
|
|
315
|
+
|
|
316
|
+
# @return [String]
|
|
317
|
+
attr_reader :id
|
|
318
|
+
|
|
319
|
+
# @return [String]
|
|
320
|
+
attr_accessor :prefix
|
|
321
|
+
|
|
322
|
+
# @return [Integer]
|
|
323
|
+
attr_accessor :expiration_days
|
|
324
|
+
|
|
325
|
+
# @return [String] Returns the rule status, 'Enabled' or 'Disabled'
|
|
326
|
+
attr_accessor :status
|
|
327
|
+
|
|
328
|
+
def enabled?
|
|
329
|
+
status == 'Enabled'
|
|
330
|
+
end
|
|
331
|
+
|
|
332
|
+
def enable!
|
|
333
|
+
self.status = 'Enabled'
|
|
334
|
+
end
|
|
335
|
+
|
|
336
|
+
def disabled?
|
|
337
|
+
status == 'Disabled'
|
|
338
|
+
end
|
|
339
|
+
|
|
340
|
+
def disabled!
|
|
341
|
+
self.status = 'Disabled'
|
|
342
|
+
end
|
|
343
|
+
|
|
344
|
+
# @private
|
|
345
|
+
def eql? other
|
|
346
|
+
other.is_a?(Rule) and
|
|
347
|
+
other.configuration.bucket == configuration.bucket and
|
|
348
|
+
other.id == id and
|
|
349
|
+
other.prefix == prefix and
|
|
350
|
+
other.expiration_days == expiration_days and
|
|
351
|
+
other.status == status
|
|
352
|
+
end
|
|
353
|
+
alias_method :==, :eql?
|
|
354
|
+
|
|
355
|
+
end
|
|
356
|
+
|
|
357
|
+
end
|
|
358
|
+
|
|
359
|
+
end
|
|
360
|
+
end
|
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
# Copyright 2011-2012 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,1184 @@
|
|
|
1
|
+
# Copyright 2011-2012 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
|
+
|
|
20
|
+
module AWS
|
|
21
|
+
class S3
|
|
22
|
+
|
|
23
|
+
# Client class for Amazon Simple Storage Service (S3).
|
|
24
|
+
class Client < Core::Client
|
|
25
|
+
|
|
26
|
+
API_VERSION = '2006-03-01'
|
|
27
|
+
|
|
28
|
+
XMLNS = "http://s3.amazonaws.com/doc/#{API_VERSION}/"
|
|
29
|
+
|
|
30
|
+
AWS.register_autoloads(self) do
|
|
31
|
+
autoload :XML, 'xml'
|
|
32
|
+
end
|
|
33
|
+
|
|
34
|
+
# @private
|
|
35
|
+
EMPTY_BODY_ERRORS = {
|
|
36
|
+
304 => Errors::NotModified,
|
|
37
|
+
404 => Errors::NoSuchKey
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
# @private
|
|
41
|
+
CACHEABLE_REQUESTS = Set[]
|
|
42
|
+
|
|
43
|
+
include DataOptions
|
|
44
|
+
include Core::UriEscape
|
|
45
|
+
|
|
46
|
+
protected
|
|
47
|
+
|
|
48
|
+
def self.bucket_method(method_name, verb, *args, &block)
|
|
49
|
+
|
|
50
|
+
method_options = (args.pop if args.last.kind_of?(Hash)) || {}
|
|
51
|
+
xml_grammar = (args.pop if args.last.respond_to?(:rules))
|
|
52
|
+
verb = verb.to_s.upcase
|
|
53
|
+
subresource = args.first
|
|
54
|
+
|
|
55
|
+
add_client_request_method(method_name) do
|
|
56
|
+
|
|
57
|
+
configure_request do |req, options|
|
|
58
|
+
require_bucket_name!(options[:bucket_name])
|
|
59
|
+
req.http_method = verb
|
|
60
|
+
req.bucket = options[:bucket_name]
|
|
61
|
+
req.add_param(subresource) if subresource
|
|
62
|
+
|
|
63
|
+
if header_options = method_options[:header_options]
|
|
64
|
+
header_options.each do |(option_name, header)|
|
|
65
|
+
req.headers[header] = options[option_name] if
|
|
66
|
+
options[option_name]
|
|
67
|
+
end
|
|
68
|
+
end
|
|
69
|
+
|
|
70
|
+
end
|
|
71
|
+
|
|
72
|
+
instance_eval(&block) if block
|
|
73
|
+
|
|
74
|
+
if xml_grammar
|
|
75
|
+
|
|
76
|
+
parser = Core::XML::Parser.new(xml_grammar.rules)
|
|
77
|
+
|
|
78
|
+
process_response do |resp|
|
|
79
|
+
resp.data = parser.parse(resp.http_response.body)
|
|
80
|
+
super(resp)
|
|
81
|
+
end
|
|
82
|
+
|
|
83
|
+
simulate_response do |resp|
|
|
84
|
+
resp.data = parser.simulate
|
|
85
|
+
super(resp)
|
|
86
|
+
end
|
|
87
|
+
|
|
88
|
+
end
|
|
89
|
+
|
|
90
|
+
end
|
|
91
|
+
end
|
|
92
|
+
|
|
93
|
+
def self.object_method(method_name, verb, *args, &block)
|
|
94
|
+
bucket_method(method_name, verb, *args) do
|
|
95
|
+
configure_request do |req, options|
|
|
96
|
+
validate_key!(options[:key])
|
|
97
|
+
super(req, options)
|
|
98
|
+
req.key = options[:key]
|
|
99
|
+
end
|
|
100
|
+
|
|
101
|
+
instance_eval(&block) if block
|
|
102
|
+
end
|
|
103
|
+
end
|
|
104
|
+
|
|
105
|
+
public
|
|
106
|
+
|
|
107
|
+
# Creates a bucket.
|
|
108
|
+
# @overload create_bucket(options = {})
|
|
109
|
+
# @param [Hash] options
|
|
110
|
+
# @option options [required,String] :bucket_name
|
|
111
|
+
# @return [Core::Response]
|
|
112
|
+
bucket_method(:create_bucket, :put) do
|
|
113
|
+
configure_request do |req, options|
|
|
114
|
+
validate_bucket_name!(options[:bucket_name])
|
|
115
|
+
req.canned_acl = options[:acl]
|
|
116
|
+
if location = options[:location_constraint]
|
|
117
|
+
xmlns = "http://s3.amazonaws.com/doc/#{API_VERSION}/"
|
|
118
|
+
req.body = <<-XML
|
|
119
|
+
<CreateBucketConfiguration xmlns="#{xmlns}">
|
|
120
|
+
<LocationConstraint>#{location}</LocationConstraint>
|
|
121
|
+
</CreateBucketConfiguration>
|
|
122
|
+
XML
|
|
123
|
+
end
|
|
124
|
+
super(req, options)
|
|
125
|
+
end
|
|
126
|
+
end
|
|
127
|
+
|
|
128
|
+
# Deletes an empty bucket.
|
|
129
|
+
# @overload delete_bucket(options = {})
|
|
130
|
+
# @param [Hash] options
|
|
131
|
+
# @option options [required,String] :bucket_name
|
|
132
|
+
# @return [Core::Response]
|
|
133
|
+
bucket_method(:delete_bucket, :delete)
|
|
134
|
+
|
|
135
|
+
# @overload set_bucket_lifecycle_configuration(options = {})
|
|
136
|
+
# @param [Hash] options
|
|
137
|
+
# @option options [required,String] :bucket_name
|
|
138
|
+
# @option options [required,String] :lifecycle_configuration
|
|
139
|
+
# @return [Core::Response]
|
|
140
|
+
bucket_method(:set_bucket_lifecycle_configuration, :put) do
|
|
141
|
+
|
|
142
|
+
configure_request do |req, options|
|
|
143
|
+
xml = options[:lifecycle_configuration]
|
|
144
|
+
md5 = Base64.encode64(Digest::MD5.digest(xml)).strip
|
|
145
|
+
req.add_param('lifecycle')
|
|
146
|
+
req.body = xml
|
|
147
|
+
req.headers['content-md5'] = md5
|
|
148
|
+
super(req, options)
|
|
149
|
+
end
|
|
150
|
+
|
|
151
|
+
end
|
|
152
|
+
|
|
153
|
+
# @overload get_bucket_lifecycle_configuration(options = {})
|
|
154
|
+
# @param [Hash] options
|
|
155
|
+
# @option options [required,String] :bucket_name
|
|
156
|
+
# @return [Core::Response]
|
|
157
|
+
bucket_method(:get_bucket_lifecycle_configuration, :get) do
|
|
158
|
+
|
|
159
|
+
configure_request do |req, options|
|
|
160
|
+
req.add_param('lifecycle')
|
|
161
|
+
super(req, options)
|
|
162
|
+
end
|
|
163
|
+
|
|
164
|
+
process_response do |resp|
|
|
165
|
+
xml = resp.http_response.body
|
|
166
|
+
resp.data = XML::GetBucketLifecycleConfiguration.parse(xml)
|
|
167
|
+
end
|
|
168
|
+
|
|
169
|
+
end
|
|
170
|
+
|
|
171
|
+
# @overload delete_bucket_lifecycle_configuration(options = {})
|
|
172
|
+
# @param [Hash] options
|
|
173
|
+
# @option options [required,String] :bucket_name
|
|
174
|
+
# @return [Core::Response]
|
|
175
|
+
bucket_method(:delete_bucket_lifecycle_configuration, :delete) do
|
|
176
|
+
|
|
177
|
+
configure_request do |req, options|
|
|
178
|
+
req.add_param('lifecycle')
|
|
179
|
+
super(req, options)
|
|
180
|
+
end
|
|
181
|
+
|
|
182
|
+
end
|
|
183
|
+
|
|
184
|
+
# @overload list_buckets(options = {})
|
|
185
|
+
# @param [Hash] options
|
|
186
|
+
# @return [Core::Response]
|
|
187
|
+
add_client_request_method(:list_buckets) do
|
|
188
|
+
|
|
189
|
+
configure_request do |req, options|
|
|
190
|
+
req.http_method = "GET"
|
|
191
|
+
end
|
|
192
|
+
|
|
193
|
+
process_response do |resp|
|
|
194
|
+
resp.data = XML::ListBuckets.parse(resp.http_response.body)
|
|
195
|
+
end
|
|
196
|
+
|
|
197
|
+
simulate_response do |resp|
|
|
198
|
+
resp.data = Core::XML::Parser.new(XML::ListBuckets.rules).simulate
|
|
199
|
+
end
|
|
200
|
+
|
|
201
|
+
end
|
|
202
|
+
|
|
203
|
+
# Sets the access policy for a bucket.
|
|
204
|
+
# @overload set_bucket_policy(options = {})
|
|
205
|
+
# @param [Hash] options
|
|
206
|
+
# @option options [required,String] :bucket_name
|
|
207
|
+
# @option options [required,String] :policy This can be a String
|
|
208
|
+
# or any object that responds to +#to_json+.
|
|
209
|
+
# @return [Core::Response]
|
|
210
|
+
bucket_method(:set_bucket_policy, :put, 'policy') do
|
|
211
|
+
|
|
212
|
+
configure_request do |req, options|
|
|
213
|
+
require_policy!(options[:policy])
|
|
214
|
+
super(req, options)
|
|
215
|
+
policy = options[:policy]
|
|
216
|
+
policy = policy.to_json unless policy.respond_to?(:to_str)
|
|
217
|
+
req.body = policy
|
|
218
|
+
end
|
|
219
|
+
|
|
220
|
+
end
|
|
221
|
+
|
|
222
|
+
# Gets the access policy for a bucket.
|
|
223
|
+
# @overload get_bucket_policy(options = {})
|
|
224
|
+
# @param [Hash] options
|
|
225
|
+
# @option options [required,String] :bucket_name
|
|
226
|
+
# @return [Core::Response]
|
|
227
|
+
bucket_method(:get_bucket_policy, :get, 'policy') do
|
|
228
|
+
|
|
229
|
+
process_response do |resp|
|
|
230
|
+
resp.data[:policy] = resp.http_response.body
|
|
231
|
+
end
|
|
232
|
+
|
|
233
|
+
end
|
|
234
|
+
|
|
235
|
+
# Deletes the access policy for a bucket.
|
|
236
|
+
# @overload delete_bucket_policy(options = {})
|
|
237
|
+
# @param [Hash] options
|
|
238
|
+
# @option options [required,String] :bucket_name
|
|
239
|
+
# @return [Core::Response]
|
|
240
|
+
bucket_method(:delete_bucket_policy, :delete, 'policy')
|
|
241
|
+
|
|
242
|
+
# @overload set_bucket_versioning(options = {})
|
|
243
|
+
# @param [Hash] options
|
|
244
|
+
# @option options [required,String] :bucket_name
|
|
245
|
+
# @option options [required,String] :state
|
|
246
|
+
# @return [Core::Response]
|
|
247
|
+
bucket_method(:set_bucket_versioning, :put, 'versioning') do
|
|
248
|
+
|
|
249
|
+
configure_request do |req, options|
|
|
250
|
+
state = options[:state].to_s.downcase.capitalize
|
|
251
|
+
unless state =~ /^(Enabled|Suspended)$/
|
|
252
|
+
raise ArgumentError, "invalid versioning state `#{state}`"
|
|
253
|
+
end
|
|
254
|
+
super(req, options)
|
|
255
|
+
req.body = <<-XML.strip
|
|
256
|
+
<VersioningConfiguration xmlns="#{XMLNS}">
|
|
257
|
+
<Status>#{state}</Status>
|
|
258
|
+
</VersioningConfiguration>
|
|
259
|
+
XML
|
|
260
|
+
end
|
|
261
|
+
|
|
262
|
+
end
|
|
263
|
+
|
|
264
|
+
# Gets the bucket's location constraint.
|
|
265
|
+
# @overload get_bucket_location(options = {})
|
|
266
|
+
# @param [Hash] options
|
|
267
|
+
# @option options [required,String] :bucket_name
|
|
268
|
+
# @return [Core::Response]
|
|
269
|
+
bucket_method(:get_bucket_location, :get, 'location') do
|
|
270
|
+
|
|
271
|
+
process_response do |response|
|
|
272
|
+
regex = />(.*)<\/LocationConstraint>/
|
|
273
|
+
matches = response.http_response.body.match(regex)
|
|
274
|
+
response.data[:location_constraint] = matches ? matches[1] : nil
|
|
275
|
+
end
|
|
276
|
+
|
|
277
|
+
end
|
|
278
|
+
|
|
279
|
+
# @overload get_bucket_versioning(options = {})
|
|
280
|
+
# @param [Hash] options
|
|
281
|
+
# @option options [required,String] :bucket_name
|
|
282
|
+
# @return [Core::Response]
|
|
283
|
+
bucket_method(:get_bucket_versioning, :get, 'versioning',
|
|
284
|
+
XML::GetBucketVersioning)
|
|
285
|
+
|
|
286
|
+
# @overload list_object_versions(options = {})
|
|
287
|
+
# @param [Hash] options
|
|
288
|
+
# @option options [required,String] :bucket_name
|
|
289
|
+
# @option options [String] :prefix
|
|
290
|
+
# @option options [String] :delimiter
|
|
291
|
+
# @option options [String] :max_keys
|
|
292
|
+
# @option options [String] :key_marker
|
|
293
|
+
# @option options [String] :version_id_marker
|
|
294
|
+
# @return [Core::Response]
|
|
295
|
+
bucket_method(:list_object_versions, :get, 'versions',
|
|
296
|
+
XML::ListObjectVersions) do
|
|
297
|
+
|
|
298
|
+
configure_request do |req, options|
|
|
299
|
+
super(req, options)
|
|
300
|
+
params = %w(delimiter key_marker max_keys prefix version_id_marker)
|
|
301
|
+
params.each do |param|
|
|
302
|
+
if options[param.to_sym]
|
|
303
|
+
req.add_param(param.gsub(/_/, '-'), options[param.to_sym])
|
|
304
|
+
end
|
|
305
|
+
end
|
|
306
|
+
end
|
|
307
|
+
|
|
308
|
+
end
|
|
309
|
+
|
|
310
|
+
# Sets the access control list for a bucket.
|
|
311
|
+
# @overload set_bucket_acl(options = {})
|
|
312
|
+
# @param [Hash] options
|
|
313
|
+
# @option options [required,String] :bucket_name
|
|
314
|
+
# @option options [required,String,AccessControlList,Hash] :acl
|
|
315
|
+
# This may be any of the following:
|
|
316
|
+
# * An XML policy as a string (which is passed to S3 uninterpreted)
|
|
317
|
+
# * An {AccessControlList} object
|
|
318
|
+
# * Any object that responds to +#to_xml+
|
|
319
|
+
# * A hash that is compatible with {AccessControlList} #new.
|
|
320
|
+
# @return [Core::Response]
|
|
321
|
+
bucket_method(:set_bucket_acl, :put, 'acl') do
|
|
322
|
+
|
|
323
|
+
configure_request do |req, options|
|
|
324
|
+
require_acl!(options[:acl])
|
|
325
|
+
super(req, options)
|
|
326
|
+
if options[:acl].kind_of?(Hash)
|
|
327
|
+
req.body = AccessControlList.new(options[:acl]).to_xml
|
|
328
|
+
elsif options[:acl].respond_to?(:to_str)
|
|
329
|
+
req.body = options[:acl]
|
|
330
|
+
else
|
|
331
|
+
req.body = options[:acl].to_xml
|
|
332
|
+
end
|
|
333
|
+
end
|
|
334
|
+
|
|
335
|
+
end
|
|
336
|
+
|
|
337
|
+
# Gets the access control list for a bucket.
|
|
338
|
+
# @overload get_bucket_acl(options = {})
|
|
339
|
+
# @param [Hash] options
|
|
340
|
+
# @option options [required,String] :bucket_name
|
|
341
|
+
# @return [Core::Response]
|
|
342
|
+
bucket_method(:get_bucket_acl, :get, 'acl', XML::GetBucketAcl)
|
|
343
|
+
|
|
344
|
+
# Sets the access control list for an object.
|
|
345
|
+
# @overload set_object_acl(options = {})
|
|
346
|
+
# @param [Hash] options
|
|
347
|
+
# @option options [required,String] :bucket_name
|
|
348
|
+
# @option options [required,String] :key
|
|
349
|
+
# @option options [required,String,AccessControlList,Hash] :acl
|
|
350
|
+
# This may be any of the following:
|
|
351
|
+
# * An XML policy as a string (which is passed to S3 uninterpreted)
|
|
352
|
+
# * An {AccessControlList} object
|
|
353
|
+
# * Any object that responds to +#to_xml+
|
|
354
|
+
# * A hash that is compatible with {AccessControlList} #new.
|
|
355
|
+
# @return [Core::Response]
|
|
356
|
+
object_method(:set_object_acl, :put, 'acl') do
|
|
357
|
+
configure_request do |req, options|
|
|
358
|
+
require_acl!(options[:acl]) unless options[:acl].kind_of?(Symbol)
|
|
359
|
+
super(req, options)
|
|
360
|
+
if options[:acl].kind_of?(Hash)
|
|
361
|
+
req.body = AccessControlList.new(options[:acl]).to_xml
|
|
362
|
+
elsif options[:acl].kind_of?(Symbol)
|
|
363
|
+
req.headers["x-amz-acl"] = options[:acl].to_s.tr("_","-")
|
|
364
|
+
elsif options[:acl].respond_to?(:to_str)
|
|
365
|
+
req.body = options[:acl]
|
|
366
|
+
else
|
|
367
|
+
req.body = options[:acl].to_xml
|
|
368
|
+
end
|
|
369
|
+
end
|
|
370
|
+
end
|
|
371
|
+
|
|
372
|
+
# Gets the access control list for an object.
|
|
373
|
+
# @overload get_object_acl(options = {})
|
|
374
|
+
# @param [Hash] options
|
|
375
|
+
# @option options [required,String] :bucket_name
|
|
376
|
+
# @option options [required,String] :key
|
|
377
|
+
# @return [Core::Response]
|
|
378
|
+
object_method(:get_object_acl, :get, 'acl', XML::GetBucketAcl)
|
|
379
|
+
|
|
380
|
+
# Puts data into an object, replacing the current contents.
|
|
381
|
+
#
|
|
382
|
+
# s3_client.put_object({
|
|
383
|
+
# :bucket_name => 'bucket-name',
|
|
384
|
+
# :key => 'readme.txt',
|
|
385
|
+
# :data => 'This is the readme for ...',
|
|
386
|
+
# })
|
|
387
|
+
#
|
|
388
|
+
# == Block Form
|
|
389
|
+
#
|
|
390
|
+
# In block form, this method yields a stream to the block that
|
|
391
|
+
# accepts data chunks. For example:
|
|
392
|
+
#
|
|
393
|
+
# s3_client.put_object(
|
|
394
|
+
# :bucket_name => 'mybucket',
|
|
395
|
+
# :key => 'some/key'
|
|
396
|
+
# :content_length => File.size('myfile')
|
|
397
|
+
# ) do |buffer|
|
|
398
|
+
#
|
|
399
|
+
# File.open('myfile') do |io|
|
|
400
|
+
# buffer.write(io.read(length)) until io.eof?
|
|
401
|
+
# end
|
|
402
|
+
#
|
|
403
|
+
# end
|
|
404
|
+
#
|
|
405
|
+
# This form is useful if you need finer control over how
|
|
406
|
+
# potentially large amounts of data are read from another
|
|
407
|
+
# source before being sent to S3; for example, if you are
|
|
408
|
+
# using a non-blocking IO model and reading from a large file
|
|
409
|
+
# on disk or from another network stream. Some HTTP handlers
|
|
410
|
+
# do not support streaming request bodies, so if you plan to
|
|
411
|
+
# upload large objects using this interface you should make
|
|
412
|
+
# sure the HTTP handler you configure for the client meets
|
|
413
|
+
# your needs.
|
|
414
|
+
#
|
|
415
|
+
# @overload put_object(options = {})
|
|
416
|
+
# @param [Hash] options
|
|
417
|
+
# @option options [required,String] :bucket_name
|
|
418
|
+
# @option options [required,String] :key
|
|
419
|
+
# @option options [required,String,Pathname,File,IO] :data
|
|
420
|
+
# The data to upload. This can be provided as a string,
|
|
421
|
+
# a Pathname object, or any object that responds to
|
|
422
|
+
# +#read+ and +#eof?+ (e.g. IO, File, Tempfile, StringIO, etc).
|
|
423
|
+
# @option options [Integer] :content_length
|
|
424
|
+
# Required if you are using block form to write data or if it is
|
|
425
|
+
# not possible to determine the size of +:data+. A best effort
|
|
426
|
+
# is made to determine the content length of strings, files,
|
|
427
|
+
# tempfiles, io objects, and any object that responds
|
|
428
|
+
# to +#length+ or +#size+.
|
|
429
|
+
# @option options [Hash] :metadata
|
|
430
|
+
# A hash of metadata to be included with the
|
|
431
|
+
# object. These will be sent to S3 as headers prefixed with
|
|
432
|
+
# +x-amz-meta+.
|
|
433
|
+
# @option options [Symbol] :acl (:private) A canned access
|
|
434
|
+
# control policy. Accepted values include:
|
|
435
|
+
# * +:private+
|
|
436
|
+
# * +:public_read+
|
|
437
|
+
# * ...
|
|
438
|
+
# @option options [Symbol] :storage_class+ (:standard)
|
|
439
|
+
# Controls whether Reduced Redundancy Storage is enabled for
|
|
440
|
+
# the object. Valid values are +:standard+ and
|
|
441
|
+
# +:reduced_redundancy+.
|
|
442
|
+
# @option options [String] :cache_control
|
|
443
|
+
# Can be used to specify caching behavior.
|
|
444
|
+
# @option opitons [String] :content_disposition
|
|
445
|
+
# Specifies presentational information.
|
|
446
|
+
# @option options [String] :content_encoding
|
|
447
|
+
# Specifies the content encoding.
|
|
448
|
+
# @option options [String] :content_md5
|
|
449
|
+
# The base64 encoded content md5 of the +:data+.
|
|
450
|
+
# @option options [String] :content_type
|
|
451
|
+
# Specifies the content type.
|
|
452
|
+
# @option options [String] :expires
|
|
453
|
+
# @return [Core::Response]
|
|
454
|
+
#
|
|
455
|
+
object_method(:put_object, :put,
|
|
456
|
+
:header_options => {
|
|
457
|
+
:content_md5 => 'Content-MD5',
|
|
458
|
+
:cache_control => 'Cache-Control',
|
|
459
|
+
:content_disposition => 'Content-Disposition',
|
|
460
|
+
:content_encoding => 'Content-Encoding',
|
|
461
|
+
:content_type => 'Content-Type',
|
|
462
|
+
:storage_class => 'x-amz-storage-class',
|
|
463
|
+
:server_side_encryption => 'x-amz-server-side-encryption',
|
|
464
|
+
:expires => 'Expires'
|
|
465
|
+
}) do
|
|
466
|
+
configure_request do |request, options, block|
|
|
467
|
+
options[:server_side_encryption] =
|
|
468
|
+
options[:server_side_encryption].to_s.upcase if
|
|
469
|
+
options[:server_side_encryption].kind_of?(Symbol)
|
|
470
|
+
super(request, options)
|
|
471
|
+
set_request_data(request, options, block)
|
|
472
|
+
request.metadata = options[:metadata]
|
|
473
|
+
request.canned_acl = options[:acl]
|
|
474
|
+
request.storage_class = options[:storage_class]
|
|
475
|
+
end
|
|
476
|
+
|
|
477
|
+
process_response do |response|
|
|
478
|
+
|
|
479
|
+
response.data[:version_id] =
|
|
480
|
+
response.http_response.header('x-amz-version-id')
|
|
481
|
+
|
|
482
|
+
response.data[:etag] = response.http_response.header('ETag')
|
|
483
|
+
|
|
484
|
+
if time = response.http_response.header('Last-Modified')
|
|
485
|
+
response.data[:last_modified] = Time.parse(time)
|
|
486
|
+
end
|
|
487
|
+
|
|
488
|
+
add_sse_to_response(response)
|
|
489
|
+
end
|
|
490
|
+
|
|
491
|
+
simulate_response do |response|
|
|
492
|
+
response.data[:etag] = 'abc123'
|
|
493
|
+
response.data[:version_id] = nil
|
|
494
|
+
end
|
|
495
|
+
|
|
496
|
+
end
|
|
497
|
+
|
|
498
|
+
# Gets the data for a key.
|
|
499
|
+
# @overload get_object(options = {})
|
|
500
|
+
# @param [Hash] options
|
|
501
|
+
# @option options [required,String] :bucket_name
|
|
502
|
+
# @option options [required,String] :key
|
|
503
|
+
# @option options [Time] :if_modified_since If specified, the
|
|
504
|
+
# response will contain an additional +:modified+ value that
|
|
505
|
+
# returns true if the object was modified after the given
|
|
506
|
+
# time. If +:modified+ is false, then the response
|
|
507
|
+
# +:data+ value will be +nil+.
|
|
508
|
+
# @option options [Time] :if_unmodified_since If specified, the
|
|
509
|
+
# response will contain an additional +:unmodified+ value
|
|
510
|
+
# that is true if the object was not modified after the
|
|
511
|
+
# given time. If +:unmodified+ returns false, the +:data+
|
|
512
|
+
# value will be +nil+.
|
|
513
|
+
# @option options [String] :if_match If specified, the response
|
|
514
|
+
# will contain an additional +:matches+ value that is true
|
|
515
|
+
# if the object ETag matches the value for this option. If
|
|
516
|
+
# +:matches+ is false, the +:data+ value of the
|
|
517
|
+
# response will be +nil+.
|
|
518
|
+
# @option options [String] :if_none_match If specified, the
|
|
519
|
+
# response will contain an additional +:matches+ value that
|
|
520
|
+
# is true if and only if the object ETag matches the value for
|
|
521
|
+
# this option. If +:matches+ is true, the +:data+ value
|
|
522
|
+
# of the response will be +nil+.
|
|
523
|
+
# @option options [Range<Integer>] :range A byte range of data to request.
|
|
524
|
+
# @return [Core::Response]
|
|
525
|
+
#
|
|
526
|
+
object_method(:get_object, :get,
|
|
527
|
+
:header_options => {
|
|
528
|
+
:if_modified_since => "If-Modified-Since",
|
|
529
|
+
:if_unmodified_since => "If-Unmodified-Since",
|
|
530
|
+
:if_match => "If-Match",
|
|
531
|
+
:if_none_match => "If-None-Match"
|
|
532
|
+
}) do
|
|
533
|
+
configure_request do |req, options|
|
|
534
|
+
|
|
535
|
+
super(req, options)
|
|
536
|
+
|
|
537
|
+
if options[:version_id]
|
|
538
|
+
req.add_param('versionId', options[:version_id])
|
|
539
|
+
end
|
|
540
|
+
|
|
541
|
+
["If-Modified-Since",
|
|
542
|
+
"If-Unmodified-Since"].each do |date_header|
|
|
543
|
+
case value = req.headers[date_header]
|
|
544
|
+
when DateTime
|
|
545
|
+
req.headers[date_header] = Time.parse(value.to_s).rfc2822
|
|
546
|
+
when Time
|
|
547
|
+
req.headers[date_header] = value.rfc2822
|
|
548
|
+
end
|
|
549
|
+
end
|
|
550
|
+
|
|
551
|
+
if options[:range]
|
|
552
|
+
range = options[:range]
|
|
553
|
+
range = "bytes=#{range.first}-#{range.last}" if range.is_a?(Range)
|
|
554
|
+
req.headers['Range'] = range
|
|
555
|
+
end
|
|
556
|
+
|
|
557
|
+
end
|
|
558
|
+
|
|
559
|
+
process_response do |resp|
|
|
560
|
+
resp.data[:data] = resp.http_response.body
|
|
561
|
+
resp.data[:version_id] = resp.http_response.header('x-amz-version-id')
|
|
562
|
+
add_sse_to_response(resp)
|
|
563
|
+
end
|
|
564
|
+
end
|
|
565
|
+
|
|
566
|
+
# @overload head_object(options = {})
|
|
567
|
+
# @param [Hash] options
|
|
568
|
+
# @option options [required,String] :bucket_name
|
|
569
|
+
# @option options [required,String] :key
|
|
570
|
+
# @option options [String] :version_id
|
|
571
|
+
# @return [Core::Response]
|
|
572
|
+
object_method(:head_object, :head) do
|
|
573
|
+
|
|
574
|
+
configure_request do |req, options|
|
|
575
|
+
super(req, options)
|
|
576
|
+
if options[:version_id]
|
|
577
|
+
req.add_param('versionId', options[:version_id])
|
|
578
|
+
end
|
|
579
|
+
end
|
|
580
|
+
|
|
581
|
+
process_response do |resp|
|
|
582
|
+
|
|
583
|
+
# create a hash of user-supplied metadata
|
|
584
|
+
meta = {}
|
|
585
|
+
resp.http_response.headers.each_pair do |name,value|
|
|
586
|
+
if name =~ /^x-amz-meta-(.+)$/i
|
|
587
|
+
meta[$1] = [value].flatten.join
|
|
588
|
+
end
|
|
589
|
+
end
|
|
590
|
+
meta
|
|
591
|
+
resp.data[:meta] = meta
|
|
592
|
+
|
|
593
|
+
if expiry = resp.http_response.headers['x-amz-expiration']
|
|
594
|
+
expiry.first =~ /^expiry-date="(.+)", rule-id="(.+)"$/
|
|
595
|
+
exp_date = DateTime.parse($1)
|
|
596
|
+
exp_rule_id = $2
|
|
597
|
+
else
|
|
598
|
+
exp_date = nil
|
|
599
|
+
exp_rule_id = nil
|
|
600
|
+
end
|
|
601
|
+
|
|
602
|
+
resp.data[:expiration_date] = exp_date
|
|
603
|
+
resp.data[:expiration_rule_id] = exp_rule_id
|
|
604
|
+
|
|
605
|
+
{
|
|
606
|
+
'x-amz-version-id' => :version_id,
|
|
607
|
+
'content-type' => :content_type,
|
|
608
|
+
'etag' => :etag,
|
|
609
|
+
}.each_pair do |header,method|
|
|
610
|
+
resp.data[method] = resp.http_response.header(header)
|
|
611
|
+
end
|
|
612
|
+
|
|
613
|
+
if time = resp.http_response.header('Last-Modified')
|
|
614
|
+
resp.data[:last_modified] = Time.parse(time)
|
|
615
|
+
end
|
|
616
|
+
|
|
617
|
+
resp.data[:content_length] =
|
|
618
|
+
resp.http_response.header('content-length').to_i
|
|
619
|
+
|
|
620
|
+
add_sse_to_response(resp)
|
|
621
|
+
|
|
622
|
+
end
|
|
623
|
+
end
|
|
624
|
+
|
|
625
|
+
# @overload delete_object(options = {})
|
|
626
|
+
# @param [Hash] options
|
|
627
|
+
# @option options [required,String] :bucket_name
|
|
628
|
+
# @option options [required,String] :key
|
|
629
|
+
# @option options [String] :version_id
|
|
630
|
+
# @return [Core::Response]
|
|
631
|
+
object_method(:delete_object, :delete) do
|
|
632
|
+
|
|
633
|
+
configure_request do |req, options|
|
|
634
|
+
super(req, options)
|
|
635
|
+
if options[:version_id]
|
|
636
|
+
req.add_param('versionId', options[:version_id])
|
|
637
|
+
end
|
|
638
|
+
end
|
|
639
|
+
|
|
640
|
+
process_response do |resp|
|
|
641
|
+
resp.data[:version_id] = resp.http_response.header('x-amz-version-id')
|
|
642
|
+
end
|
|
643
|
+
|
|
644
|
+
end
|
|
645
|
+
|
|
646
|
+
# @overload list_objects(options = {})
|
|
647
|
+
# @param [Hash] options
|
|
648
|
+
# @option options [required,String] :bucket_name
|
|
649
|
+
# @option options [String] :delimiter
|
|
650
|
+
# @option options [String] :marker
|
|
651
|
+
# @option options [String] :max_keys
|
|
652
|
+
# @option options [String] :prefix
|
|
653
|
+
# @return [Core::Response]
|
|
654
|
+
bucket_method(:list_objects, :get, XML::ListObjects) do
|
|
655
|
+
configure_request do |req, options|
|
|
656
|
+
super(req, options)
|
|
657
|
+
params = %w(delimiter marker max_keys prefix)
|
|
658
|
+
params.each do |param|
|
|
659
|
+
if options[param.to_sym]
|
|
660
|
+
req.add_param(param.gsub(/_/, '-'), options[param.to_sym])
|
|
661
|
+
end
|
|
662
|
+
end
|
|
663
|
+
end
|
|
664
|
+
end
|
|
665
|
+
|
|
666
|
+
alias_method :get_bucket, :list_objects
|
|
667
|
+
|
|
668
|
+
# @overload initiate_multipart_upload(options = {})
|
|
669
|
+
# @param [Hash] options
|
|
670
|
+
# @option options [required,String] :bucket_name
|
|
671
|
+
# @option options [required,String] :key
|
|
672
|
+
# @option options [Hash] :metadata
|
|
673
|
+
# @option options [Symbol] :acl
|
|
674
|
+
# @option options [String] :cache_control
|
|
675
|
+
# @option options [String] :content_disposition
|
|
676
|
+
# @option options [String] :content_encoding
|
|
677
|
+
# @option options [String] :content_type
|
|
678
|
+
# @option options [String] :storage_class
|
|
679
|
+
# @option options [String] :server_side_encryption
|
|
680
|
+
# @option options [String] :expires
|
|
681
|
+
# @return [Core::Response]
|
|
682
|
+
object_method(:initiate_multipart_upload, :post, 'uploads',
|
|
683
|
+
XML::InitiateMultipartUpload,
|
|
684
|
+
:header_options => {
|
|
685
|
+
:cache_control => 'Cache-Control',
|
|
686
|
+
:content_disposition => 'Content-Disposition',
|
|
687
|
+
:content_encoding => 'Content-Encoding',
|
|
688
|
+
:content_type => 'Content-Type',
|
|
689
|
+
:storage_class => 'x-amz-storage-class',
|
|
690
|
+
:server_side_encryption => 'x-amz-server-side-encryption',
|
|
691
|
+
:expires => 'Expires'
|
|
692
|
+
}) do
|
|
693
|
+
configure_request do |req, options|
|
|
694
|
+
options[:server_side_encryption] =
|
|
695
|
+
options[:server_side_encryption].to_s.upcase if
|
|
696
|
+
options[:server_side_encryption].kind_of?(Symbol)
|
|
697
|
+
super(req, options)
|
|
698
|
+
req.metadata = options[:metadata]
|
|
699
|
+
req.canned_acl = options[:acl]
|
|
700
|
+
req.storage_class = options[:storage_class]
|
|
701
|
+
end
|
|
702
|
+
|
|
703
|
+
process_response do |response|
|
|
704
|
+
add_sse_to_response(response)
|
|
705
|
+
end
|
|
706
|
+
end
|
|
707
|
+
|
|
708
|
+
# @overload list_multipart_uploads(options = {})
|
|
709
|
+
# @param [Hash] options
|
|
710
|
+
# @option options [required,String] :bucket_name
|
|
711
|
+
# @option options [String] :delimiter
|
|
712
|
+
# @option options [String] :key_marker
|
|
713
|
+
# @option options [String] :max_keys
|
|
714
|
+
# @option options [String] :upload_id_marker
|
|
715
|
+
# @option options [String] :max_uploads
|
|
716
|
+
# @option options [String] :prefix
|
|
717
|
+
# @return [Core::Response]
|
|
718
|
+
bucket_method(:list_multipart_uploads,
|
|
719
|
+
:get, 'uploads',
|
|
720
|
+
XML::ListMultipartUploads) do
|
|
721
|
+
configure_request do |req, options|
|
|
722
|
+
super(req, options)
|
|
723
|
+
params = %w(delimiter key_marker max_keys) +
|
|
724
|
+
%w(upload_id_marker max_uploads prefix)
|
|
725
|
+
params.each do |param|
|
|
726
|
+
if options[param.to_sym]
|
|
727
|
+
req.add_param(param.gsub(/_/, '-'), options[param.to_sym])
|
|
728
|
+
end
|
|
729
|
+
end
|
|
730
|
+
end
|
|
731
|
+
end
|
|
732
|
+
|
|
733
|
+
# @overload delete_objects(options = {})
|
|
734
|
+
# @param [Hash] options
|
|
735
|
+
# @option options [required,String] :bucket_name
|
|
736
|
+
# @option options [required,Array<String>] :keys
|
|
737
|
+
# @option options [Boolean] :quiet (true)
|
|
738
|
+
# @return [Core::Response]
|
|
739
|
+
bucket_method(:delete_objects, :post, 'delete', XML::DeleteObjects) do
|
|
740
|
+
configure_request do |req, options|
|
|
741
|
+
|
|
742
|
+
super(req, options)
|
|
743
|
+
|
|
744
|
+
quiet = options.key?(:quiet) ? options[:quiet] : true
|
|
745
|
+
|
|
746
|
+
# previously named this option :objects, since renamed
|
|
747
|
+
keys = options[:objects] || options[:keys]
|
|
748
|
+
|
|
749
|
+
objects = keys.inject('') do |xml,o|
|
|
750
|
+
xml << "<Object><Key>#{o[:key]}</Key>"
|
|
751
|
+
xml << "<VersionId>#{o[:version_id]}</VersionId>" if o[:version_id]
|
|
752
|
+
xml << "</Object>"
|
|
753
|
+
end
|
|
754
|
+
|
|
755
|
+
xml = '<?xml version="1.0" encoding="UTF-8"?>'
|
|
756
|
+
xml << "<Delete><Quiet>#{quiet}</Quiet>#{objects}</Delete>"
|
|
757
|
+
|
|
758
|
+
req.body = xml
|
|
759
|
+
|
|
760
|
+
md5 = Base64.encode64(Digest::MD5.digest(xml)).strip
|
|
761
|
+
|
|
762
|
+
req.headers['content-md5'] = md5
|
|
763
|
+
|
|
764
|
+
end
|
|
765
|
+
end
|
|
766
|
+
|
|
767
|
+
# @overload upload_part(options = {})
|
|
768
|
+
# @param [Hash] options
|
|
769
|
+
# @option options [required,String] :bucket_name
|
|
770
|
+
# @option options [required,String] :key
|
|
771
|
+
# @option options [required,String,Pathname,File,IO] :data
|
|
772
|
+
# The data to upload. This can be provided as a string,
|
|
773
|
+
# a Pathname object, or any object that responds to
|
|
774
|
+
# +#read+ and +#eof?+ (e.g. IO, File, Tempfile, StringIO, etc).
|
|
775
|
+
# @option options [required,String] :upload_id
|
|
776
|
+
# @option options [required,Integer] :part_number
|
|
777
|
+
# @return [Core::Response]
|
|
778
|
+
object_method(:upload_part, :put,
|
|
779
|
+
:header_options => {
|
|
780
|
+
:content_md5 => 'Content-MD5'
|
|
781
|
+
}) do
|
|
782
|
+
configure_request do |request, options, block|
|
|
783
|
+
require_upload_id!(options[:upload_id])
|
|
784
|
+
validate!("part_number", options[:part_number]) do
|
|
785
|
+
"must not be blank" if options[:part_number].to_s.empty?
|
|
786
|
+
end
|
|
787
|
+
super(request, options)
|
|
788
|
+
set_request_data(request, options, block)
|
|
789
|
+
request.add_param('uploadId', options[:upload_id])
|
|
790
|
+
request.add_param('partNumber', options[:part_number])
|
|
791
|
+
end
|
|
792
|
+
|
|
793
|
+
process_response do |response|
|
|
794
|
+
response.data[:etag] = response.http_response.header('ETag')
|
|
795
|
+
if time = response.http_response.header('Last-Modified')
|
|
796
|
+
response.data[:last_modified] = Time.parse(time)
|
|
797
|
+
end
|
|
798
|
+
add_sse_to_response(response)
|
|
799
|
+
end
|
|
800
|
+
|
|
801
|
+
simulate_response do |response|
|
|
802
|
+
response.data[:etag] = 'abc123'
|
|
803
|
+
end
|
|
804
|
+
end
|
|
805
|
+
|
|
806
|
+
# @overload complete_multipart_upload(options = {})
|
|
807
|
+
# @param [Hash] options
|
|
808
|
+
# @option options [required,String] :bucket_name
|
|
809
|
+
# @option options [required,String] :key
|
|
810
|
+
# @option options [required,String] :upload_id
|
|
811
|
+
# @option options [required,Array<String>] :parts
|
|
812
|
+
# @return [Core::Response]
|
|
813
|
+
object_method(:complete_multipart_upload, :post,
|
|
814
|
+
XML::CompleteMultipartUpload) do
|
|
815
|
+
configure_request do |req, options|
|
|
816
|
+
require_upload_id!(options[:upload_id])
|
|
817
|
+
validate_parts!(options[:parts])
|
|
818
|
+
super(req, options)
|
|
819
|
+
req.add_param('uploadId', options[:upload_id])
|
|
820
|
+
parts_xml = options[:parts].map do |part|
|
|
821
|
+
"<Part>"+
|
|
822
|
+
"<PartNumber>#{part[:part_number].to_i}</PartNumber>"+
|
|
823
|
+
"<ETag>#{REXML::Text.normalize(part[:etag].to_s)}</ETag>"+
|
|
824
|
+
"</Part>"
|
|
825
|
+
end.join
|
|
826
|
+
req.body =
|
|
827
|
+
"<CompleteMultipartUpload>#{parts_xml}</CompleteMultipartUpload>"
|
|
828
|
+
end
|
|
829
|
+
|
|
830
|
+
process_response do |response|
|
|
831
|
+
add_sse_to_response(response)
|
|
832
|
+
response.data[:version_id] =
|
|
833
|
+
response.http_response.header('x-amz-version-id')
|
|
834
|
+
end
|
|
835
|
+
|
|
836
|
+
simulate_response do |response|
|
|
837
|
+
response.data[:version_id] = nil
|
|
838
|
+
end
|
|
839
|
+
end
|
|
840
|
+
|
|
841
|
+
# @overload abort_multipart_upload(options = {})
|
|
842
|
+
# @param [Hash] options
|
|
843
|
+
# @option options [required,String] :bucket_name
|
|
844
|
+
# @option options [required,String] :key
|
|
845
|
+
# @option options [required,String] :upload_id
|
|
846
|
+
# @return [Core::Response]
|
|
847
|
+
object_method(:abort_multipart_upload, :delete) do
|
|
848
|
+
configure_request do |req, options|
|
|
849
|
+
require_upload_id!(options[:upload_id])
|
|
850
|
+
super(req, options)
|
|
851
|
+
req.add_param('uploadId', options[:upload_id])
|
|
852
|
+
end
|
|
853
|
+
end
|
|
854
|
+
|
|
855
|
+
# @overload list_parts(options = {})
|
|
856
|
+
# @param [Hash] options
|
|
857
|
+
# @option options [required,String] :bucket_name
|
|
858
|
+
# @option options [required,String] :key
|
|
859
|
+
# @option options [required,String] :upload_id
|
|
860
|
+
# @option options [Integer] :max_parts
|
|
861
|
+
# @option options [Integer] :part_number_marker
|
|
862
|
+
# @return [Core::Response]
|
|
863
|
+
object_method(:list_parts, :get, XML::ListParts) do
|
|
864
|
+
|
|
865
|
+
configure_request do |req, options|
|
|
866
|
+
require_upload_id!(options[:upload_id])
|
|
867
|
+
super(req, options)
|
|
868
|
+
req.add_param('uploadId', options[:upload_id])
|
|
869
|
+
req.add_param('max-parts', options[:max_parts])
|
|
870
|
+
req.add_param('part-number-marker', options[:part_number_marker])
|
|
871
|
+
end
|
|
872
|
+
|
|
873
|
+
end
|
|
874
|
+
|
|
875
|
+
# Copies an object from one key to another.
|
|
876
|
+
# @overload copy_object(options = {})
|
|
877
|
+
# @param [Hash] options
|
|
878
|
+
# @option options [required, String] :bucket_name Name of the bucket
|
|
879
|
+
# to copy a object into.
|
|
880
|
+
# @option options [required, String] :key Where (object key) in the
|
|
881
|
+
# bucket the object should be copied to.
|
|
882
|
+
# @option options [required, String] :copy_source The source
|
|
883
|
+
# bucket name and key, joined by a forward slash ('/').
|
|
884
|
+
# This string must be URL-encoded. Additionally, you must
|
|
885
|
+
# have read access to the source object.
|
|
886
|
+
# @option options [Symbol] :acl
|
|
887
|
+
# @return [Core::Response]
|
|
888
|
+
object_method(:copy_object, :put,
|
|
889
|
+
:header_options => {
|
|
890
|
+
:copy_source => 'x-amz-copy-source',
|
|
891
|
+
:cache_control => 'Cache-Control',
|
|
892
|
+
:metadata_directive => 'x-amz-metadata-directive',
|
|
893
|
+
:storage_class => 'x-amz-storage-class',
|
|
894
|
+
:server_side_encryption => 'x-amz-server-side-encryption',
|
|
895
|
+
:content_type => 'Content-Type',
|
|
896
|
+
}) do
|
|
897
|
+
|
|
898
|
+
configure_request do |req, options|
|
|
899
|
+
# TODO : validate metadata directive COPY / REPLACE
|
|
900
|
+
# TODO : validate storage class STANDARD / REDUCED_REDUNDANCY
|
|
901
|
+
# TODO : add validations for storage class in other places used
|
|
902
|
+
validate!(:copy_source, options[:copy_source]) do
|
|
903
|
+
"may not be blank" if options[:copy_source].to_s.empty?
|
|
904
|
+
end
|
|
905
|
+
options = options.merge(:copy_source => escape_path(options[:copy_source]))
|
|
906
|
+
options[:server_side_encryption] =
|
|
907
|
+
options[:server_side_encryption].to_s.upcase if
|
|
908
|
+
options[:server_side_encryption].kind_of?(Symbol)
|
|
909
|
+
super(req, options)
|
|
910
|
+
req.canned_acl = options[:acl]
|
|
911
|
+
req.metadata = options[:metadata]
|
|
912
|
+
req.storage_class = options[:storage_class]
|
|
913
|
+
if options[:version_id]
|
|
914
|
+
req.headers['x-amz-copy-source'] += "?versionId=#{options[:version_id]}"
|
|
915
|
+
end
|
|
916
|
+
end
|
|
917
|
+
|
|
918
|
+
process_response do |response|
|
|
919
|
+
response.data[:version_id] =
|
|
920
|
+
response.http_response.header('x-amz-version-id')
|
|
921
|
+
response.data[:etag] = response.http_response.header('ETag')
|
|
922
|
+
if time = response.http_response.header('Last-Modified')
|
|
923
|
+
response.data[:last_modified] = Time.parse(time)
|
|
924
|
+
end
|
|
925
|
+
add_sse_to_response(response)
|
|
926
|
+
end
|
|
927
|
+
|
|
928
|
+
end
|
|
929
|
+
|
|
930
|
+
protected
|
|
931
|
+
|
|
932
|
+
def extract_error_details response
|
|
933
|
+
if
|
|
934
|
+
(response.http_response.status >= 300 ||
|
|
935
|
+
response.request_type == :complete_multipart_upload) and
|
|
936
|
+
body = response.http_response.body and
|
|
937
|
+
error = Core::XML::Parser.parse(body) and
|
|
938
|
+
error[:code]
|
|
939
|
+
then
|
|
940
|
+
[error[:code], error[:message]]
|
|
941
|
+
end
|
|
942
|
+
end
|
|
943
|
+
|
|
944
|
+
# There are a few of s3 requests that can generate empty bodies and
|
|
945
|
+
# yet still be errors. These return empty bodies to comply with the
|
|
946
|
+
# HTTP spec. We have to detect these errors specially.
|
|
947
|
+
def populate_error resp
|
|
948
|
+
code = resp.http_response.status
|
|
949
|
+
if EMPTY_BODY_ERRORS.include?(code) and resp.http_response.body.nil?
|
|
950
|
+
error_class = EMPTY_BODY_ERRORS[code]
|
|
951
|
+
resp.error = error_class.new(resp.http_request, resp.http_response)
|
|
952
|
+
else
|
|
953
|
+
super
|
|
954
|
+
end
|
|
955
|
+
end
|
|
956
|
+
|
|
957
|
+
def should_retry? response
|
|
958
|
+
super or
|
|
959
|
+
response.request_type == :complete_multipart_upload &&
|
|
960
|
+
extract_error_details(response)
|
|
961
|
+
# complete multipart upload can return an error inside a
|
|
962
|
+
# 200 level response -- this forces us to parse the
|
|
963
|
+
# response for errors every time
|
|
964
|
+
end
|
|
965
|
+
|
|
966
|
+
def set_request_data request, options, block
|
|
967
|
+
request.body_stream = data_stream_from(options, &block)
|
|
968
|
+
request.headers['Content-Length'] = content_length_from(options)
|
|
969
|
+
end
|
|
970
|
+
|
|
971
|
+
def new_request
|
|
972
|
+
S3::Request.new
|
|
973
|
+
end
|
|
974
|
+
|
|
975
|
+
def add_sse_to_response response
|
|
976
|
+
if sse = response.http_response.header('x-amz-server-side-encryption')
|
|
977
|
+
sse = sse.downcase.to_sym
|
|
978
|
+
end
|
|
979
|
+
response.data[:server_side_encryption] = sse
|
|
980
|
+
end
|
|
981
|
+
|
|
982
|
+
module Validators
|
|
983
|
+
|
|
984
|
+
# @return [Boolean] Returns true if the given bucket name is valid.
|
|
985
|
+
def valid_bucket_name?(bucket_name)
|
|
986
|
+
validate_bucket_name!(bucket_name) rescue false
|
|
987
|
+
end
|
|
988
|
+
|
|
989
|
+
# Returns true if the given +bucket_name+ is DNS compatible.
|
|
990
|
+
#
|
|
991
|
+
# DNS compatible bucket names may be accessed like:
|
|
992
|
+
#
|
|
993
|
+
# http://dns.compat.bucket.name.s3.amazonaws.com/
|
|
994
|
+
#
|
|
995
|
+
# Whereas non-dns compatible bucket names must place the bucket
|
|
996
|
+
# name in the url path, like:
|
|
997
|
+
#
|
|
998
|
+
# http://s3.amazonaws.com/dns_incompat_bucket_name/
|
|
999
|
+
#
|
|
1000
|
+
# @return [Boolean] Returns true if the given bucket name may be
|
|
1001
|
+
# is dns compatible.
|
|
1002
|
+
# this bucket n
|
|
1003
|
+
#
|
|
1004
|
+
def dns_compatible_bucket_name?(bucket_name)
|
|
1005
|
+
return false if
|
|
1006
|
+
!valid_bucket_name?(bucket_name) or
|
|
1007
|
+
|
|
1008
|
+
# Bucket names should not contain underscores (_)
|
|
1009
|
+
bucket_name["_"] or
|
|
1010
|
+
|
|
1011
|
+
# Bucket names should be between 3 and 63 characters long
|
|
1012
|
+
bucket_name.size > 63 or
|
|
1013
|
+
|
|
1014
|
+
# Bucket names should not end with a dash
|
|
1015
|
+
bucket_name[-1,1] == '-' or
|
|
1016
|
+
|
|
1017
|
+
# Bucket names cannot contain two, adjacent periods
|
|
1018
|
+
bucket_name['..'] or
|
|
1019
|
+
|
|
1020
|
+
# Bucket names cannot contain dashes next to periods
|
|
1021
|
+
# (e.g., "my-.bucket.com" and "my.-bucket" are invalid)
|
|
1022
|
+
(bucket_name['-.'] || bucket_name['.-'])
|
|
1023
|
+
|
|
1024
|
+
true
|
|
1025
|
+
end
|
|
1026
|
+
|
|
1027
|
+
# Returns true if the bucket name must be used in the request
|
|
1028
|
+
# path instead of as a sub-domain when making requests against
|
|
1029
|
+
# S3.
|
|
1030
|
+
#
|
|
1031
|
+
# This can be an issue if the bucket name is DNS compatible but
|
|
1032
|
+
# contains '.' (periods). These cause the SSL certificate to
|
|
1033
|
+
# become invalid when making authenticated requets over SSL to the
|
|
1034
|
+
# bucket name. The solution is to send this as a path argument
|
|
1035
|
+
# instead.
|
|
1036
|
+
#
|
|
1037
|
+
# @return [Boolean] Returns true if the bucket name should be used
|
|
1038
|
+
# as a path segement instead of dns prefix when making requests
|
|
1039
|
+
# against s3.
|
|
1040
|
+
#
|
|
1041
|
+
def path_style_bucket_name? bucket_name
|
|
1042
|
+
if dns_compatible_bucket_name?(bucket_name)
|
|
1043
|
+
bucket_name =~ /\./ ? true : false
|
|
1044
|
+
else
|
|
1045
|
+
true
|
|
1046
|
+
end
|
|
1047
|
+
end
|
|
1048
|
+
|
|
1049
|
+
def validate! name, value, &block
|
|
1050
|
+
if error_msg = yield
|
|
1051
|
+
raise ArgumentError, "#{name} #{error_msg}"
|
|
1052
|
+
end
|
|
1053
|
+
value
|
|
1054
|
+
end
|
|
1055
|
+
|
|
1056
|
+
def validate_key!(key)
|
|
1057
|
+
validate!('key', key) do
|
|
1058
|
+
case
|
|
1059
|
+
when key.nil? || key == ''
|
|
1060
|
+
'may not be blank'
|
|
1061
|
+
end
|
|
1062
|
+
end
|
|
1063
|
+
end
|
|
1064
|
+
|
|
1065
|
+
def require_bucket_name! bucket_name
|
|
1066
|
+
if [nil, ''].include?(bucket_name)
|
|
1067
|
+
raise ArgumentError, "bucket_name may not be blank"
|
|
1068
|
+
end
|
|
1069
|
+
end
|
|
1070
|
+
|
|
1071
|
+
# Returns true if the given bucket name is valid. If the name
|
|
1072
|
+
# is invalid, an ArgumentError is raised.
|
|
1073
|
+
def validate_bucket_name!(bucket_name)
|
|
1074
|
+
validate!('bucket_name', bucket_name) do
|
|
1075
|
+
case
|
|
1076
|
+
when bucket_name.nil? || bucket_name == ''
|
|
1077
|
+
'may not be blank'
|
|
1078
|
+
when bucket_name !~ /^[a-z0-9._\-]+$/
|
|
1079
|
+
'may only contain lowercase letters, numbers, periods (.), ' +
|
|
1080
|
+
'underscores (_), and dashes (-)'
|
|
1081
|
+
when bucket_name !~ /^[a-z0-9]/
|
|
1082
|
+
'must start with a letter or a number'
|
|
1083
|
+
when !(3..255).include?(bucket_name.size)
|
|
1084
|
+
'must be between 3 and 255 characters long'
|
|
1085
|
+
when bucket_name =~ /(\d+\.){3}\d+/
|
|
1086
|
+
'must not be formatted like an IP address (e.g., 192.168.5.4)'
|
|
1087
|
+
when bucket_name =~ /\n/
|
|
1088
|
+
'must not contain a newline character'
|
|
1089
|
+
end
|
|
1090
|
+
end
|
|
1091
|
+
end
|
|
1092
|
+
|
|
1093
|
+
def require_policy!(policy)
|
|
1094
|
+
validate!('policy', policy) do
|
|
1095
|
+
case
|
|
1096
|
+
when policy.nil? || policy == ''
|
|
1097
|
+
'may not be blank'
|
|
1098
|
+
else
|
|
1099
|
+
json_validation_message(policy)
|
|
1100
|
+
end
|
|
1101
|
+
end
|
|
1102
|
+
end
|
|
1103
|
+
|
|
1104
|
+
def require_acl!(acl)
|
|
1105
|
+
validate!('acl', acl) do
|
|
1106
|
+
case
|
|
1107
|
+
when acl.kind_of?(Hash)
|
|
1108
|
+
AccessControlList.new(acl).validate!
|
|
1109
|
+
nil
|
|
1110
|
+
when !acl.respond_to?(:to_str) && !acl.respond_to?(:to_xml)
|
|
1111
|
+
"must support to_xml: #{acl.inspect}"
|
|
1112
|
+
when acl.nil? || acl == ''
|
|
1113
|
+
'may not be blank'
|
|
1114
|
+
else
|
|
1115
|
+
xml_validation_message(acl)
|
|
1116
|
+
end
|
|
1117
|
+
end
|
|
1118
|
+
end
|
|
1119
|
+
|
|
1120
|
+
def require_upload_id!(upload_id)
|
|
1121
|
+
validate!("upload_id", upload_id) do
|
|
1122
|
+
"must not be blank" if upload_id.to_s.empty?
|
|
1123
|
+
end
|
|
1124
|
+
end
|
|
1125
|
+
|
|
1126
|
+
def validate_parts!(parts)
|
|
1127
|
+
validate!("parts", parts) do
|
|
1128
|
+
if !parts.kind_of?(Array)
|
|
1129
|
+
"must not be blank"
|
|
1130
|
+
elsif parts.empty?
|
|
1131
|
+
"must contain at least one entry"
|
|
1132
|
+
elsif !parts.all? { |p| p.kind_of?(Hash) }
|
|
1133
|
+
"must be an array of hashes"
|
|
1134
|
+
elsif !parts.all? { |p| p[:part_number] }
|
|
1135
|
+
"must contain part_number for each part"
|
|
1136
|
+
elsif !parts.all? { |p| p[:etag] }
|
|
1137
|
+
"must contain etag for each part"
|
|
1138
|
+
elsif parts.any? { |p| p[:part_number].to_i < 1 }
|
|
1139
|
+
"must not have part numbers less than 1"
|
|
1140
|
+
end
|
|
1141
|
+
end
|
|
1142
|
+
end
|
|
1143
|
+
|
|
1144
|
+
def json_validation_message(obj)
|
|
1145
|
+
if obj.respond_to?(:to_str)
|
|
1146
|
+
obj = obj.to_str
|
|
1147
|
+
elsif obj.respond_to?(:to_json)
|
|
1148
|
+
obj = obj.to_json
|
|
1149
|
+
end
|
|
1150
|
+
|
|
1151
|
+
error = nil
|
|
1152
|
+
begin
|
|
1153
|
+
JSON.parse(obj)
|
|
1154
|
+
rescue => e
|
|
1155
|
+
error = e
|
|
1156
|
+
end
|
|
1157
|
+
"contains invalid JSON: #{error}" if error
|
|
1158
|
+
end
|
|
1159
|
+
|
|
1160
|
+
def xml_validation_message(obj)
|
|
1161
|
+
if obj.respond_to?(:to_str)
|
|
1162
|
+
obj = obj.to_str
|
|
1163
|
+
elsif obj.respond_to?(:to_xml)
|
|
1164
|
+
obj = obj.to_xml
|
|
1165
|
+
end
|
|
1166
|
+
|
|
1167
|
+
error = nil
|
|
1168
|
+
begin
|
|
1169
|
+
REXML::Document.new(obj)
|
|
1170
|
+
rescue => e
|
|
1171
|
+
error = e
|
|
1172
|
+
end
|
|
1173
|
+
"contains invalid XML: #{error}" if error
|
|
1174
|
+
end
|
|
1175
|
+
|
|
1176
|
+
end
|
|
1177
|
+
|
|
1178
|
+
include Validators
|
|
1179
|
+
extend Validators
|
|
1180
|
+
|
|
1181
|
+
end
|
|
1182
|
+
|
|
1183
|
+
end
|
|
1184
|
+
end
|