aws-sdk-v1-reinteractive 1.67.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (569) hide show
  1. checksums.yaml +7 -0
  2. data/.yardopts +9 -0
  3. data/LICENSE.txt +12 -0
  4. data/README.md +364 -0
  5. data/bin/aws-rb +179 -0
  6. data/ca-bundle.crt +3554 -0
  7. data/endpoints.json +1838 -0
  8. data/lib/aws-sdk-v1.rb +2 -0
  9. data/lib/aws.rb +14 -0
  10. data/lib/aws/api_config/AutoScaling-2011-01-01.yml +1083 -0
  11. data/lib/aws/api_config/CloudFormation-2010-05-15.yml +372 -0
  12. data/lib/aws/api_config/CloudFront-2013-05-12.yml +2448 -0
  13. data/lib/aws/api_config/CloudFront-2013-08-26.yml +2599 -0
  14. data/lib/aws/api_config/CloudFront-2013-09-27.yml +2765 -0
  15. data/lib/aws/api_config/CloudFront-2013-11-11.yml +2886 -0
  16. data/lib/aws/api_config/CloudFront-2013-11-22.yml +2918 -0
  17. data/lib/aws/api_config/CloudFront-2014-01-31.yml +2934 -0
  18. data/lib/aws/api_config/CloudFront-2014-05-31.yml +3100 -0
  19. data/lib/aws/api_config/CloudFront-2014-10-21.yml +3290 -0
  20. data/lib/aws/api_config/CloudFront-2014-11-06.yml +3547 -0
  21. data/lib/aws/api_config/CloudSearch-2011-02-01.yml +681 -0
  22. data/lib/aws/api_config/CloudSearch-2013-01-01.yml +1184 -0
  23. data/lib/aws/api_config/CloudTrail-2013-11-01.yml +130 -0
  24. data/lib/aws/api_config/CloudWatch-2010-08-01.yml +433 -0
  25. data/lib/aws/api_config/DataPipeline-2012-10-29.yml +422 -0
  26. data/lib/aws/api_config/DirectConnect-2012-10-25.yml +735 -0
  27. data/lib/aws/api_config/DynamoDB-2011-12-05.yml +1168 -0
  28. data/lib/aws/api_config/DynamoDB-2012-08-10.yml +2105 -0
  29. data/lib/aws/api_config/EC2-2013-08-15.yml +4708 -0
  30. data/lib/aws/api_config/EC2-2013-10-01.yml +4726 -0
  31. data/lib/aws/api_config/EC2-2013-10-15.yml +4651 -0
  32. data/lib/aws/api_config/EC2-2014-02-01.yml +4755 -0
  33. data/lib/aws/api_config/EC2-2014-05-01.yml +4812 -0
  34. data/lib/aws/api_config/EC2-2014-09-01.yml +4826 -0
  35. data/lib/aws/api_config/EC2-2014-10-01.yml +4969 -0
  36. data/lib/aws/api_config/ELB-2012-06-01.yml +785 -0
  37. data/lib/aws/api_config/EMR-2009-03-31.yml +972 -0
  38. data/lib/aws/api_config/ElastiCache-2013-06-15.yml +1188 -0
  39. data/lib/aws/api_config/ElastiCache-2014-03-24.yml +1375 -0
  40. data/lib/aws/api_config/ElastiCache-2014-07-15.yml +1385 -0
  41. data/lib/aws/api_config/ElastiCache-2014-09-30.yml +1426 -0
  42. data/lib/aws/api_config/ElasticBeanstalk-2010-12-01.yml +854 -0
  43. data/lib/aws/api_config/ElasticTranscoder-2012-09-25.yml +4179 -0
  44. data/lib/aws/api_config/Glacier-2012-06-01.yml +649 -0
  45. data/lib/aws/api_config/IAM-2010-05-08.yml +1912 -0
  46. data/lib/aws/api_config/ImportExport-2010-06-01.yml +109 -0
  47. data/lib/aws/api_config/Kinesis-2013-12-02.yml +275 -0
  48. data/lib/aws/api_config/OpsWorks-2013-02-18.yml +2324 -0
  49. data/lib/aws/api_config/RDS-2013-05-15.yml +2464 -0
  50. data/lib/aws/api_config/RDS-2013-09-09.yml +2640 -0
  51. data/lib/aws/api_config/RDS-2014-09-01.yml +2796 -0
  52. data/lib/aws/api_config/Redshift-2012-12-01.yml +2577 -0
  53. data/lib/aws/api_config/Route53-2012-12-12.yml +547 -0
  54. data/lib/aws/api_config/Route53-2013-04-01.yml +1093 -0
  55. data/lib/aws/api_config/SNS-2010-03-31.yml +448 -0
  56. data/lib/aws/api_config/SQS-2012-11-05.yml +404 -0
  57. data/lib/aws/api_config/STS-2011-06-15.yml +151 -0
  58. data/lib/aws/api_config/SimpleDB-2009-04-15.yml +306 -0
  59. data/lib/aws/api_config/SimpleEmailService-2010-12-01.yml +346 -0
  60. data/lib/aws/api_config/SimpleWorkflow-2012-01-25.yml +2426 -0
  61. data/lib/aws/api_config/StorageGateway-2012-06-30.yml +748 -0
  62. data/lib/aws/api_config/StorageGateway-2013-06-30.yml +1025 -0
  63. data/lib/aws/api_config/Support-2013-04-15.yml +489 -0
  64. data/lib/aws/auto_scaling.rb +163 -0
  65. data/lib/aws/auto_scaling/activity.rb +102 -0
  66. data/lib/aws/auto_scaling/activity_collection.rb +81 -0
  67. data/lib/aws/auto_scaling/client.rb +48 -0
  68. data/lib/aws/auto_scaling/config.rb +18 -0
  69. data/lib/aws/auto_scaling/errors.rb +22 -0
  70. data/lib/aws/auto_scaling/group.rb +421 -0
  71. data/lib/aws/auto_scaling/group_collection.rb +96 -0
  72. data/lib/aws/auto_scaling/group_options.rb +155 -0
  73. data/lib/aws/auto_scaling/instance.rb +192 -0
  74. data/lib/aws/auto_scaling/instance_collection.rb +63 -0
  75. data/lib/aws/auto_scaling/launch_configuration.rb +179 -0
  76. data/lib/aws/auto_scaling/launch_configuration_collection.rb +177 -0
  77. data/lib/aws/auto_scaling/notification_configuration.rb +89 -0
  78. data/lib/aws/auto_scaling/notification_configuration_collection.rb +183 -0
  79. data/lib/aws/auto_scaling/scaling_policy.rb +142 -0
  80. data/lib/aws/auto_scaling/scaling_policy_collection.rb +72 -0
  81. data/lib/aws/auto_scaling/scaling_policy_options.rb +65 -0
  82. data/lib/aws/auto_scaling/scheduled_action.rb +141 -0
  83. data/lib/aws/auto_scaling/scheduled_action_collection.rb +202 -0
  84. data/lib/aws/auto_scaling/tag.rb +59 -0
  85. data/lib/aws/auto_scaling/tag_collection.rb +114 -0
  86. data/lib/aws/cloud_formation.rb +272 -0
  87. data/lib/aws/cloud_formation/client.rb +48 -0
  88. data/lib/aws/cloud_formation/config.rb +18 -0
  89. data/lib/aws/cloud_formation/errors.rb +22 -0
  90. data/lib/aws/cloud_formation/stack.rb +266 -0
  91. data/lib/aws/cloud_formation/stack_collection.rb +232 -0
  92. data/lib/aws/cloud_formation/stack_event.rb +73 -0
  93. data/lib/aws/cloud_formation/stack_event_collection.rb +47 -0
  94. data/lib/aws/cloud_formation/stack_options.rb +72 -0
  95. data/lib/aws/cloud_formation/stack_output.rb +53 -0
  96. data/lib/aws/cloud_formation/stack_resource.rb +117 -0
  97. data/lib/aws/cloud_formation/stack_resource_collection.rb +83 -0
  98. data/lib/aws/cloud_formation/stack_resource_summary_collection.rb +64 -0
  99. data/lib/aws/cloud_formation/stack_summary_collection.rb +123 -0
  100. data/lib/aws/cloud_front.rb +72 -0
  101. data/lib/aws/cloud_front/client.rb +65 -0
  102. data/lib/aws/cloud_front/config.rb +18 -0
  103. data/lib/aws/cloud_front/errors.rb +22 -0
  104. data/lib/aws/cloud_search.rb +73 -0
  105. data/lib/aws/cloud_search/client.rb +40 -0
  106. data/lib/aws/cloud_search/config.rb +18 -0
  107. data/lib/aws/cloud_search/errors.rb +22 -0
  108. data/lib/aws/cloud_trail.rb +72 -0
  109. data/lib/aws/cloud_trail/client.rb +35 -0
  110. data/lib/aws/cloud_trail/config.rb +18 -0
  111. data/lib/aws/cloud_trail/errors.rb +22 -0
  112. data/lib/aws/cloud_watch.rb +118 -0
  113. data/lib/aws/cloud_watch/alarm.rb +293 -0
  114. data/lib/aws/cloud_watch/alarm_collection.rb +153 -0
  115. data/lib/aws/cloud_watch/alarm_history_item.rb +50 -0
  116. data/lib/aws/cloud_watch/alarm_history_item_collection.rb +84 -0
  117. data/lib/aws/cloud_watch/client.rb +40 -0
  118. data/lib/aws/cloud_watch/config.rb +18 -0
  119. data/lib/aws/cloud_watch/errors.rb +22 -0
  120. data/lib/aws/cloud_watch/metric.rb +135 -0
  121. data/lib/aws/cloud_watch/metric_alarm_collection.rb +160 -0
  122. data/lib/aws/cloud_watch/metric_collection.rb +129 -0
  123. data/lib/aws/cloud_watch/metric_statistics.rb +69 -0
  124. data/lib/aws/core.rb +698 -0
  125. data/lib/aws/core/async_handle.rb +90 -0
  126. data/lib/aws/core/cacheable.rb +77 -0
  127. data/lib/aws/core/client.rb +787 -0
  128. data/lib/aws/core/collection.rb +263 -0
  129. data/lib/aws/core/collection/simple.rb +82 -0
  130. data/lib/aws/core/collection/with_limit_and_next_token.rb +71 -0
  131. data/lib/aws/core/collection/with_next_token.rb +97 -0
  132. data/lib/aws/core/configuration.rb +528 -0
  133. data/lib/aws/core/credential_providers.rb +662 -0
  134. data/lib/aws/core/data.rb +252 -0
  135. data/lib/aws/core/deprecations.rb +84 -0
  136. data/lib/aws/core/endpoints.rb +37 -0
  137. data/lib/aws/core/http/connection_pool.rb +375 -0
  138. data/lib/aws/core/http/curb_handler.rb +151 -0
  139. data/lib/aws/core/http/handler.rb +89 -0
  140. data/lib/aws/core/http/net_http_handler.rb +145 -0
  141. data/lib/aws/core/http/patch.rb +98 -0
  142. data/lib/aws/core/http/request.rb +259 -0
  143. data/lib/aws/core/http/response.rb +81 -0
  144. data/lib/aws/core/indifferent_hash.rb +88 -0
  145. data/lib/aws/core/inflection.rb +56 -0
  146. data/lib/aws/core/ini_parser.rb +42 -0
  147. data/lib/aws/core/json_client.rb +47 -0
  148. data/lib/aws/core/json_parser.rb +76 -0
  149. data/lib/aws/core/json_request_builder.rb +35 -0
  150. data/lib/aws/core/json_response_parser.rb +79 -0
  151. data/lib/aws/core/lazy_error_classes.rb +108 -0
  152. data/lib/aws/core/log_formatter.rb +428 -0
  153. data/lib/aws/core/managed_file.rb +32 -0
  154. data/lib/aws/core/meta_utils.rb +45 -0
  155. data/lib/aws/core/model.rb +62 -0
  156. data/lib/aws/core/naming.rb +30 -0
  157. data/lib/aws/core/option_grammar.rb +738 -0
  158. data/lib/aws/core/options/json_serializer.rb +82 -0
  159. data/lib/aws/core/options/validator.rb +155 -0
  160. data/lib/aws/core/options/xml_serializer.rb +118 -0
  161. data/lib/aws/core/page_result.rb +75 -0
  162. data/lib/aws/core/policy.rb +941 -0
  163. data/lib/aws/core/query_client.rb +41 -0
  164. data/lib/aws/core/query_error_parser.rb +24 -0
  165. data/lib/aws/core/query_request_builder.rb +47 -0
  166. data/lib/aws/core/query_response_parser.rb +35 -0
  167. data/lib/aws/core/region.rb +85 -0
  168. data/lib/aws/core/region_collection.rb +80 -0
  169. data/lib/aws/core/resource.rb +413 -0
  170. data/lib/aws/core/resource_cache.rb +40 -0
  171. data/lib/aws/core/response.rb +215 -0
  172. data/lib/aws/core/response_cache.rb +50 -0
  173. data/lib/aws/core/rest_error_parser.rb +24 -0
  174. data/lib/aws/core/rest_json_client.rb +40 -0
  175. data/lib/aws/core/rest_request_builder.rb +154 -0
  176. data/lib/aws/core/rest_response_parser.rb +66 -0
  177. data/lib/aws/core/rest_xml_client.rb +47 -0
  178. data/lib/aws/core/service_interface.rb +83 -0
  179. data/lib/aws/core/signers/base.rb +46 -0
  180. data/lib/aws/core/signers/cloud_front.rb +56 -0
  181. data/lib/aws/core/signers/s3.rb +159 -0
  182. data/lib/aws/core/signers/version_2.rb +72 -0
  183. data/lib/aws/core/signers/version_3.rb +86 -0
  184. data/lib/aws/core/signers/version_3_https.rb +61 -0
  185. data/lib/aws/core/signers/version_4.rb +228 -0
  186. data/lib/aws/core/signers/version_4/chunk_signed_stream.rb +191 -0
  187. data/lib/aws/core/uri_escape.rb +44 -0
  188. data/lib/aws/core/xml/frame.rb +246 -0
  189. data/lib/aws/core/xml/frame_stack.rb +85 -0
  190. data/lib/aws/core/xml/grammar.rb +307 -0
  191. data/lib/aws/core/xml/parser.rb +70 -0
  192. data/lib/aws/core/xml/root_frame.rb +65 -0
  193. data/lib/aws/core/xml/sax_handlers/libxml.rb +47 -0
  194. data/lib/aws/core/xml/sax_handlers/nokogiri.rb +56 -0
  195. data/lib/aws/core/xml/sax_handlers/ox.rb +41 -0
  196. data/lib/aws/core/xml/sax_handlers/rexml.rb +47 -0
  197. data/lib/aws/core/xml/stub.rb +123 -0
  198. data/lib/aws/data_pipeline.rb +72 -0
  199. data/lib/aws/data_pipeline/client.rb +36 -0
  200. data/lib/aws/data_pipeline/config.rb +18 -0
  201. data/lib/aws/data_pipeline/errors.rb +20 -0
  202. data/lib/aws/direct_connect.rb +73 -0
  203. data/lib/aws/direct_connect/client.rb +36 -0
  204. data/lib/aws/direct_connect/config.rb +18 -0
  205. data/lib/aws/direct_connect/errors.rb +22 -0
  206. data/lib/aws/dynamo_db.rb +230 -0
  207. data/lib/aws/dynamo_db/attribute_collection.rb +456 -0
  208. data/lib/aws/dynamo_db/batch_get.rb +213 -0
  209. data/lib/aws/dynamo_db/batch_write.rb +254 -0
  210. data/lib/aws/dynamo_db/binary.rb +35 -0
  211. data/lib/aws/dynamo_db/client.rb +129 -0
  212. data/lib/aws/dynamo_db/client/v20111205.rb +1266 -0
  213. data/lib/aws/dynamo_db/client/v20120810.rb +1409 -0
  214. data/lib/aws/dynamo_db/client_v2.rb +44 -0
  215. data/lib/aws/dynamo_db/config.rb +24 -0
  216. data/lib/aws/dynamo_db/errors.rb +20 -0
  217. data/lib/aws/dynamo_db/expectations.rb +40 -0
  218. data/lib/aws/dynamo_db/item.rb +133 -0
  219. data/lib/aws/dynamo_db/item_collection.rb +856 -0
  220. data/lib/aws/dynamo_db/item_data.rb +31 -0
  221. data/lib/aws/dynamo_db/keys.rb +41 -0
  222. data/lib/aws/dynamo_db/primary_key_element.rb +48 -0
  223. data/lib/aws/dynamo_db/resource.rb +33 -0
  224. data/lib/aws/dynamo_db/table.rb +492 -0
  225. data/lib/aws/dynamo_db/table_collection.rb +165 -0
  226. data/lib/aws/dynamo_db/types.rb +111 -0
  227. data/lib/aws/ec2.rb +428 -0
  228. data/lib/aws/ec2/attachment.rb +135 -0
  229. data/lib/aws/ec2/attachment_collection.rb +54 -0
  230. data/lib/aws/ec2/availability_zone.rb +86 -0
  231. data/lib/aws/ec2/availability_zone_collection.rb +43 -0
  232. data/lib/aws/ec2/block_device_mappings.rb +53 -0
  233. data/lib/aws/ec2/client.rb +162 -0
  234. data/lib/aws/ec2/collection.rb +36 -0
  235. data/lib/aws/ec2/config.rb +21 -0
  236. data/lib/aws/ec2/customer_gateway.rb +90 -0
  237. data/lib/aws/ec2/customer_gateway_collection.rb +73 -0
  238. data/lib/aws/ec2/dhcp_options.rb +106 -0
  239. data/lib/aws/ec2/dhcp_options_collection.rb +87 -0
  240. data/lib/aws/ec2/elastic_ip.rb +209 -0
  241. data/lib/aws/ec2/elastic_ip_collection.rb +93 -0
  242. data/lib/aws/ec2/errors.rb +32 -0
  243. data/lib/aws/ec2/export_task.rb +120 -0
  244. data/lib/aws/ec2/export_task_collection.rb +67 -0
  245. data/lib/aws/ec2/filtered_collection.rb +87 -0
  246. data/lib/aws/ec2/has_permissions.rb +44 -0
  247. data/lib/aws/ec2/image.rb +274 -0
  248. data/lib/aws/ec2/image_collection.rb +219 -0
  249. data/lib/aws/ec2/instance.rb +803 -0
  250. data/lib/aws/ec2/instance_collection.rb +403 -0
  251. data/lib/aws/ec2/internet_gateway.rb +122 -0
  252. data/lib/aws/ec2/internet_gateway/attachment.rb +78 -0
  253. data/lib/aws/ec2/internet_gateway_collection.rb +54 -0
  254. data/lib/aws/ec2/key_pair.rb +82 -0
  255. data/lib/aws/ec2/key_pair_collection.rb +99 -0
  256. data/lib/aws/ec2/network_acl.rb +256 -0
  257. data/lib/aws/ec2/network_acl/association.rb +56 -0
  258. data/lib/aws/ec2/network_acl/entry.rb +147 -0
  259. data/lib/aws/ec2/network_acl_collection.rb +64 -0
  260. data/lib/aws/ec2/network_interface.rb +237 -0
  261. data/lib/aws/ec2/network_interface/attachment.rb +100 -0
  262. data/lib/aws/ec2/network_interface_collection.rb +103 -0
  263. data/lib/aws/ec2/permission_collection.rb +174 -0
  264. data/lib/aws/ec2/region.rb +106 -0
  265. data/lib/aws/ec2/region_collection.rb +51 -0
  266. data/lib/aws/ec2/reserved_instances.rb +57 -0
  267. data/lib/aws/ec2/reserved_instances_collection.rb +40 -0
  268. data/lib/aws/ec2/reserved_instances_offering.rb +60 -0
  269. data/lib/aws/ec2/reserved_instances_offering_collection.rb +45 -0
  270. data/lib/aws/ec2/resource.rb +161 -0
  271. data/lib/aws/ec2/resource_tag_collection.rb +211 -0
  272. data/lib/aws/ec2/route_table.rb +210 -0
  273. data/lib/aws/ec2/route_table/association.rb +119 -0
  274. data/lib/aws/ec2/route_table/route.rb +121 -0
  275. data/lib/aws/ec2/route_table_collection.rb +72 -0
  276. data/lib/aws/ec2/security_group.rb +482 -0
  277. data/lib/aws/ec2/security_group/ip_permission.rb +135 -0
  278. data/lib/aws/ec2/security_group/ip_permission_collection.rb +82 -0
  279. data/lib/aws/ec2/security_group_collection.rb +133 -0
  280. data/lib/aws/ec2/snapshot.rb +143 -0
  281. data/lib/aws/ec2/snapshot_collection.rb +131 -0
  282. data/lib/aws/ec2/subnet.rb +161 -0
  283. data/lib/aws/ec2/subnet_collection.rb +119 -0
  284. data/lib/aws/ec2/tag.rb +81 -0
  285. data/lib/aws/ec2/tag_collection.rb +107 -0
  286. data/lib/aws/ec2/tagged_collection.rb +67 -0
  287. data/lib/aws/ec2/tagged_item.rb +85 -0
  288. data/lib/aws/ec2/volume.rb +185 -0
  289. data/lib/aws/ec2/volume_collection.rb +102 -0
  290. data/lib/aws/ec2/vpc.rb +224 -0
  291. data/lib/aws/ec2/vpc_collection.rb +70 -0
  292. data/lib/aws/ec2/vpc_peering_connection.rb +47 -0
  293. data/lib/aws/ec2/vpc_peering_connection_collection.rb +57 -0
  294. data/lib/aws/ec2/vpn_connection.rb +99 -0
  295. data/lib/aws/ec2/vpn_connection/telemetry.rb +49 -0
  296. data/lib/aws/ec2/vpn_connection_collection.rb +96 -0
  297. data/lib/aws/ec2/vpn_gateway.rb +123 -0
  298. data/lib/aws/ec2/vpn_gateway/attachment.rb +45 -0
  299. data/lib/aws/ec2/vpn_gateway_collection.rb +77 -0
  300. data/lib/aws/elastic_beanstalk.rb +49 -0
  301. data/lib/aws/elastic_beanstalk/client.rb +36 -0
  302. data/lib/aws/elastic_beanstalk/config.rb +18 -0
  303. data/lib/aws/elastic_beanstalk/errors.rb +22 -0
  304. data/lib/aws/elastic_transcoder.rb +29 -0
  305. data/lib/aws/elastic_transcoder/client.rb +48 -0
  306. data/lib/aws/elastic_transcoder/config.rb +18 -0
  307. data/lib/aws/elastic_transcoder/errors.rb +23 -0
  308. data/lib/aws/elasticache.rb +49 -0
  309. data/lib/aws/elasticache/client.rb +45 -0
  310. data/lib/aws/elasticache/config.rb +18 -0
  311. data/lib/aws/elasticache/errors.rb +22 -0
  312. data/lib/aws/elb.rb +66 -0
  313. data/lib/aws/elb/availability_zone_collection.rb +138 -0
  314. data/lib/aws/elb/backend_server_policy_collection.rb +139 -0
  315. data/lib/aws/elb/client.rb +35 -0
  316. data/lib/aws/elb/config.rb +18 -0
  317. data/lib/aws/elb/errors.rb +26 -0
  318. data/lib/aws/elb/instance_collection.rb +168 -0
  319. data/lib/aws/elb/listener.rb +190 -0
  320. data/lib/aws/elb/listener_collection.rb +113 -0
  321. data/lib/aws/elb/listener_opts.rb +45 -0
  322. data/lib/aws/elb/load_balancer.rb +280 -0
  323. data/lib/aws/elb/load_balancer_collection.rb +148 -0
  324. data/lib/aws/elb/load_balancer_policy.rb +93 -0
  325. data/lib/aws/elb/load_balancer_policy_collection.rb +208 -0
  326. data/lib/aws/emr.rb +87 -0
  327. data/lib/aws/emr/client.rb +35 -0
  328. data/lib/aws/emr/config.rb +18 -0
  329. data/lib/aws/emr/errors.rb +22 -0
  330. data/lib/aws/emr/instance_group.rb +138 -0
  331. data/lib/aws/emr/instance_group_collection.rb +82 -0
  332. data/lib/aws/emr/job_flow.rb +307 -0
  333. data/lib/aws/emr/job_flow_collection.rb +183 -0
  334. data/lib/aws/errors.rb +162 -0
  335. data/lib/aws/glacier.rb +79 -0
  336. data/lib/aws/glacier/archive.rb +56 -0
  337. data/lib/aws/glacier/archive_collection.rb +146 -0
  338. data/lib/aws/glacier/client.rb +49 -0
  339. data/lib/aws/glacier/config.rb +19 -0
  340. data/lib/aws/glacier/errors.rb +22 -0
  341. data/lib/aws/glacier/resource.rb +30 -0
  342. data/lib/aws/glacier/vault.rb +145 -0
  343. data/lib/aws/glacier/vault_collection.rb +75 -0
  344. data/lib/aws/glacier/vault_notification_configuration.rb +29 -0
  345. data/lib/aws/iam.rb +408 -0
  346. data/lib/aws/iam/access_key.rb +185 -0
  347. data/lib/aws/iam/access_key_collection.rb +128 -0
  348. data/lib/aws/iam/account_alias_collection.rb +79 -0
  349. data/lib/aws/iam/client.rb +49 -0
  350. data/lib/aws/iam/collection.rb +83 -0
  351. data/lib/aws/iam/config.rb +18 -0
  352. data/lib/aws/iam/errors.rb +22 -0
  353. data/lib/aws/iam/group.rb +111 -0
  354. data/lib/aws/iam/group_collection.rb +132 -0
  355. data/lib/aws/iam/group_policy_collection.rb +47 -0
  356. data/lib/aws/iam/group_user_collection.rb +84 -0
  357. data/lib/aws/iam/login_profile.rb +111 -0
  358. data/lib/aws/iam/mfa_device.rb +52 -0
  359. data/lib/aws/iam/mfa_device_collection.rb +127 -0
  360. data/lib/aws/iam/policy.rb +46 -0
  361. data/lib/aws/iam/policy_collection.rb +188 -0
  362. data/lib/aws/iam/resource.rb +62 -0
  363. data/lib/aws/iam/server_certificate.rb +148 -0
  364. data/lib/aws/iam/server_certificate_collection.rb +138 -0
  365. data/lib/aws/iam/signing_certificate.rb +186 -0
  366. data/lib/aws/iam/signing_certificate_collection.rb +131 -0
  367. data/lib/aws/iam/user.rb +200 -0
  368. data/lib/aws/iam/user_collection.rb +133 -0
  369. data/lib/aws/iam/user_group_collection.rb +98 -0
  370. data/lib/aws/iam/user_policy.rb +90 -0
  371. data/lib/aws/iam/user_policy_collection.rb +45 -0
  372. data/lib/aws/iam/virtual_mfa_device.rb +139 -0
  373. data/lib/aws/iam/virtual_mfa_device_collection.rb +73 -0
  374. data/lib/aws/import_export.rb +73 -0
  375. data/lib/aws/import_export/client.rb +35 -0
  376. data/lib/aws/import_export/config.rb +19 -0
  377. data/lib/aws/import_export/errors.rb +22 -0
  378. data/lib/aws/kinesis.rb +53 -0
  379. data/lib/aws/kinesis/client.rb +35 -0
  380. data/lib/aws/kinesis/config.rb +18 -0
  381. data/lib/aws/kinesis/errors.rb +20 -0
  382. data/lib/aws/ops_works.rb +29 -0
  383. data/lib/aws/ops_works/client.rb +35 -0
  384. data/lib/aws/ops_works/config.rb +18 -0
  385. data/lib/aws/ops_works/errors.rb +20 -0
  386. data/lib/aws/rails.rb +195 -0
  387. data/lib/aws/rds.rb +70 -0
  388. data/lib/aws/rds/client.rb +48 -0
  389. data/lib/aws/rds/config.rb +18 -0
  390. data/lib/aws/rds/db_instance.rb +215 -0
  391. data/lib/aws/rds/db_instance_collection.rb +75 -0
  392. data/lib/aws/rds/db_snapshot.rb +163 -0
  393. data/lib/aws/rds/db_snapshot_collection.rb +89 -0
  394. data/lib/aws/rds/errors.rb +22 -0
  395. data/lib/aws/record.rb +139 -0
  396. data/lib/aws/record/abstract_base.rb +689 -0
  397. data/lib/aws/record/attributes.rb +388 -0
  398. data/lib/aws/record/conversion.rb +38 -0
  399. data/lib/aws/record/dirty_tracking.rb +287 -0
  400. data/lib/aws/record/errors.rb +143 -0
  401. data/lib/aws/record/exceptions.rb +51 -0
  402. data/lib/aws/record/hash_model.rb +204 -0
  403. data/lib/aws/record/hash_model/attributes.rb +195 -0
  404. data/lib/aws/record/hash_model/finder_methods.rb +172 -0
  405. data/lib/aws/record/hash_model/scope.rb +108 -0
  406. data/lib/aws/record/model.rb +453 -0
  407. data/lib/aws/record/model/attributes.rb +377 -0
  408. data/lib/aws/record/model/finder_methods.rb +232 -0
  409. data/lib/aws/record/model/scope.rb +212 -0
  410. data/lib/aws/record/naming.rb +31 -0
  411. data/lib/aws/record/scope.rb +203 -0
  412. data/lib/aws/record/validations.rb +694 -0
  413. data/lib/aws/record/validator.rb +246 -0
  414. data/lib/aws/record/validators/acceptance.rb +49 -0
  415. data/lib/aws/record/validators/block.rb +36 -0
  416. data/lib/aws/record/validators/confirmation.rb +41 -0
  417. data/lib/aws/record/validators/count.rb +106 -0
  418. data/lib/aws/record/validators/exclusion.rb +41 -0
  419. data/lib/aws/record/validators/format.rb +55 -0
  420. data/lib/aws/record/validators/inclusion.rb +54 -0
  421. data/lib/aws/record/validators/length.rb +105 -0
  422. data/lib/aws/record/validators/method.rb +31 -0
  423. data/lib/aws/record/validators/numericality.rb +136 -0
  424. data/lib/aws/record/validators/presence.rb +43 -0
  425. data/lib/aws/redshift.rb +51 -0
  426. data/lib/aws/redshift/client.rb +35 -0
  427. data/lib/aws/redshift/config.rb +18 -0
  428. data/lib/aws/redshift/errors.rb +22 -0
  429. data/lib/aws/route_53.rb +86 -0
  430. data/lib/aws/route_53/change_batch.rb +162 -0
  431. data/lib/aws/route_53/change_info.rb +72 -0
  432. data/lib/aws/route_53/client.rb +38 -0
  433. data/lib/aws/route_53/config.rb +18 -0
  434. data/lib/aws/route_53/errors.rb +22 -0
  435. data/lib/aws/route_53/hosted_zone.rb +159 -0
  436. data/lib/aws/route_53/hosted_zone_collection.rb +101 -0
  437. data/lib/aws/route_53/resource_record_set.rb +258 -0
  438. data/lib/aws/route_53/resource_record_set_collection.rb +110 -0
  439. data/lib/aws/s3.rb +160 -0
  440. data/lib/aws/s3/access_control_list.rb +265 -0
  441. data/lib/aws/s3/acl_object.rb +264 -0
  442. data/lib/aws/s3/acl_options.rb +204 -0
  443. data/lib/aws/s3/bucket.rb +743 -0
  444. data/lib/aws/s3/bucket_collection.rb +162 -0
  445. data/lib/aws/s3/bucket_lifecycle_configuration.rb +473 -0
  446. data/lib/aws/s3/bucket_region_cache.rb +51 -0
  447. data/lib/aws/s3/bucket_tag_collection.rb +111 -0
  448. data/lib/aws/s3/bucket_version_collection.rb +79 -0
  449. data/lib/aws/s3/cipher_io.rb +120 -0
  450. data/lib/aws/s3/client.rb +2089 -0
  451. data/lib/aws/s3/client/xml.rb +266 -0
  452. data/lib/aws/s3/config.rb +61 -0
  453. data/lib/aws/s3/cors_rule.rb +108 -0
  454. data/lib/aws/s3/cors_rule_collection.rb +194 -0
  455. data/lib/aws/s3/data_options.rb +191 -0
  456. data/lib/aws/s3/encryption_utils.rb +146 -0
  457. data/lib/aws/s3/errors.rb +94 -0
  458. data/lib/aws/s3/multipart_upload.rb +353 -0
  459. data/lib/aws/s3/multipart_upload_collection.rb +76 -0
  460. data/lib/aws/s3/object_collection.rb +356 -0
  461. data/lib/aws/s3/object_metadata.rb +103 -0
  462. data/lib/aws/s3/object_upload_collection.rb +77 -0
  463. data/lib/aws/s3/object_version.rb +154 -0
  464. data/lib/aws/s3/object_version_collection.rb +89 -0
  465. data/lib/aws/s3/paginated_collection.rb +75 -0
  466. data/lib/aws/s3/policy.rb +74 -0
  467. data/lib/aws/s3/prefix_and_delimiter_collection.rb +47 -0
  468. data/lib/aws/s3/prefixed_collection.rb +85 -0
  469. data/lib/aws/s3/presign_v4.rb +136 -0
  470. data/lib/aws/s3/presigned_post.rb +554 -0
  471. data/lib/aws/s3/region_detection.rb +75 -0
  472. data/lib/aws/s3/request.rb +62 -0
  473. data/lib/aws/s3/s3_object.rb +1795 -0
  474. data/lib/aws/s3/tree.rb +116 -0
  475. data/lib/aws/s3/tree/branch_node.rb +68 -0
  476. data/lib/aws/s3/tree/child_collection.rb +104 -0
  477. data/lib/aws/s3/tree/leaf_node.rb +94 -0
  478. data/lib/aws/s3/tree/node.rb +22 -0
  479. data/lib/aws/s3/tree/parent.rb +87 -0
  480. data/lib/aws/s3/uploaded_part.rb +82 -0
  481. data/lib/aws/s3/uploaded_part_collection.rb +84 -0
  482. data/lib/aws/s3/website_configuration.rb +102 -0
  483. data/lib/aws/simple_db.rb +218 -0
  484. data/lib/aws/simple_db/attribute.rb +156 -0
  485. data/lib/aws/simple_db/attribute_collection.rb +240 -0
  486. data/lib/aws/simple_db/client.rb +67 -0
  487. data/lib/aws/simple_db/config.rb +20 -0
  488. data/lib/aws/simple_db/consistent_read_option.rb +42 -0
  489. data/lib/aws/simple_db/delete_attributes.rb +62 -0
  490. data/lib/aws/simple_db/domain.rb +123 -0
  491. data/lib/aws/simple_db/domain_collection.rb +86 -0
  492. data/lib/aws/simple_db/domain_metadata.rb +110 -0
  493. data/lib/aws/simple_db/errors.rb +55 -0
  494. data/lib/aws/simple_db/expect_condition_option.rb +45 -0
  495. data/lib/aws/simple_db/item.rb +93 -0
  496. data/lib/aws/simple_db/item_collection.rb +654 -0
  497. data/lib/aws/simple_db/item_data.rb +73 -0
  498. data/lib/aws/simple_db/put_attributes.rb +60 -0
  499. data/lib/aws/simple_email_service.rb +443 -0
  500. data/lib/aws/simple_email_service/client.rb +37 -0
  501. data/lib/aws/simple_email_service/config.rb +18 -0
  502. data/lib/aws/simple_email_service/email_address_collection.rb +69 -0
  503. data/lib/aws/simple_email_service/errors.rb +22 -0
  504. data/lib/aws/simple_email_service/identity.rb +230 -0
  505. data/lib/aws/simple_email_service/identity_collection.rb +81 -0
  506. data/lib/aws/simple_email_service/quotas.rb +66 -0
  507. data/lib/aws/simple_workflow.rb +227 -0
  508. data/lib/aws/simple_workflow/activity_task.rb +178 -0
  509. data/lib/aws/simple_workflow/activity_task_collection.rb +123 -0
  510. data/lib/aws/simple_workflow/activity_type.rb +140 -0
  511. data/lib/aws/simple_workflow/activity_type_collection.rb +102 -0
  512. data/lib/aws/simple_workflow/client.rb +69 -0
  513. data/lib/aws/simple_workflow/config.rb +18 -0
  514. data/lib/aws/simple_workflow/count.rb +49 -0
  515. data/lib/aws/simple_workflow/decision_task.rb +617 -0
  516. data/lib/aws/simple_workflow/decision_task_collection.rb +223 -0
  517. data/lib/aws/simple_workflow/domain.rb +122 -0
  518. data/lib/aws/simple_workflow/domain_collection.rb +169 -0
  519. data/lib/aws/simple_workflow/errors.rb +20 -0
  520. data/lib/aws/simple_workflow/history_event.rb +280 -0
  521. data/lib/aws/simple_workflow/history_event_collection.rb +76 -0
  522. data/lib/aws/simple_workflow/option_formatters.rb +86 -0
  523. data/lib/aws/simple_workflow/resource.rb +94 -0
  524. data/lib/aws/simple_workflow/type.rb +89 -0
  525. data/lib/aws/simple_workflow/type_collection.rb +140 -0
  526. data/lib/aws/simple_workflow/workflow_execution.rb +391 -0
  527. data/lib/aws/simple_workflow/workflow_execution_collection.rb +617 -0
  528. data/lib/aws/simple_workflow/workflow_type.rb +186 -0
  529. data/lib/aws/simple_workflow/workflow_type_collection.rb +100 -0
  530. data/lib/aws/sns.rb +76 -0
  531. data/lib/aws/sns/client.rb +35 -0
  532. data/lib/aws/sns/config.rb +18 -0
  533. data/lib/aws/sns/errors.rb +22 -0
  534. data/lib/aws/sns/has_delivery_policy.rb +68 -0
  535. data/lib/aws/sns/message.rb +204 -0
  536. data/lib/aws/sns/originators/from_auto_scaling.rb +68 -0
  537. data/lib/aws/sns/policy.rb +47 -0
  538. data/lib/aws/sns/subscription.rb +165 -0
  539. data/lib/aws/sns/subscription_collection.rb +78 -0
  540. data/lib/aws/sns/topic.rb +403 -0
  541. data/lib/aws/sns/topic_collection.rb +62 -0
  542. data/lib/aws/sns/topic_subscription_collection.rb +54 -0
  543. data/lib/aws/sqs.rb +80 -0
  544. data/lib/aws/sqs/client.rb +53 -0
  545. data/lib/aws/sqs/config.rb +20 -0
  546. data/lib/aws/sqs/errors.rb +125 -0
  547. data/lib/aws/sqs/policy.rb +48 -0
  548. data/lib/aws/sqs/queue.rb +856 -0
  549. data/lib/aws/sqs/queue_collection.rb +186 -0
  550. data/lib/aws/sqs/received_message.rb +190 -0
  551. data/lib/aws/sqs/received_sns_message.rb +116 -0
  552. data/lib/aws/storage_gateway.rb +72 -0
  553. data/lib/aws/storage_gateway/client.rb +42 -0
  554. data/lib/aws/storage_gateway/config.rb +18 -0
  555. data/lib/aws/storage_gateway/errors.rb +22 -0
  556. data/lib/aws/sts.rb +164 -0
  557. data/lib/aws/sts/client.rb +55 -0
  558. data/lib/aws/sts/config.rb +18 -0
  559. data/lib/aws/sts/errors.rb +22 -0
  560. data/lib/aws/sts/federated_session.rb +56 -0
  561. data/lib/aws/sts/policy.rb +30 -0
  562. data/lib/aws/sts/session.rb +48 -0
  563. data/lib/aws/support.rb +29 -0
  564. data/lib/aws/support/client.rb +35 -0
  565. data/lib/aws/support/config.rb +18 -0
  566. data/lib/aws/support/errors.rb +20 -0
  567. data/lib/aws/version.rb +17 -0
  568. data/rails/init.rb +15 -0
  569. metadata +645 -0
