aws-sdk-euca 1.8.5

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