@@ -0,0 +1,75 @@
1
+ require 'cgi'
2
+
3
+ module AWS
4
+ class S3
5
+ # @api private
6
+ module RegionDetection
7
+
8
+ private
9
+
10
+ def retry_server_errors(&block)
11
+ response = super
12
+ if requires_sigv4?(response)
13
+ detect_region_and_retry(response, &block)
14
+ else
15
+ response
16
+ end
17
+ end
18
+
19
+ def requires_sigv4?(resp)
20
+ resp.http_response.status == 400 &&
21
+ resp.http_response.body &&
22
+ resp.http_response.body.include?('Please use AWS4-HMAC-SHA256')
23
+ end
24
+
25
+ def detect_region_and_retry(response, &retry_block)
26
+ updgrade_to_v4(response, 'us-east-1')
27
+ yield
28
+ return if response.http_response.status == 200
29
+ actual_region = region_from_location_header(response)
30
+ updgrade_to_v4(response, actual_region)
31
+ log_region_warning(response, actual_region)
32
+ yield
33
+ end
34
+
35
+ def updgrade_to_v4(response, region)
36
+ bucket = response.request_options[:bucket_name]
37
+ if response.http_request.body_stream.respond_to?(:rewind)
38
+ response.http_request.body_stream.rewind
39
+ end
40
+ response.http_request.headers.delete('authorization')
41
+ response.http_request.headers.delete('x-amz-security-token')
42
+ response.http_request.host = new_hostname(response, region)
43
+ new_v4_signer(region).sign_request(response.http_request)
44
+ end
45
+
46
+ def region_from_location_header(response)
47
+ location = response.http_response.headers['location'].first
48
+ location.match(/s3\.(.+?)\.amazonaws\.com/)[1]
49
+ end
50
+
51
+ def new_v4_signer(region)
52
+ Core::Signers::Version4.new(credential_provider, 's3', region)
53
+ end
54
+
55
+ def new_hostname(response, region)
56
+ bucket = response.request_options[:bucket_name]
57
+ if region == 'us-east-1'
58
+ 's3-external-1.amazonaws.com'
59
+ else
60
+ "s3.#{region}.amazonaws.com"
61
+ end
62
+ end
63
+
64
+ def log_region_warning(response, actual_region)
65
+ bucket_name = response.request_options[:bucket_name]
66
+ S3::BUCKET_REGIONS[bucket_name] = actual_region
67
+ log_warning("S3 client configured for #{@region.inspect} " +
68
+ "but the bucket #{bucket_name.inspect} is in" +
69
+ "#{actual_region.inspect}; Please configure the proper region " +
70
+ "to avoid multiple unecessary redirects and signing attempts\n")
71
+ end
72
+
73
+ end
74
+ end
75
+ end
@@ -0,0 +1,62 @@
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 'uri'
15
+ require 'time'
16
+
17
+ module AWS
18
+ class S3
19
+
20
+ # @api private
21
+ class Request < Core::Http::Request
22
+
23
+ include Core::UriEscape
24
+
25
+ # @return [bucket] S3 bucket name
26
+ attr_accessor :bucket
27
+
28
+ # @return [String] S3 object key
29
+ attr_accessor :key
30
+
31
+ # @api private
32
+ attr_accessor :force_path_style
33
+
34
+ def host
35
+ path_style? ? @host : "#{bucket}.#{@host}"
36
+ end
37
+
38
+ def path_style?
39
+ if force_path_style
40
+ true
41
+ else
42
+ Client.path_style_bucket_name?(bucket)
43
+ end
44
+ end
45
+
46
+ def uri
47
+ parts = []
48
+ parts << bucket if bucket and path_style?
49
+ parts << escape_path(key) if key
50
+
51
+ path = '/' + parts.join('/')
52
+ querystring = url_encoded_params
53
+
54
+ uri = ''
55
+ uri << path
56
+ uri << "?#{querystring}" if querystring
57
+ uri
58
+ end
59
+
60
+ end
61
+ end
62
+ end
@@ -0,0 +1,1795 @@
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 'uri'
15
+ require 'base64'
16
+
17
+ module AWS
18
+ class S3
19
+
20
+ # Represents an object in S3. Objects live in a bucket and have
21
+ # unique keys.
22
+ #
23
+ # # Getting Objects
24
+ #
25
+ # You can get an object by its key.
26
+ #
27
+ # s3 = AWS::S3.new
28
+ # obj = s3.buckets['my-bucket'].objects['key'] # no request made
29
+ #
30
+ # You can also get objects by enumerating a objects in a bucket.
31
+ #
32
+ # bucket.objects.each do |obj|
33
+ # puts obj.key
34
+ # end
35
+ #
36
+ # See {ObjectCollection} for more information on finding objects.
37
+ #
38
+ # # Creating Objects
39
+ #
40
+ # You create an object by writing to it. The following two
41
+ # expressions are equivalent.
42
+ #
43
+ # obj = bucket.objects.create('key', 'data')
44
+ # obj = bucket.objects['key'].write('data')
45
+ #
46
+ # # Writing Objects
47
+ #
48
+ # To upload data to S3, you simply need to call {#write} on an object.
49
+ #
50
+ # obj.write('Hello World!')
51
+ # obj.read
52
+ # #=> 'Hello World!'
53
+ #
54
+ # ## Uploading Files
55
+ #
56
+ # You can upload a file to S3 in a variety of ways. Given a path
57
+ # to a file (as a string) you can do any of the following:
58
+ #
59
+ # # specify the data as a path to a file
60
+ # obj.write(Pathname.new(path_to_file))
61
+ #
62
+ # # also works this way
63
+ # obj.write(:file => path_to_file)
64
+ #
65
+ # # Also accepts an open file object
66
+ # file = File.open(path_to_file, 'rb')
67
+ # obj.write(file)
68
+ #
69
+ # All three examples above produce the same result. The file
70
+ # will be streamed to S3 in chunks. It will not be loaded
71
+ # entirely into memory.
72
+ #
73
+ # ## Streaming Uploads
74
+ #
75
+ # When you call {#write} with an IO-like object, it will be streamed
76
+ # to S3 in chunks.
77
+ #
78
+ # While it is possible to determine the size of many IO objects, you may
79
+ # have to specify the :content_length of your IO object.
80
+ # If the exact size can not be known, you may provide an
81
+ # `:estimated_content_length`. Depending on the size (actual or
82
+ # estimated) of your data, it will be uploaded in a single request or
83
+ # in multiple requests via {#multipart_upload}.
84
+ #
85
+ # You may also stream uploads to S3 using a block:
86
+ #
87
+ # obj.write do |buffer, bytes|
88
+ # # writing fewer than the requested number of bytes to the buffer
89
+ # # will cause write to stop yielding to the block
90
+ # end
91
+ #
92
+ # # Reading Objects
93
+ #
94
+ # You can read an object directly using {#read}. Be warned, this will
95
+ # load the entire object into memory and is not recommended for large
96
+ # objects.
97
+ #
98
+ # obj.write('abc')
99
+ # puts obj.read
100
+ # #=> abc
101
+ #
102
+ # ## Streaming Downloads
103
+ #
104
+ # If you want to stream an object from S3, you can pass a block
105
+ # to {#read}.
106
+ #
107
+ # File.open('output', 'wb') do |file|
108
+ # large_object.read do |chunk|
109
+ # file.write(chunk)
110
+ # end
111
+ # end
112
+ #
113
+ # # Encryption
114
+ #
115
+ # Amazon S3 can encrypt objects for you service-side. You can also
116
+ # use client-side encryption.
117
+ #
118
+ # ## Server Side Encryption
119
+ #
120
+ # You can specify to use server side encryption when writing an object.
121
+ #
122
+ # obj.write('data', :server_side_encryption => :aes256)
123
+ #
124
+ # You can also make this the default behavior.
125
+ #
126
+ # AWS.config(:s3_server_side_encryption => :aes256)
127
+ #
128
+ # s3 = AWS::S3.new
129
+ # s3.buckets['name'].objects['key'].write('abc') # will be encrypted
130
+ #
131
+ # ## Client Side Encryption
132
+ #
133
+ # Client side encryption utilizes envelope encryption, so that your keys are
134
+ # never sent to S3. You can use a symetric key or an asymmetric
135
+ # key pair.
136
+ #
137
+ # ### Symmetric Key Encryption
138
+ #
139
+ # An AES key is used for symmetric encryption. The key can be 128, 192,
140
+ # and 256 bit sizes. Start by generating key or read a previously
141
+ # generated key.
142
+ #
143
+ # # generate a new random key
144
+ # my_key = OpenSSL::Cipher.new("AES-256-ECB").random_key
145
+ #
146
+ # # read an existing key from disk
147
+ # my_key = File.read("my_key.der")
148
+ #
149
+ # Now you can encrypt locally and upload the encrypted data to S3.
150
+ # To do this, you need to provide your key.
151
+ #
152
+ # obj = bucket.objects["my-text-object"]
153
+ #
154
+ # # encrypt then upload data
155
+ # obj.write("MY TEXT", :encryption_key => my_key)
156
+ #
157
+ # # try read the object without decrypting, oops
158
+ # obj.read
159
+ # #=> '.....'
160
+ #
161
+ # Lastly, you can download and decrypt by providing the same key.
162
+ #
163
+ # obj.read(:encryption_key => my_key)
164
+ # #=> "MY TEXT"
165
+ #
166
+ # ### Asymmetric Key Pair
167
+ #
168
+ # A RSA key pair is used for asymmetric encryption. The public key is used
169
+ # for encryption and the private key is used for decryption. Start
170
+ # by generating a key.
171
+ #
172
+ # my_key = OpenSSL::PKey::RSA.new(1024)
173
+ #
174
+ # Provide your key to #write and the data will be encrypted before it
175
+ # is uploaded. Pass the same key to #read to decrypt the data
176
+ # when you download it.
177
+ #
178
+ # obj = bucket.objects["my-text-object"]
179
+ #
180
+ # # encrypt and upload the data
181
+ # obj.write("MY TEXT", :encryption_key => my_key)
182
+ #
183
+ # # download and decrypt the data
184
+ # obj.read(:encryption_key => my_key)
185
+ # #=> "MY TEXT"
186
+ #
187
+ # ### Configuring storage locations
188
+ #
189
+ # By default, encryption materials are stored in the object metadata.
190
+ # If you prefer, you can store the encryption materials in a separate
191
+ # object in S3. This object will have the same key + '.instruction'.
192
+ #
193
+ # # new object, does not exist yet
194
+ # obj = bucket.objects["my-text-object"]
195
+ #
196
+ # # no instruction file present
197
+ # bucket.objects['my-text-object.instruction'].exists?
198
+ # #=> false
199
+ #
200
+ # # store the encryption materials in the instruction file
201
+ # # instead of obj#metadata
202
+ # obj.write("MY TEXT",
203
+ # :encryption_key => MY_KEY,
204
+ # :encryption_materials_location => :instruction_file)
205
+ #
206
+ # bucket.objects['my-text-object.instruction'].exists?
207
+ # #=> true
208
+ #
209
+ # If you store the encryption materials in an instruction file, you
210
+ # must tell #read this or it will fail to find your encryption materials.
211
+ #
212
+ # # reading an encrypted file whos materials are stored in an
213
+ # # instruction file, and not metadata
214
+ # obj.read(:encryption_key => MY_KEY,
215
+ # :encryption_materials_location => :instruction_file)
216
+ #
217
+ # ### Configuring default behaviors
218
+ #
219
+ # You can configure the default key such that it will automatically
220
+ # encrypt and decrypt for you. You can do this globally or for a
221
+ # single S3 interface
222
+ #
223
+ # # all objects uploaded/downloaded with this s3 object will be
224
+ # # encrypted/decrypted
225
+ # s3 = AWS::S3.new(:s3_encryption_key => "MY_KEY")
226
+ #
227
+ # # set the key to always encrypt/decrypt
228
+ # AWS.config(:s3_encryption_key => "MY_KEY")
229
+ #
230
+ # You can also configure the default storage location for the encryption
231
+ # materials.
232
+ #
233
+ # AWS.config(:s3_encryption_materials_location => :instruction_file)
234
+ #
235
+ class S3Object
236
+
237
+ include Core::Model
238
+ include DataOptions
239
+ include ACLOptions
240
+ include AWS::S3::EncryptionUtils
241
+
242
+ # @param [Bucket] bucket The bucket this object belongs to.
243
+ # @param [String] key The object's key.
244
+ def initialize(bucket, key, opts = {})
245
+ @content_length = opts.delete(:content_length)
246
+ @etag = opts.delete(:etag)
247
+ @last_modified = opts.delete(:last_modified)
248
+ super
249
+ @key = key
250
+ @bucket = bucket
251
+ end
252
+
253
+ # @return [String] The objects unique key
254
+ attr_reader :key
255
+
256
+ # @return [Bucket] The bucket this object is in.
257
+ attr_reader :bucket
258
+
259
+ # @api private
260
+ def inspect
261
+ "<#{self.class}:#{bucket.name}/#{key}>"
262
+ end
263
+
264
+ # @return [Boolean] Returns true if the other object belongs to the
265
+ # same bucket and has the same key.
266
+ def == other
267
+ other.kind_of?(S3Object) and other.bucket == bucket and other.key == key
268
+ end
269
+ alias_method :eql?, :==
270
+
271
+ # @return [Boolean] Returns `true` if the object exists in S3.
272
+ def exists?
273
+ head
274
+ rescue Errors::NoSuchKey => e
275
+ false
276
+ else
277
+ true
278
+ end
279
+
280
+ # Performs a HEAD request against this object and returns an object
281
+ # with useful information about the object, including:
282
+ #
283
+ # * metadata (hash of user-supplied key-value pairs)
284
+ # * content_length (integer, number of bytes)
285
+ # * content_type (as sent to S3 when uploading the object)
286
+ # * etag (typically the object's MD5)
287
+ # * server_side_encryption (the algorithm used to encrypt the
288
+ # object on the server side, e.g. `:aes256`)
289
+ #
290
+ # @param [Hash] options
291
+ # @option options [String] :version_id Which version of this object
292
+ # to make a HEAD request against.
293
+ # @return A head object response with metadata,
294
+ # content_length, content_type, etag and server_side_encryption.
295
+ def head options = {}
296
+ client.head_object(options.merge(
297
+ :bucket_name => bucket.name, :key => key))
298
+ end
299
+
300
+ # Returns the object's ETag.
301
+ #
302
+ # Generally the ETAG is the MD5 of the object. If the object was
303
+ # uploaded using multipart upload then this is the MD5 all of the
304
+ # upload-part-md5s.
305
+ #
306
+ # @return [String] Returns the object's ETag
307
+ def etag
308
+ @etag = config.s3_cache_object_attributes && @etag || head[:etag]
309
+ end
310
+
311
+ # Returns the object's last modified time.
312
+ #
313
+ # @return [Time] Returns the object's last modified time.
314
+ def last_modified
315
+ @last_modified = config.s3_cache_object_attributes && @last_modified || head[:last_modified]
316
+ end
317
+
318
+ # @return [Integer] Size of the object in bytes.
319
+ def content_length
320
+ @content_length = config.s3_cache_object_attributes && @content_length || head[:content_length]
321
+ end
322
+
323
+ # @note S3 does not compute content-type. It reports the content-type
324
+ # as was reported during the file upload.
325
+ # @return [String] Returns the content type as reported by S3,
326
+ # defaults to an empty string when not provided during upload.
327
+ def content_type
328
+ head[:content_type]
329
+ end
330
+
331
+ # @return [DateTime,nil]
332
+ def expiration_date
333
+ head[:expiration_date]
334
+ end
335
+
336
+ # @return [String,nil]
337
+ def expiration_rule_id
338
+ head[:expiration_rule_id]
339
+ end
340
+
341
+ # @return [Symbol, nil] Returns the algorithm used to encrypt
342
+ # the object on the server side, or `nil` if SSE was not used
343
+ # when storing the object.
344
+ def server_side_encryption
345
+ head[:server_side_encryption]
346
+ end
347
+
348
+ # @return [true, false] Returns true if the object was stored
349
+ # using server side encryption.
350
+ def server_side_encryption?
351
+ !server_side_encryption.nil?
352
+ end
353
+
354
+ # @return [Boolean] whether a {#restore} operation on the
355
+ # object is currently being performed on the object.
356
+ # @see #restore_expiration_date
357
+ # @since 1.7.2
358
+ def restore_in_progress?
359
+ head[:restore_in_progress]
360
+ end
361
+
362
+ # @return [DateTime] the time when the temporarily restored object
363
+ # will be removed from S3. Note that the original object will remain
364
+ # available in Glacier.
365
+ # @return [nil] if the object was not restored from an archived
366
+ # copy
367
+ # @since 1.7.2
368
+ def restore_expiration_date
369
+ head[:restore_expiration_date]
370
+ end
371
+
372
+ # @return [Boolean] whether the object is a temporary copy of an
373
+ # archived object in the Glacier storage class.
374
+ # @since 1.7.2
375
+ def restored_object?
376
+ !!head[:restore_expiration_date]
377
+ end
378
+
379
+ # Deletes the object from its S3 bucket.
380
+ #
381
+ # @param [Hash] options
382
+ #
383
+ # @option [String] :version_id (nil) If present the specified version
384
+ # of this object will be deleted. Only works for buckets that have
385
+ # had versioning enabled.
386
+ #
387
+ # @option [Boolean] :delete_instruction_file (false) Set this to `true`
388
+ # if you use client-side encryption and the encryption materials
389
+ # were stored in a separate object in S3 (key.instruction).
390
+ #
391
+ # @option [String] :mfa The serial number and current token code of
392
+ # the Multi-Factor Authentication (MFA) device for the user. Format
393
+ # is "SERIAL TOKEN" - with a space between the serial and token.
394
+ #
395
+ # @return [nil]
396
+ def delete options = {}
397
+ client.delete_object(options.merge(
398
+ :bucket_name => bucket.name,
399
+ :key => key))
400
+
401
+ if options[:delete_instruction_file]
402
+ client.delete_object(
403
+ :bucket_name => bucket.name,
404
+ :key => key + '.instruction')
405
+ end
406
+
407
+ nil
408
+
409
+ end
410
+
411
+ # Restores a temporary copy of an archived object from the
412
+ # Glacier storage tier. After the specified `days`, Amazon
413
+ # S3 deletes the temporary copy. Note that the object
414
+ # remains archived; Amazon S3 deletes only the restored copy.
415
+ #
416
+ # Restoring an object does not occur immediately. Use
417
+ # {#restore_in_progress?} to check the status of the operation.
418
+ #
419
+ # @option [Integer] :days (1) the number of days to keep the object
420
+ # @return [Boolean] `true` if a restore can be initiated.
421
+ # @since 1.7.2
422
+ def restore options = {}
423
+ options[:days] ||= 1
424
+ client.restore_object(options.merge({
425
+ :bucket_name => bucket.name,
426
+ :key => key,
427
+ }))
428
+ true
429
+ end
430
+
431
+ # @option [String] :version_id (nil) If present the metadata object
432
+ # will be for the specified version.
433
+ # @return [ObjectMetadata] Returns an instance of ObjectMetadata
434
+ # representing the metadata for this object.
435
+ def metadata options = {}
436
+ options[:config] = config
437
+ ObjectMetadata.new(self, options)
438
+ end
439
+
440
+ # Returns a collection representing all the object versions
441
+ # for this object.
442
+ #
443
+ # @example
444
+ #
445
+ # bucket.versioning_enabled? # => true
446
+ # version = bucket.objects["mykey"].versions.latest
447
+ #
448
+ # @return [ObjectVersionCollection]
449
+ def versions
450
+ ObjectVersionCollection.new(self)
451
+ end
452
+
453
+ # Uploads data to the object in S3.
454
+ #
455
+ # obj = s3.buckets['bucket-name'].objects['key']
456
+ #
457
+ # # strings
458
+ # obj.write("HELLO")
459
+ #
460
+ # # files (by path)
461
+ # obj.write(Pathname.new('path/to/file.txt'))
462
+ #
463
+ # # file objects
464
+ # obj.write(File.open('path/to/file.txt', 'rb'))
465
+ #
466
+ # # IO objects (must respond to #read and #eof?)
467
+ # obj.write(io)
468
+ #
469
+ # ### Multipart Uploads vs Single Uploads
470
+ #
471
+ # This method will intelligently choose between uploading the
472
+ # file in a signal request and using {#multipart_upload}.
473
+ # You can control this behavior by configuring the thresholds
474
+ # and you can disable the multipart feature as well.
475
+ #
476
+ # # always send the file in a single request
477
+ # obj.write(file, :single_request => true)
478
+ #
479
+ # # upload the file in parts if the total file size exceeds 100MB
480
+ # obj.write(file, :multipart_threshold => 100 * 1024 * 1024)
481
+ #
482
+ # @overload write(data, options = {})
483
+ #
484
+ # @param [String,Pathname,File,IO] data The data to upload.
485
+ # This may be a:
486
+ # * String
487
+ # * Pathname
488
+ # * File
489
+ # * IO
490
+ # * Any object that responds to `#read` and `#eof?`.
491
+ #
492
+ # @param options [Hash] Additional upload options.
493
+ #
494
+ # @option options [Integer] :content_length If provided, this
495
+ # option must match the total number of bytes written to S3.
496
+ # This options is *required* when it is not possible to
497
+ # automatically determine the size of `data`.
498
+ #
499
+ # @option options [Integer] :estimated_content_length When uploading
500
+ # data of unknown content length, you may specify this option to
501
+ # hint what mode of upload should take place. When
502
+ # `:estimated_content_length` exceeds the `:multipart_threshold`,
503
+ # then the data will be uploaded in parts, otherwise it will
504
+ # be read into memory and uploaded via {Client#put_object}.
505
+ #
506
+ # @option options [Boolean] :single_request (false) When `true`,
507
+ # this method will always upload the data in a single request
508
+ # (via {Client#put_object}). When `false`, this method will
509
+ # choose between {Client#put_object} and {#multipart_upload}.
510
+ #
511
+ # @option options [Integer] :multipart_threshold (16777216) Specifies
512
+ # the maximum size (in bytes) of a single-request upload. If the
513
+ # data exceeds this threshold, it will be uploaded via
514
+ # {#multipart_upload}. The default threshold is 16MB and can
515
+ # be configured via AWS.config(:s3_multipart_threshold => ...).
516
+ #
517
+ # @option options [Integer] :multipart_min_part_size (5242880) The
518
+ # minimum size of a part to upload to S3 when using
519
+ # {#multipart_upload}. S3 will reject parts smaller than 5MB
520
+ # (except the final part). The default is 5MB and can be
521
+ # configured via AWS.config(:s3_multipart_min_part_size => ...).
522
+ #
523
+ # @option options [Hash] :metadata A hash of metadata to be
524
+ # included with the object. These will be sent to S3 as
525
+ # headers prefixed with `x-amz-meta`. Each name, value pair
526
+ # must conform to US-ASCII.
527
+ #
528
+ # @option options [Symbol,String] :acl (:private) A canned access
529
+ # control policy. Valid values are:
530
+ #
531
+ # * `:private`
532
+ # * `:public_read`
533
+ # * `:public_read_write`
534
+ # * `:authenticated_read`
535
+ # * `:bucket_owner_read`
536
+ # * `:bucket_owner_full_control`
537
+ #
538
+ # @option options [String] :grant_read
539
+ #
540
+ # @option options [String] :grant_write
541
+ #
542
+ # @option options [String] :grant_read_acp
543
+ #
544
+ # @option options [String] :grant_write_acp
545
+ #
546
+ # @option options [String] :grant_full_control
547
+ #
548
+ # @option options [Boolean] :reduced_redundancy (false) When `true`,
549
+ # this object will be stored with Reduced Redundancy Storage.
550
+ #
551
+ # @option options :cache_control [String] Can be used to specify
552
+ # caching behavior. See
553
+ # http://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html#sec14.9
554
+ #
555
+ # @option options :content_disposition [String] Specifies
556
+ # presentational information for the object. See
557
+ # http://www.w3.org/Protocols/rfc2616/rfc2616-sec19.html#sec19.5.1
558
+ #
559
+ # @option options :content_encoding [String] Specifies what
560
+ # content encodings have been applied to the object and thus
561
+ # what decoding mechanisms must be applied to obtain the
562
+ # media-type referenced by the `Content-Type` header field.
563
+ # See
564
+ # http://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html#sec14.11
565
+ #
566
+ # @option options [String] :content_md5
567
+ # The base64 encoded content md5 of the data.
568
+ #
569
+ # @option options :content_type A standard MIME type
570
+ # describing the format of the object data.
571
+ #
572
+ # @option options [Symbol] :server_side_encryption (nil) If this
573
+ # option is set, the object will be stored using server side
574
+ # encryption. The only valid value is `:aes256`, which
575
+ # specifies that the object should be stored using the AES
576
+ # encryption algorithm with 256 bit keys. By default, this
577
+ # option uses the value of the `:s3_server_side_encryption`
578
+ # option in the current configuration; for more information,
579
+ # see {AWS.config}.
580
+ #
581
+ # @option options [OpenSSL::PKey::RSA, String] :encryption_key
582
+ # Set this to encrypt the data client-side using envelope
583
+ # encryption. The key must be an OpenSSL asymmetric key
584
+ # or a symmetric key string (16, 24 or 32 bytes in length).
585
+ #
586
+ # @option options [Symbol] :encryption_materials_location (:metadata)
587
+ # Set this to `:instruction_file` if you prefer to store the
588
+ # client-side encryption materials in a separate object in S3
589
+ # instead of in the object metadata.
590
+ #
591
+ # @option options [String] :expires The date and time at which the
592
+ # object is no longer cacheable.
593
+ #
594
+ # @option options [String] :website_redirect_location
595
+ #
596
+ # @return [S3Object, ObjectVersion] If the bucket has versioning
597
+ # enabled, this methods returns an {ObjectVersion}, otherwise
598
+ # this method returns `self`.
599
+ #
600
+ def write *args, &block
601
+
602
+ options = compute_write_options(*args, &block)
603
+
604
+ add_storage_class_option(options)
605
+ add_sse_options(options)
606
+ add_cse_options(options)
607
+
608
+ if use_multipart?(options)
609
+ write_with_multipart(options)
610
+ else
611
+ write_with_put_object(options)
612
+ end
613
+
614
+ end
615
+
616
+ # Performs a multipart upload. Use this if you have specific
617
+ # needs for how the upload is split into parts, or if you want
618
+ # to have more control over how the failure of an individual
619
+ # part upload is handled. Otherwise, {#write} is much simpler
620
+ # to use.
621
+ #
622
+ # Note: After you initiate multipart upload and upload one or
623
+ # more parts, you must either complete or abort multipart
624
+ # upload in order to stop getting charged for storage of the
625
+ # uploaded parts. Only after you either complete or abort
626
+ # multipart upload, Amazon S3 frees up the parts storage and
627
+ # stops charging you for the parts storage.
628
+ #
629
+ # @example Uploading an object in two parts
630
+ #
631
+ # bucket.objects.myobject.multipart_upload do |upload|
632
+ # upload.add_part("a" * 5242880)
633
+ # upload.add_part("b" * 2097152)
634
+ # end
635
+ #
636
+ # @example Uploading parts out of order
637
+ #
638
+ # bucket.objects.myobject.multipart_upload do |upload|
639
+ # upload.add_part("b" * 2097152, :part_number => 2)
640
+ # upload.add_part("a" * 5242880, :part_number => 1)
641
+ # end
642
+ #
643
+ # @example Aborting an upload after parts have been added
644
+ #
645
+ # bucket.objects.myobject.multipart_upload do |upload|
646
+ # upload.add_part("b" * 2097152, :part_number => 2)
647
+ # upload.abort
648
+ # end
649
+ #
650
+ # @example Starting an upload and completing it later by ID
651
+ #
652
+ # upload = bucket.objects.myobject.multipart_upload
653
+ # upload.add_part("a" * 5242880)
654
+ # upload.add_part("b" * 2097152)
655
+ # id = upload.id
656
+ #
657
+ # # later or in a different process
658
+ # upload = bucket.objects.myobject.multipart_uploads[id]
659
+ # upload.complete(:remote_parts)
660
+ #
661
+ # @yieldparam [MultipartUpload] upload A handle to the upload.
662
+ # {MultipartUpload#close} is called in an `ensure` clause so
663
+ # that the upload will always be either completed or
664
+ # aborted.
665
+ #
666
+ # @param [Hash] options Options for the upload.
667
+ #
668
+ # @option options [Hash] :metadata A hash of metadata to be
669
+ # included with the object. These will be sent to S3 as
670
+ # headers prefixed with `x-amz-meta`. Each name, value pair
671
+ # must conform to US-ASCII.
672
+ #
673
+ # @option options [Symbol] :acl (private) A canned access
674
+ # control policy. Valid values are:
675
+ #
676
+ # * `:private`
677
+ # * `:public_read`
678
+ # * `:public_read_write`
679
+ # * `:authenticated_read`
680
+ # * `:bucket_owner_read`
681
+ # * `:bucket_owner_full_control`
682
+ #
683
+ # @option options [Boolean] :reduced_redundancy (false) If true,
684
+ # Reduced Redundancy Storage will be enabled for the uploaded
685
+ # object.
686
+ #
687
+ # @option options :cache_control [String] Can be used to specify
688
+ # caching behavior. See
689
+ # http://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html#sec14.9
690
+ #
691
+ # @option options :content_disposition [String] Specifies
692
+ # presentational information for the object. See
693
+ # http://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html#sec19.5.1
694
+ #
695
+ # @option options :content_encoding [String] Specifies what
696
+ # content encodings have been applied to the object and thus
697
+ # what decoding mechanisms must be applied to obtain the
698
+ # media-type referenced by the `Content-Type` header field.
699
+ # See
700
+ # http://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html#sec14.11
701
+ #
702
+ # @option options :content_type A standard MIME type
703
+ # describing the format of the object data.
704
+ #
705
+ # @option options [Symbol] :server_side_encryption (nil) If this
706
+ # option is set, the object will be stored using server side
707
+ # encryption. The only valid value is `:aes256`, which
708
+ # specifies that the object should be stored using the AES
709
+ # encryption algorithm with 256 bit keys. By default, this
710
+ # option uses the value of the `:s3_server_side_encryption`
711
+ # option in the current configuration; for more information,
712
+ # see {AWS.config}.
713
+ #
714
+ # @return [S3Object, ObjectVersion] If the bucket has versioning
715
+ # enabled, returns the {ObjectVersion} representing the
716
+ # version that was uploaded. If versioning is disabled,
717
+ # returns self.
718
+ #
719
+ def multipart_upload(options = {})
720
+
721
+ options = options.dup
722
+ add_sse_options(options)
723
+
724
+ upload = multipart_uploads.create(options)
725
+
726
+ if block_given?
727
+ begin
728
+ yield(upload)
729
+ upload.close
730
+ rescue => e
731
+ upload.abort
732
+ raise e
733
+ end
734
+ else
735
+ upload
736
+ end
737
+ end
738
+
739
+ # @example Abort any in-progress uploads for the object:
740
+ #
741
+ # object.multipart_uploads.each(&:abort)
742
+ #
743
+ # @return [ObjectUploadCollection] Returns an object representing the
744
+ # collection of uploads that are in progress for this object.
745
+ def multipart_uploads
746
+ ObjectUploadCollection.new(self)
747
+ end
748
+
749
+ # Moves an object to a new key.
750
+ #
751
+ # This works by copying the object to a new key and then
752
+ # deleting the old object. This function returns the
753
+ # new object once this is done.
754
+ #
755
+ # bucket = s3.buckets['old-bucket']
756
+ # old_obj = bucket.objects['old-key']
757
+ #
758
+ # # renaming an object returns a new object
759
+ # new_obj = old_obj.move_to('new-key')
760
+ #
761
+ # old_obj.key #=> 'old-key'
762
+ # old_obj.exists? #=> false
763
+ #
764
+ # new_obj.key #=> 'new-key'
765
+ # new_obj.exists? #=> true
766
+ #
767
+ # If you need to move an object to a different bucket, pass
768
+ # `:bucket` or `:bucket_name`.
769
+ #
770
+ # obj = s3.buckets['old-bucket'].objects['old-key']
771
+ # obj.move_to('new-key', :bucket_name => 'new_bucket')
772
+ #
773
+ # If the copy succeeds, but the then the delete fails, an error
774
+ # will be raised.
775
+ #
776
+ # @param [String] target The key to move this object to.
777
+ #
778
+ # @param [Hash] options
779
+ #
780
+ # @option (see #copy_to)
781
+ #
782
+ # @return [S3Object] Returns a new object with the new key.
783
+ #
784
+ def move_to target, options = {}
785
+ copy = copy_to(target, options)
786
+ delete
787
+ copy
788
+ end
789
+ alias_method :rename_to, :move_to
790
+
791
+ # Copies data from one S3 object to another.
792
+ #
793
+ # S3 handles the copy so the clients does not need to fetch the data
794
+ # and upload it again. You can also change the storage class and
795
+ # metadata of the object when copying.
796
+ #
797
+ # @note This operation does not copy the ACL, storage class
798
+ # (standard vs. reduced redundancy) or server side encryption
799
+ # setting from the source object. If you don't specify any of
800
+ # these options when copying, the object will have the default
801
+ # values as described below.
802
+ #
803
+ # @param [Mixed] source
804
+ #
805
+ # @param [Hash] options
806
+ #
807
+ # @option options [String] :bucket_name The slash-prefixed name of
808
+ # the bucket the source object can be found in. Defaults to the
809
+ # current object's bucket.
810
+ #
811
+ # @option options [Bucket] :bucket The bucket the source object
812
+ # can be found in. Defaults to the current object's bucket.
813
+ #
814
+ # @option options [Hash] :metadata A hash of metadata to save
815
+ # with the copied object. Each name, value pair must conform
816
+ # to US-ASCII. When blank, the sources metadata is copied.
817
+ # If you set this value, you must set ALL metadata values for
818
+ # the object as we do not preserve existing values.
819
+ #
820
+ # @option options [String] :content_type The content type of
821
+ # the copied object. Defaults to the source object's content
822
+ # type.
823
+ #
824
+ # @option options [String] :content_disposition The presentational
825
+ # information for the object. Defaults to the source object's
826
+ # content disposition.
827
+ #
828
+ # @option options [Boolean] :reduced_redundancy (false) If true the
829
+ # object is stored with reduced redundancy in S3 for a lower cost.
830
+ #
831
+ # @option options [String] :version_id (nil) Causes the copy to
832
+ # read a specific version of the source object.
833
+ #
834
+ # @option options [Symbol] :acl (private) A canned access
835
+ # control policy. Valid values are:
836
+ #
837
+ # * `:private`
838
+ # * `:public_read`
839
+ # * `:public_read_write`
840
+ # * `:authenticated_read`
841
+ # * `:bucket_owner_read`
842
+ # * `:bucket_owner_full_control`
843
+ #
844
+ # @option options [Symbol] :server_side_encryption (nil) If this
845
+ # option is set, the object will be stored using server side
846
+ # encryption. The only valid value is `:aes256`, which
847
+ # specifies that the object should be stored using the AES
848
+ # encryption algorithm with 256 bit keys. By default, this
849
+ # option uses the value of the `:s3_server_side_encryption`
850
+ # option in the current configuration; for more information,
851
+ # see {AWS.config}.
852
+ #
853
+ # @option options [Boolean] :client_side_encrypted (false) Set to true
854
+ # when the object being copied was client-side encrypted. This
855
+ # is important so the encryption metadata will be copied.
856
+ #
857
+ # @option options [Boolean] :use_multipart_copy (false) Set this to
858
+ # `true` if you need to copy an object that is larger than 5GB.
859
+ #
860
+ # @option options :cache_control [String] Can be used to specify
861
+ # caching behavior. See
862
+ # http://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html#sec14.9
863
+ #
864
+ # @option options [String] :expires The date and time at which the
865
+ # object is no longer cacheable.
866
+ #
867
+ # @return [nil]
868
+ def copy_from source, options = {}
869
+
870
+ options = options.dup
871
+
872
+ options[:copy_source] =
873
+ case source
874
+ when S3Object
875
+ "/#{source.bucket.name}/#{source.key}"
876
+ when ObjectVersion
877
+ options[:version_id] = source.version_id
878
+ "/#{source.object.bucket.name}/#{source.object.key}"
879
+ else
880
+ if options[:bucket]
881
+ "/#{options.delete(:bucket).name}/#{source}"
882
+ elsif options[:bucket_name]
883
+ # oops, this should be slash-prefixed, but unable to change
884
+ # this without breaking users that already work-around this
885
+ # bug by sending :bucket_name => "/bucket-name"
886
+ "#{options.delete(:bucket_name)}/#{source}"
887
+ else
888
+ "/#{self.bucket.name}/#{source}"
889
+ end
890
+ end
891
+
892
+ if [:metadata, :content_disposition, :content_type, :cache_control,
893
+ ].any? {|opt| options.key?(opt) }
894
+ then
895
+ options[:metadata_directive] = 'REPLACE'
896
+ else
897
+ options[:metadata_directive] ||= 'COPY'
898
+ end
899
+
900
+ # copies client-side encryption materials (from the metadata or
901
+ # instruction file)
902
+ if options.delete(:client_side_encrypted)
903
+ copy_cse_materials(source, options)
904
+ end
905
+
906
+ add_sse_options(options)
907
+
908
+ options[:storage_class] = options.delete(:reduced_redundancy) ?
909
+ 'REDUCED_REDUNDANCY' : 'STANDARD'
910
+
911
+ options[:bucket_name] = bucket.name
912
+ options[:key] = key
913
+
914
+ if use_multipart_copy?(options)
915
+ multipart_copy(options)
916
+ else
917
+ resp = client.copy_object(options)
918
+ end
919
+
920
+ nil
921
+
922
+ end
923
+
924
+ # Copies data from the current object to another object in S3.
925
+ #
926
+ # S3 handles the copy so the client does not need to fetch the data
927
+ # and upload it again. You can also change the storage class and
928
+ # metadata of the object when copying.
929
+ #
930
+ # @note This operation does not copy the ACL, storage class
931
+ # (standard vs. reduced redundancy) or server side encryption
932
+ # setting from this object to the new object. If you don't
933
+ # specify any of these options when copying, the new object
934
+ # will have the default values as described below.
935
+ #
936
+ # @param [S3Object,String] target An S3Object, or a string key of
937
+ # and object to copy to.
938
+ #
939
+ # @param [Hash] options
940
+ #
941
+ # @option options [String] :bucket_name The slash-prefixed name of the
942
+ # bucket the object should be copied into. Defaults to the current
943
+ # object's bucket.
944
+ #
945
+ # @option options [Bucket] :bucket The bucket the target object
946
+ # should be copied into. Defaults to the current object's bucket.
947
+ #
948
+ # @option options [Hash] :metadata A hash of metadata to save
949
+ # with the copied object. Each name, value pair must conform
950
+ # to US-ASCII. When blank, the sources metadata is copied.
951
+ #
952
+ # @option options [Boolean] :reduced_redundancy (false) If true
953
+ # the object is stored with reduced redundancy in S3 for a
954
+ # lower cost.
955
+ #
956
+ # @option options [Symbol] :acl (private) A canned access
957
+ # control policy. Valid values are:
958
+ #
959
+ # * `:private`
960
+ # * `:public_read`
961
+ # * `:public_read_write`
962
+ # * `:authenticated_read`
963
+ # * `:bucket_owner_read`
964
+ # * `:bucket_owner_full_control`
965
+ #
966
+ # @option options [Symbol] :server_side_encryption (nil) If this
967
+ # option is set, the object will be stored using server side
968
+ # encryption. The only valid value is `:aes256`, which
969
+ # specifies that the object should be stored using the AES
970
+ # encryption algorithm with 256 bit keys. By default, this
971
+ # option uses the value of the `:s3_server_side_encryption`
972
+ # option in the current configuration; for more information,
973
+ # see {AWS.config}.
974
+ #
975
+ # @option options [Boolean] :client_side_encrypted (false) When `true`,
976
+ # the client-side encryption materials will be copied. Without this
977
+ # option, the key and iv are not guaranteed to be transferred to
978
+ # the new object.
979
+ #
980
+ # @option options [String] :expires The date and time at which the
981
+ # object is no longer cacheable.
982
+ #
983
+ # @return [S3Object] Returns the copy (target) object.
984
+ #
985
+ def copy_to target, options = {}
986
+
987
+ unless target.is_a?(S3Object)
988
+
989
+ bucket = case
990
+ when options[:bucket] then options[:bucket]
991
+ when options[:bucket_name]
992
+ Bucket.new(options[:bucket_name], :config => config)
993
+ else self.bucket
994
+ end
995
+
996
+ target = S3Object.new(bucket, target)
997
+ end
998
+
999
+ copy_opts = options.dup
1000
+ copy_opts.delete(:bucket)
1001
+ copy_opts.delete(:bucket_name)
1002
+
1003
+ target.copy_from(self, copy_opts)
1004
+ target
1005
+
1006
+ end
1007
+
1008
+ # Fetches the object data from S3. If you pass a block to this
1009
+ # method, the data will be yielded to the block in chunks as it
1010
+ # is read off the HTTP response.
1011
+ #
1012
+ # ### Read an object from S3 in chunks
1013
+ #
1014
+ # When downloading large objects it is recommended to pass a block
1015
+ # to #read. Data will be yielded to the block as it is read off
1016
+ # the HTTP response.
1017
+ #
1018
+ # # read an object from S3 to a file
1019
+ # File.open('output.txt', 'wb') do |file|
1020
+ # bucket.objects['key'].read do |chunk|
1021
+ # file.write(chunk)
1022
+ # end
1023
+ # end
1024
+ #
1025
+ # ### Reading an object without a block
1026
+ #
1027
+ # When you omit the block argument to #read, then the entire
1028
+ # HTTP response and read and the object data is loaded into
1029
+ # memory.
1030
+ #
1031
+ # bucket.objects['key'].read
1032
+ # #=> 'object-contents-here'
1033
+ #
1034
+ # @param [Hash] options
1035
+ #
1036
+ # @option options [String] :version_id Reads data from a
1037
+ # specific version of this object.
1038
+ #
1039
+ # @option options [Time] :if_unmodified_since If specified, the
1040
+ # method will raise
1041
+ # `AWS::S3::Errors::PreconditionFailed` unless the
1042
+ # object has not been modified since the given time.
1043
+ #
1044
+ # @option options [Time] :if_modified_since If specified, the
1045
+ # method will raise `AWS::S3::Errors::NotModified` if
1046
+ # the object has not been modified since the given time.
1047
+ #
1048
+ # @option options [String] :if_match If specified, the method
1049
+ # will raise `AWS::S3::Errors::PreconditionFailed`
1050
+ # unless the object ETag matches the provided value.
1051
+ #
1052
+ # @option options [String] :if_none_match If specified, the
1053
+ # method will raise `AWS::S3::Errors::NotModified` if
1054
+ # the object ETag matches the provided value.
1055
+ #
1056
+ # @option options [Range] :range A byte range to read data from
1057
+ #
1058
+ # @option options [OpenSSL::PKey::RSA, String] :encryption_key
1059
+ # (nil) If this option is set, the object will be decrypted using
1060
+ # envelope encryption. The valid values are OpenSSL asymmetric keys
1061
+ # `OpenSSL::Pkey::RSA` or strings representing symmetric keys
1062
+ # of an AES-128/192/256-ECB cipher as a `String`.
1063
+ # This value defaults to the value in `s3_encryption_key`;
1064
+ # for more information, see {AWS.config}.
1065
+ #
1066
+ # Symmetric Keys:
1067
+ #
1068
+ # cipher = OpenSSL::Cipher.new('AES-256-ECB')
1069
+ # key = cipher.random_key
1070
+ #
1071
+ # Asymmetric keys can also be generated as so:
1072
+ # key = OpenSSL::PKey::RSA.new(KEY_SIZE)
1073
+ #
1074
+ # @option options [Symbol] :encryption_materials_location (:metadata)
1075
+ # Set this to `:instruction_file` if the encryption materials
1076
+ # are not stored in the object metadata
1077
+ #
1078
+ # @note `:range` option cannot be used with client-side encryption
1079
+ #
1080
+ # @note All decryption reads incur at least an extra HEAD operation.
1081
+ #
1082
+ def read options = {}, &read_block
1083
+
1084
+ options[:bucket_name] = bucket.name
1085
+ options[:key] = key
1086
+
1087
+ if should_decrypt?(options)
1088
+ get_encrypted_object(options, &read_block)
1089
+ else
1090
+ resp_data = get_object(options, &read_block)
1091
+ block_given? ? resp_data : resp_data[:data]
1092
+ end
1093
+
1094
+ end
1095
+
1096
+ # @api private
1097
+ module ACLProxy
1098
+
1099
+ attr_accessor :object
1100
+
1101
+ def change
1102
+ yield(self)
1103
+ object.acl = self
1104
+ end
1105
+
1106
+ end
1107
+
1108
+ # Returns the object's access control list. This will be an
1109
+ # instance of AccessControlList, plus an additional `change`
1110
+ # method:
1111
+ #
1112
+ # object.acl.change do |acl|
1113
+ # # remove any grants to someone other than the bucket owner
1114
+ # owner_id = object.bucket.owner.id
1115
+ # acl.grants.reject! do |g|
1116
+ # g.grantee.canonical_user_id != owner_id
1117
+ # end
1118
+ # end
1119
+ #
1120
+ # Note that changing the ACL is not an atomic operation; it
1121
+ # fetches the current ACL, yields it to the block, and then
1122
+ # sets it again. Therefore, it's possible that you may
1123
+ # overwrite a concurrent update to the ACL using this
1124
+ # method.
1125
+ #
1126
+ # @return [AccessControlList]
1127
+ #
1128
+ def acl
1129
+
1130
+ resp = client.get_object_acl(:bucket_name => bucket.name, :key => key)
1131
+
1132
+ acl = AccessControlList.new(resp.data)
1133
+ acl.extend ACLProxy
1134
+ acl.object = self
1135
+ acl
1136
+
1137
+ end
1138
+
1139
+ # Sets the objects's ACL (access control list). You can provide an ACL
1140
+ # in a number of different formats.
1141
+ # @param (see ACLOptions#acl_options)
1142
+ # @return [nil]
1143
+ def acl=(acl)
1144
+
1145
+ client_opts = {}
1146
+ client_opts[:bucket_name] = bucket.name
1147
+ client_opts[:key] = key
1148
+
1149
+ client.put_object_acl(acl_options(acl).merge(client_opts))
1150
+ nil
1151
+
1152
+ end
1153
+
1154
+ # @api private
1155
+ REQUEST_PARAMETERS = Core::Signers::S3::QUERY_PARAMS.map do |p|
1156
+ p.tr("-","_").to_sym
1157
+ end
1158
+
1159
+ # Generates a presigned URL for an operation on this object.
1160
+ # This URL can be used by a regular HTTP client to perform the
1161
+ # desired operation without credentials and without changing
1162
+ # the permissions of the object.
1163
+ #
1164
+ # @example Generate a url to read an object
1165
+ #
1166
+ # bucket.objects.myobject.url_for(:read)
1167
+ #
1168
+ # @example Generate a url to delete an object
1169
+ #
1170
+ # bucket.objects.myobject.url_for(:delete)
1171
+ #
1172
+ # @example Override response headers for reading an object
1173
+ #
1174
+ # object = bucket.objects.myobject
1175
+ # url = object.url_for(:read,
1176
+ # :response_content_type => "application/json")
1177
+ #
1178
+ # @example Generate a url that expires in 10 minutes
1179
+ #
1180
+ # bucket.objects.myobject.url_for(:read, :expires => 10*60)
1181
+ #
1182
+ # @param [Symbol, String] method The HTTP verb or object
1183
+ # method for which the returned URL will be valid. Valid
1184
+ # values:
1185
+ #
1186
+ # * `:get` or `:read`
1187
+ # * `:put` or `:write`
1188
+ # * `:delete`
1189
+ # * `:head`
1190
+ #
1191
+ # @param [Hash] options Additional options for generating the URL.
1192
+ #
1193
+ # @option options :expires Sets the expiration time of the
1194
+ # URL; after this time S3 will return an error if the URL is
1195
+ # used. This can be an integer (to specify the number of
1196
+ # seconds after the current time), a string (which is parsed
1197
+ # as a date using Time#parse), a Time, or a DateTime object.
1198
+ # This option defaults to one hour after the current time.
1199
+ #
1200
+ # @option options [Boolean] :secure (true) Whether to generate a
1201
+ # secure (HTTPS) URL or a plain HTTP url.
1202
+ #
1203
+ # @option options [String] :content_type Object content type for
1204
+ # HTTP PUT. When provided, has to be also added to the request
1205
+ # header as a 'content-type' field
1206
+ #
1207
+ # @option options [String] :content_md5 Object MD5 hash for HTTP PUT.
1208
+ # When provided, has to be also added to the request header as a
1209
+ # 'content-md5' field
1210
+ #
1211
+ # @option options [String] :endpoint Sets the hostname of the
1212
+ # endpoint.
1213
+ #
1214
+ # @option options [Integer] :port Sets the port of the
1215
+ # endpoint (overrides config.s3_port).
1216
+ #
1217
+ # @option options [Boolean] :force_path_style (false) Indicates
1218
+ # whether the generated URL should place the bucket name in
1219
+ # the path (true) or as a subdomain (false).
1220
+ #
1221
+ # @option options [String] :response_content_type Sets the
1222
+ # Content-Type header of the response when performing an
1223
+ # HTTP GET on the returned URL.
1224
+ #
1225
+ # @option options [String] :response_content_language Sets the
1226
+ # Content-Language header of the response when performing an
1227
+ # HTTP GET on the returned URL.
1228
+ #
1229
+ # @option options [String] :response_expires Sets the Expires
1230
+ # header of the response when performing an HTTP GET on the
1231
+ # returned URL.
1232
+ #
1233
+ # @option options [String] :response_cache_control Sets the
1234
+ # Cache-Control header of the response when performing an
1235
+ # HTTP GET on the returned URL.
1236
+ #
1237
+ # @option options [String] :response_content_disposition Sets
1238
+ # the Content-Disposition header of the response when
1239
+ # performing an HTTP GET on the returned URL.
1240
+ #
1241
+ # @option options [String] :acl The value to use for the
1242
+ # x-amz-acl.
1243
+ #
1244
+ # @option options [String] :response_content_encoding Sets the
1245
+ # Content-Encoding header of the response when performing an
1246
+ # HTTP GET on the returned URL.
1247
+ #
1248
+ # @option options [:v3, :v4] :signature_version (:v3)
1249
+ #
1250
+ # @return [URI::HTTP, URI::HTTPS]
1251
+ def url_for(method, options = {})
1252
+
1253
+ options = options.dup
1254
+ options[:expires] = expiration_timestamp(options[:expires])
1255
+ options[:secure] = config.use_ssl? unless options.key?(:secure)
1256
+ options[:signature_version] ||= config.s3_signature_version
1257
+
1258
+ case options[:signature_version]
1259
+ when :v3 then presign_v3(method, options)
1260
+ when :v4 then presign_v4(method, options)
1261
+ else
1262
+ msg = "invalid signature version, expected :v3 or :v4, got "
1263
+ msg << options[:signature_version].inspect
1264
+ raise ArgumentError, msg
1265
+ end
1266
+ end
1267
+
1268
+ # Generates a public (not authenticated) URL for the object.
1269
+ #
1270
+ # @param [Hash] options Options for generating the URL.
1271
+ #
1272
+ # @option options [Boolean] :secure Whether to generate a
1273
+ # secure (HTTPS) URL or a plain HTTP url.
1274
+ #
1275
+ # @return [URI::HTTP, URI::HTTPS]
1276
+ #
1277
+ def public_url(options = {})
1278
+ options[:secure] = config.use_ssl? unless options.key?(:secure)
1279
+ build_uri(request_for_signing(options), options)
1280
+ end
1281
+
1282
+ # Generates fields for a presigned POST to this object. This
1283
+ # method adds a constraint that the key must match the key of
1284
+ # this object. All options are sent to the PresignedPost
1285
+ # constructor.
1286
+ #
1287
+ # @see PresignedPost
1288
+ # @return [PresignedPost]
1289
+ def presigned_post(options = {})
1290
+ PresignedPost.new(bucket, options.merge(:key => key))
1291
+ end
1292
+
1293
+ # @note Changing the storage class of an object incurs a COPY
1294
+ # operation.
1295
+ #
1296
+ # Changes the storage class of the object to enable or disable
1297
+ # Reduced Redundancy Storage (RRS).
1298
+ #
1299
+ # @param [true,false] value If this is true, the object will be
1300
+ # copied in place and stored with reduced redundancy at a
1301
+ # lower cost. Otherwise, the object will be copied and stored
1302
+ # with the standard storage class.
1303
+ #
1304
+ # @return [true,false] The `value` parameter.
1305
+ def reduced_redundancy= value
1306
+ copy_from(key, :reduced_redundancy => value)
1307
+ value
1308
+ end
1309
+
1310
+ private
1311
+
1312
+ def presign_v4(method, options)
1313
+ PresignV4.new(self).presign(method, options)
1314
+ end
1315
+
1316
+ def presign_v3(method, options)
1317
+ options[:acl] = options[:acl].to_s.sub('_', '-') if options[:acl]
1318
+
1319
+ req = request_for_signing(options)
1320
+ req.http_method = http_method(method)
1321
+ req.add_param("AWSAccessKeyId", config.credential_provider.access_key_id)
1322
+ req.add_param("versionId", options[:version_id]) if options[:version_id]
1323
+ req.add_param("Signature", signature(req, options))
1324
+ req.add_param("Expires", options[:expires])
1325
+ req.add_param("x-amz-acl", options[:acl]) if options[:acl]
1326
+ if config.credential_provider.session_token
1327
+ req.add_param(
1328
+ "x-amz-security-token",
1329
+ config.credential_provider.session_token
1330
+ )
1331
+ end
1332
+
1333
+ build_uri(req, options)
1334
+ end
1335
+
1336
+ # Used to determine if the data needs to be copied in parts
1337
+ def use_multipart_copy? options
1338
+ options[:use_multipart_copy]
1339
+ end
1340
+
1341
+ def multipart_copy options
1342
+
1343
+ unless options[:content_length]
1344
+ msg = "unknown content length, must set :content_length " +
1345
+ "to use multi-part copy"
1346
+ raise ArgumentError, msg
1347
+ end
1348
+
1349
+ part_size = compute_part_size(options)
1350
+ clean_up_options(options)
1351
+ source_length = options.delete(:content_length)
1352
+
1353
+ multipart_upload(options) do |upload|
1354
+ pos = 0
1355
+ # We copy in part_size chunks until we read the
1356
+ until pos >= source_length
1357
+ last_byte = (pos + part_size >= source_length) ? source_length - 1 : pos + part_size - 1
1358
+ upload.copy_part(options[:copy_source], options.merge({:copy_source_range => "bytes=#{pos}-#{last_byte}"}))
1359
+ pos += part_size
1360
+ end
1361
+ end
1362
+ end
1363
+
1364
+ # @return [Boolean]
1365
+ def should_decrypt? options
1366
+ options[:encryption_key] or config.s3_encryption_key
1367
+ end
1368
+
1369
+ # A small wrapper around client#get_object
1370
+ def get_object options, &read_block
1371
+ client.get_object(options, &read_block).data
1372
+ end
1373
+
1374
+ # A wrapper around get_object that decrypts
1375
+ def get_encrypted_object options, &read_block
1376
+ decryption_cipher(options) do |cipher|
1377
+ if block_given?
1378
+ resp = get_object(options) do |chunk|
1379
+ yield(cipher.update(chunk))
1380
+ end
1381
+ yield(cipher.final)
1382
+ resp
1383
+ else
1384
+ cipher.update(get_object(options)[:data]) + cipher.final
1385
+ end
1386
+ end
1387
+ end
1388
+
1389
+ # @return [Boolean] Returns `true` if the :data option is large or
1390
+ # guessed to be larger than a configured threshold.
1391
+ def use_multipart? options
1392
+ estimated_content_length(options) > multipart_threshold(options) and
1393
+ !options[:single_request]
1394
+ end
1395
+
1396
+ # @return [Integer] Returns the number of bytes where a multipart
1397
+ # upload is used instead of #put_object.
1398
+ def multipart_threshold options
1399
+ threshold = options[:multipart_threshold] ||
1400
+ config.s3_multipart_threshold
1401
+ end
1402
+
1403
+ # @return [Integer] Returns the size of each multipart chunk.
1404
+ def compute_part_size options
1405
+
1406
+ max_parts = options[:multipart_max_parts] ||
1407
+ config.s3_multipart_max_parts
1408
+
1409
+ min_size = options[:multipart_min_part_size] ||
1410
+ config.s3_multipart_min_part_size
1411
+
1412
+ estimated_size = estimated_content_length(options)
1413
+
1414
+ part_size = [(estimated_size.to_f / max_parts).ceil, min_size].max.to_i
1415
+ part_size += 16 - (part_size % 16)
1416
+ part_size
1417
+
1418
+ end
1419
+
1420
+ # @return [Integer] Returns the size of the data or an estimated
1421
+ # size as provided by the user (useful for IO streams).
1422
+ def estimated_content_length options
1423
+ estimate = options[:content_length] ||
1424
+ options[:estimated_content_length]
1425
+ unless estimate
1426
+ msg = "unknown content length, must set :content_length or " +
1427
+ ":estimated_content_length"
1428
+ raise ArgumentError, msg
1429
+ end
1430
+ estimate
1431
+ end
1432
+
1433
+ def build_uri(request, options)
1434
+ uri_class = options[:secure] ? URI::HTTPS : URI::HTTP
1435
+ uri_class.build(:host => request.host,
1436
+ :port => request.port,
1437
+ :path => request.path,
1438
+ :query => request.querystring)
1439
+ end
1440
+
1441
+ def signature request, options
1442
+ parts = []
1443
+ parts << request.http_method
1444
+ parts << options[:content_md5].to_s
1445
+ parts << options[:content_type].to_s
1446
+ parts << options[:expires]
1447
+ parts << "x-amz-acl:#{options[:acl]}" if options[:acl]
1448
+ if token = config.credential_provider.session_token
1449
+ parts << "x-amz-security-token:#{token}"
1450
+ end
1451
+ parts << Core::Signers::S3.canonicalized_resource(request)
1452
+
1453
+ string_to_sign = parts.join("\n")
1454
+
1455
+ secret = config.credential_provider.secret_access_key
1456
+ Core::Signers::Base.sign(secret, string_to_sign, 'sha1')
1457
+ end
1458
+
1459
+ def expiration_timestamp(input)
1460
+ input = input.to_int if input.respond_to?(:to_int)
1461
+ case input
1462
+ when Time then input.to_i
1463
+ when DateTime then Time.parse(input.to_s).to_i
1464
+ when Integer then (Time.now + input).to_i
1465
+ when String then Time.parse(input).to_i
1466
+ else (Time.now + 60*60).to_i
1467
+ end
1468
+ end
1469
+
1470
+ def http_method(input)
1471
+ symbol = case input
1472
+ when :read then :get
1473
+ when :write then :put
1474
+ else
1475
+ input
1476
+ end
1477
+ symbol.to_s.upcase
1478
+ end
1479
+
1480
+ def request_for_signing(options)
1481
+
1482
+ port = [443, 80].include?(config.s3_port) ?
1483
+ (options[:secure] ? 443 : 80) :
1484
+ config.s3_port
1485
+
1486
+ req = Request.new
1487
+
1488
+ req.key = key
1489
+ req.host = options.fetch(:endpoint, config.s3_endpoint)
1490
+
1491
+ if req.host.nil? && options.include?(:endpoint) && options[:endpoint].nil?
1492
+ req.host = bucket.name
1493
+ else
1494
+ req.bucket = bucket.name
1495
+ end
1496
+
1497
+ req.port = options.fetch(:port, port)
1498
+ req.force_path_style = options.fetch(:force_path_style, config.s3_force_path_style)
1499
+
1500
+ REQUEST_PARAMETERS.each do |param|
1501
+ req.add_param(param.to_s.tr("_","-"),
1502
+ options[param]) if options.key?(param)
1503
+ end
1504
+
1505
+ req
1506
+ end
1507
+
1508
+ def add_sse_options(options)
1509
+ unless options.key?(:server_side_encryption)
1510
+ options[:server_side_encryption] = config.s3_server_side_encryption
1511
+ end
1512
+ options.delete(:server_side_encryption) if
1513
+ options[:server_side_encryption].nil?
1514
+ end
1515
+
1516
+ # Adds client-side encryption metadata headers and encrypts key
1517
+ def add_cse_options(options)
1518
+ encryption_key_for(options) do |encryption_key|
1519
+
1520
+ check_encryption_materials(:encrypt, encryption_key)
1521
+ cipher = get_aes_cipher(:encrypt, :CBC)
1522
+
1523
+ generate_aes_key(cipher) do |envelope_key, envelope_iv|
1524
+ envelope_key, envelope_iv =
1525
+ encode_envelope_key(encryption_key, envelope_key, envelope_iv)
1526
+
1527
+ build_cse_metadata(options,
1528
+ envelope_key,
1529
+ envelope_iv) do |headers, encryption_materials|
1530
+ store_encryption_materials(options, headers, encryption_materials)
1531
+ end
1532
+ end
1533
+
1534
+ # Wrap current stream in encryption
1535
+ options[:data] = CipherIO.new(cipher,
1536
+ options[:data],
1537
+ options[:content_length])
1538
+
1539
+ # Update content_length
1540
+ options[:content_length] =
1541
+ get_encrypted_size(options[:content_length]) if
1542
+ options[:content_length]
1543
+
1544
+ end
1545
+ remove_cse_options(options)
1546
+ end
1547
+
1548
+ # @yield [String, String] Yields an encrypted encoded key and iv pair
1549
+ def encode_envelope_key encryption_key, envelope_key, envelope_iv, &block
1550
+ envelope_key = encrypt(envelope_key, encryption_key)
1551
+ [encode64(envelope_key), encode64(envelope_iv)]
1552
+ end
1553
+
1554
+ # @yield [Hash, Hash] Yields headers and encryption materials that are
1555
+ # to be stored in the metadata and/or instruction file
1556
+ def build_cse_metadata options, enc_envelope_key, enc_envelope_iv, &block
1557
+ # Ensure metadata exists
1558
+ options[:metadata] = {} unless options[:metadata]
1559
+
1560
+ matdesc = options[:encryption_matdesc] || config.s3_encryption_matdesc
1561
+
1562
+ encryption_materials = {'x-amz-key' => enc_envelope_key,
1563
+ 'x-amz-iv' => enc_envelope_iv,
1564
+ 'x-amz-matdesc' => matdesc}
1565
+ orig_headers = {}
1566
+
1567
+ # Save the unencrypted content length
1568
+ if options[:content_length]
1569
+ orig_headers['x-amz-unencrypted-content-length'] =
1570
+ options[:content_length]
1571
+ end
1572
+
1573
+ # Save the unencrypted content MD5
1574
+ if options[:content_md5]
1575
+ orig_headers['x-amz-unencrypted-content-md5'] =
1576
+ options[:content_md5]
1577
+ options.delete(:content_md5)
1578
+ end
1579
+
1580
+ options[:metadata].merge!(orig_headers)
1581
+
1582
+ yield([orig_headers, encryption_materials])
1583
+ end
1584
+
1585
+ # Stores the headers and encryption materials needed to decrypt the data
1586
+ # and to know unencrypted information about the object
1587
+ def store_encryption_materials options, orig_headers, encryption_materials
1588
+ # Get the storage location
1589
+ cse_location = options[:encryption_materials_location] ||
1590
+ config.s3_encryption_materials_location
1591
+
1592
+ # Encryption type specific metadata
1593
+ case cse_location
1594
+ when :metadata
1595
+ options[:metadata].merge!(encryption_materials)
1596
+ when :instruction_file
1597
+ json_string = JSON.generate(encryption_materials)
1598
+ inst_headers = {'x-amz-crypto-instr-file' => ""}.merge(orig_headers)
1599
+ bucket.objects["#{key}.instruction"].write(json_string,
1600
+ :metadata => inst_headers)
1601
+ else
1602
+ msg = "invalid :encryption_materials_location, expected "
1603
+ msg << ":metadata or :instruction_file, got: #{cse_location.inspect}"
1604
+ raise ArgumentError, msg
1605
+ end
1606
+ nil
1607
+ end
1608
+
1609
+ # Removes any extra headers client-side encryption uses.
1610
+ def remove_cse_options options
1611
+ options.delete(:encryption_key)
1612
+ options.delete(:encryption_materials_location)
1613
+ options.delete(:encryption_matdesc)
1614
+ end
1615
+
1616
+ # Yields a decryption cipher for the given client-side encryption key
1617
+ # or raises an error.
1618
+ def decryption_cipher options, &block
1619
+ encryption_key_for(options) do |encryption_key|
1620
+
1621
+ check_encryption_materials(:decrypt, encryption_key)
1622
+
1623
+ location = options[:encryption_materials_location] ||
1624
+ config.s3_encryption_materials_location
1625
+
1626
+ cipher =
1627
+ decryption_materials(location, options) do |envelope_key, envelope_iv|
1628
+ envelope_key, envelope_iv =
1629
+ decode_envelope_key(envelope_key, envelope_iv, encryption_key)
1630
+ get_aes_cipher(:decrypt, :CBC, envelope_key, envelope_iv)
1631
+ end
1632
+
1633
+ remove_cse_options(options)
1634
+
1635
+ yield(cipher)
1636
+
1637
+ end
1638
+ end
1639
+
1640
+ # Decodes the envelope key for decryption
1641
+ def decode_envelope_key envelope_key, envelope_iv, encryption_key
1642
+ decrypted_key =
1643
+ begin
1644
+ decrypt(decode64(envelope_key), encryption_key)
1645
+ rescue RuntimeError
1646
+ msg = "Master key used to decrypt data key is not correct."
1647
+ raise AWS::S3::Errors::IncorrectClientSideEncryptionKey, msg
1648
+ end
1649
+
1650
+ [decrypted_key, decode64(envelope_iv)]
1651
+ end
1652
+
1653
+
1654
+ # @yield [String, String, String] Yields encryption materials for
1655
+ # decryption
1656
+ def decryption_materials location, options = {}, &block
1657
+
1658
+ materials = case location
1659
+ when :metadata then get_metadata_materials(options)
1660
+ when :instruction_file then get_inst_file_materials
1661
+ else
1662
+ msg = "invalid :encryption_materials_location option, expected "
1663
+ msg << ":metadata or :instruction_file, got: #{location.inspect}"
1664
+ raise ArgumentError, msg
1665
+ end
1666
+
1667
+ envelope_key, envelope_iv = materials
1668
+
1669
+ unless envelope_key and envelope_iv
1670
+ raise 'no encryption materials found, unable to decrypt'
1671
+ end
1672
+
1673
+ yield(envelope_key, envelope_iv)
1674
+
1675
+ end
1676
+
1677
+ # @return [String, String, String] Returns the data key, envelope_iv, and the
1678
+ # material description for decryption from the metadata.
1679
+ def get_metadata_materials(options)
1680
+ opts = {}
1681
+ opts[:version_id] = options[:version_id] if options[:version_id]
1682
+ metadata(opts).to_h.values_at(*%w(x-amz-key x-amz-iv))
1683
+ end
1684
+
1685
+ # @return [String, String, String] Returns the data key, envelope_iv, and the
1686
+ # material description for decryption from the instruction file.
1687
+ def get_inst_file_materials
1688
+ obj = bucket.objects["#{key}.instruction"]
1689
+ JSON.parse(obj.read).values_at(*%w(x-amz-key x-amz-iv))
1690
+ end
1691
+
1692
+ # @yield [Hash] Yields the metadata to be saved for client-side encryption
1693
+ def copy_cse_materials source, options
1694
+ cse_materials = {}
1695
+ meta = source.metadata.to_h
1696
+ cse_materials['x-amz-key'] = meta['x-amz-key'] if meta['x-amz-key']
1697
+ cse_materials['x-amz-iv'] = meta['x-amz-iv'] if meta['x-amz-iv']
1698
+ cse_materials['x-amz-matdesc'] = meta['x-amz-matdesc'] if
1699
+ meta['x-amz-matdesc']
1700
+ cse_materials['x-amz-unencrypted-content-length'] =
1701
+ meta['x-amz-unencrypted-content-length'] if
1702
+ meta['x-amz-unencrypted-content-length']
1703
+ cse_materials['x-amz-unencrypted-content-md5'] =
1704
+ meta['x-amz-unencrypted-content-md5'] if
1705
+ meta['x-amz-unencrypted-content-md5']
1706
+
1707
+ if
1708
+ cse_materials['x-amz-key'] and
1709
+ cse_materials['x-amz-iv'] and
1710
+ cse_materials['x-amz-matdesc']
1711
+ then
1712
+ options[:metadata] = (options[:metadata] || {}).merge(cse_materials)
1713
+ else
1714
+ # Handling instruction file
1715
+ source_inst = "#{source.key}.instruction"
1716
+ dest_inst = "#{key}.instruction"
1717
+ self.bucket.objects[dest_inst].copy_from(
1718
+ source.bucket.objects[source_inst])
1719
+ end
1720
+ end
1721
+
1722
+ # Removes unwanted options that should not be passed to the client.
1723
+ def clean_up_options(options)
1724
+ options.delete(:estimated_content_length)
1725
+ options.delete(:single_request)
1726
+ options.delete(:multipart_threshold)
1727
+ end
1728
+
1729
+ # Performs a write using a multipart upload
1730
+ def write_with_multipart options
1731
+ part_size = compute_part_size(options)
1732
+ clean_up_options(options)
1733
+ options.delete(:content_length)
1734
+
1735
+ multipart_upload(options) do |upload|
1736
+ upload.add_part(options[:data].read(part_size)) until
1737
+ options[:data].eof?
1738
+ end
1739
+ end
1740
+
1741
+ # Performs a write using a single request
1742
+ def write_with_put_object options
1743
+
1744
+ # its possible we don't know the content length of the data
1745
+ # option, but the :estimated_content_length was sufficiently
1746
+ # small that we will read the entire stream into memory
1747
+ # so we can tell s3 the content length (this is required).
1748
+ unless options[:content_length]
1749
+ data = StringIO.new
1750
+
1751
+ while (chunk = options[:data].read(4 * 1024))
1752
+ data << chunk
1753
+ end
1754
+
1755
+ options[:content_length] = data.size
1756
+ data.rewind
1757
+ options[:data] = data
1758
+ end
1759
+
1760
+ clean_up_options(options)
1761
+
1762
+ options[:bucket_name] = bucket.name
1763
+ options[:key] = key
1764
+
1765
+ resp = client.put_object(options)
1766
+
1767
+ resp.data[:version_id] ?
1768
+ ObjectVersion.new(self, resp.data[:version_id]) : self
1769
+ end
1770
+
1771
+ def encryption_key_for options, &block
1772
+ if key = options[:encryption_key] || config.s3_encryption_key
1773
+ yield(key)
1774
+ end
1775
+ end
1776
+
1777
+ def add_storage_class_option options
1778
+ if options[:reduced_redundancy] == true
1779
+ options[:storage_class] = 'REDUCED_REDUNDANCY'
1780
+ end
1781
+ end
1782
+
1783
+ # @return [String] Encodes a `String` in base 64 regardless of version of
1784
+ # Ruby for http headers (removes newlines).
1785
+ def encode64 input
1786
+ Base64.encode64(input).split("\n") * ""
1787
+ end
1788
+
1789
+ # @return [String] Decodes a `String` in base 64.
1790
+ def decode64 input
1791
+ Base64.decode64(input)
1792
+ end
1793
+ end
1794
+ end
1795
+ end